Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Connect to GTalk server (XMPP, Smack) using an authToken

I'm writing a chat app which is connecting to a XMPP server, and if the user chooses, I want to give them the option to connect to their google chat account, without having to enter the credentials... I used google's javascript api to popout the google login form and after successful login access token will generate. Now using that access token and users email id i want to communicate with xmpp server so that users can chat with their gtalk friends.

I searched a lot but didn't found the solution. Whatever i found required users password but i want to use access token.

SASLAuthentication.registerSASLMechanism("X-OAUTH2", GoogleConnectSASLMechanism.class);
SASLAuthentication.supportSASLMechanism("X-OAUTH2", 0);
config = new ConnectionConfiguration(server, 5222, 'gmail.com');
config.setSASLAuthenticationEnabled(true);
config.setSecurityMode(SecurityMode.enabled);
config.setReconnectionAllowed(true);

connection = new XMPPConnection(config);
connection.connect();

 connection.login(username, session_key, "Chat");
 setServer(SERVER_TYPE.GTALK);

GoogleConnectSASLMechanism.java code is as follows:-

    package org.jivesoftware.smack;

    import java.io.IOException;
    import java.net.URLEncoder;
    import java.io.UnsupportedEncodingException;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.util.GregorianCalendar;
    import java.util.HashMap;
    import java.util.Map;

    import javax.security.auth.callback.CallbackHandler;
    import javax.security.sasl.Sasl;

    import org.jivesoftware.smack.SASLAuthentication;
    import org.jivesoftware.smack.XMPPException;
    import org.jivesoftware.smack.packet.Packet;
    import org.jivesoftware.smack.sasl.SASLMechanism;
    import org.jivesoftware.smack.util.Base64;


    public class GoogleConnectSASLMechanism extends SASLMechanism {
    public static final String NAME="X-OAUTH2";


    public GoogleConnectSASLMechanism(SASLAuthentication saslAuthentication) {
        super(saslAuthentication);
    }

    @Override
    protected String getName() {
        return NAME;
    }

    static void enable() { }

    @Override
    protected void authenticate() throws IOException, XMPPException
    {
        String authCode = password;
        String jidAndToken = "\0" + URLEncoder.encode( authenticationId, "utf-8" ) + "\0" + authCode;

        StringBuilder stanza = new StringBuilder();
        //stanza.append( "<auth mechanism=\"" ).append( getName() );
        //stanza.append( "\" xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">" );
       // stanza.append( new String(Base64.encode( jidAndToken.getBytes( "UTF-8" ), Base64.DEFAULT ) ) );
        stanza.append( "<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" mechanism=\"" ).append( getName() );
        stanza.append( "\" auth:service=\"oauth2\"" );
        stanza.append( "\" xmlns:auth=\"http://www.google.com/talk/protocol/auth\">" );
        stanza.append( "\" base64(\"\\0"+user_name+"\\0" + authCode+")" );



        stanza.append( "</auth>" );

        //Log.v("BlueTalk", "Authentication text is "+stanza);
        // Send the authentication to the server
        getSASLAuthentication().send( new Auth2Mechanism(stanza.toString()) );
    }

    public class Auth2Mechanism extends Packet {
        String stanza;
        public Auth2Mechanism(String txt) {
            stanza = txt;
        }
        public String toXML() {
            return stanza;
        }
    }


    /**
     * Initiating SASL authentication by select a mechanism.
     */
    public class AuthMechanism extends Packet {
        final private String name;
        final private String authenticationText;

        public AuthMechanism(String name, String authenticationText) {
            if (name == null) {
                throw new NullPointerException("SASL mechanism name shouldn't be null.");
            }
            this.name = name;
            this.authenticationText = authenticationText;
        }

        public String toXML() {
            StringBuilder stanza = new StringBuilder();
            stanza.append("<auth mechanism=\"").append(name);
            stanza.append("\" xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
            if (authenticationText != null &&
                    authenticationText.trim().length() > 0) {
                stanza.append(authenticationText);
            }
            stanza.append("</auth>");
            return stanza.toString();
        }
        }
    }

But I got an Exception from connection.login() that "username or password are not correct"

To do this, I'd get the permission to use the google account, get the token and authenticate to google talk (XMPP server, using Smack) using the token..

The problem is.. how do I do that? I mean, how do I authenticate to the GTalk server if I know the login and the token?

Any help would be highly appreciated...:)

like image 370
imVJ Avatar asked Jan 14 '13 14:01

imVJ


2 Answers

Vijay,

Change your authenticate function as follows :

protected void authenticate() throws IOException, XMPPException {
    final StringBuilder stanza = new StringBuilder();
    byte response[] = null;

    stanza.append("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\"" +
            "mechanism=\"X-OAUTH2\"" +
            "auth:service=\"oauth2\"" +
            "xmlns:auth= \"http://www.google.com/talk/protocol/auth\">");

    String composedResponse =  "\0" + username + "\0" + sessionKey;
    response = composedResponse.getBytes("UTF-8");
    String authenticationText = "";
    if (response != null) {
        authenticationText = Base64.encodeBytes(response, Base64.DONT_BREAK_LINES);
    }

    stanza.append(authenticationText);
    stanza.append("</auth>");

    // Send the authentication to the server
    Packet p=new Packet() {
        @Override
        public String toXML() {
            return stanza.toString();
        }
    };
    getSASLAuthentication().send(p);
}

Its same as your original authenticate function. I have just changed stanza.

like image 174
Ketan Yekale Avatar answered Sep 30 '22 09:09

Ketan Yekale


Your problem seems to be with the line:

stanza.append( "\" base64(\"\\0"+user_name+"\\0" + authCode+")" );

So I think this is what your authenticate function should look like:

protected void authenticate() throws IOException, XMPPException
{
    String authCode = password;
    String jidAndToken = "\0" + authenticationId + "\0" + authCode;

    StringBuilder stanza = new StringBuilder();
    stanza.append("<auth mechanism=\"").append( getName());
    stanza.append("\" xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
    stanza.append(new String(Base64.encode(jidAndToken.getBytes("UTF-8"), Base64.DEFAULT)));
    stanza.append("</auth>");

    //Log.v("BlueTalk", "Authentication text is "+stanza);
    // Send the authentication to the server
    getSASLAuthentication().send( new Auth2Mechanism(stanza.toString()) );
}

So, it's more like your commented code. base64(..) shouldn't appear in the <auth> content at all. There should just be a base64 encoded string in there.

With your help on my thread regarding this same topic, I was able to log in successfully.

like image 39
dexy Avatar answered Sep 30 '22 10:09

dexy