How to authenticate to Google Talk with an AccountManager authentication token using the Smack API?

This question is similar to: Authentication in Google Talk (XMPP, Smack) using authToken

  • I have an android.accounts.AccountManager class and its methods for getting an authentication token for a Google account:

    public AccountManagerFuture<Bundle> getAuthToken (Account account, String authTokenType, Bundle options, Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) 
  • I know how to prepare XML authentication:

     jidAndToken ="\0" + UTF8(YOURUSERNAME@gmail.com) + "\0" + Auth 

    (where "\ 0" is for one octet with a value of 0). Use this in the original version of SASL:

     <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='X-GOOGLE-TOKEN'>Base64(jidAndToken)</auth> 


But I was not able to integrate it with the Smack API, like someone in facebook chat: XMPP with the Java Asmack library supporting X-FACEBOOK-PLATFORM

Can someone help me?

+8
android xmpp smack
source share
2 answers

Vijay

Your code really helped me! I am posting here to offer my solution to the problem of using AccountManager to log into Google Talk. So far, I have not found a complete solution there, but I have developed mine based on the above code and fixing a few lines that do not work.

There are two parts to the solution. The first is based on the above idea and code. It should create a subclass of SASLMechanism:

 import java.io.IOException; import java.net.URLEncoder; import org.jivesoftware.smack.SASLAuthentication; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.packet.Packet; import org.jivesoftware.smack.sasl.SASLMechanism; import android.util.Base64; import android.util.Log; public class GTalkOAuth2 extends SASLMechanism { public static final String NAME="X-GOOGLE-TOKEN"; public GTalkOAuth2(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>" ); 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(); } } } 

The second part is its use. The great thing that no other example gave me is that when receiving a token from the AccountManager system, the type of token is not “ah”, but “mail”. The idea was there, in examples that directly communicate with google servers, to get a token, but not requesting it from the AccountManager. Combining them, you should do the following in the driver code. Create a function to get the token:

 public String getAuthToken(String name) { Context context = getApplicationContext(); Activity activity = this; String retVal = ""; Account account = new Account(name, "com.google"); AccountManagerFuture<Bundle> accFut = AccountManager.get(context).getAuthToken(account, "mail", null, activity, null, null); try { Bundle authTokenBundle = accFut.getResult(); retVal = authTokenBundle.get(AccountManager.KEY_AUTHTOKEN).toString(); } catch (OperationCanceledException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (AuthenticatorException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return retVal; } 

And then call it, making sure that the correct SASL system will be used:

 SASLAuthentication.registerSASLMechanism( GTalkOAuth2.NAME, GTalkOAuth2.class ); SASLAuthentication.supportSASLMechanism( GTalkOAuth2.NAME, 0 ); config.setSASLAuthenticationEnabled(true); String saslAuthString = getAuthToken(acct.name); connection = new XMPPConnection(config); try { connection.connect(); connection.login(name, saslAuthString); } catch (XMPPException e) { // Most likely an expired token // Invalidate the token and start over. There are example of this available } 

Happy Google Talking!

+8
source share

I know this thread is a bit outdated, but I thought I would help ... So here is my class that seems to work with smack connecting to Gtalk using the token mechanism. to be honest, i would rather go with oauth2 .. but this seems to work fine. Make sure your username is "<your_user>@gmail.com" and it should work:

 public class GoogleTalkAuthentication extends SASLMechanism { static { SASLAuthentication.registerSASLMechanism( "X-GOOGLE-TOKEN", GoogleTalkAuthentication.class ); SASLAuthentication.supportSASLMechanism( "X-GOOGLE-TOKEN", 0 ); } public GoogleTalkAuthentication( SASLAuthentication saslAuthentication ) { super( saslAuthentication ); } @Override protected String getName() { return "X-GOOGLE-TOKEN"; } @Override public void authenticate( String username, String host, String password ) throws IOException, XMPPException { super.authenticate( username, host, password ); } @Override protected void authenticate() throws IOException, XMPPException { String authCode = getAuthCode( authenticationId, 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( Base64.encode( jidAndToken.getBytes( "UTF-8" ) ) ); stanza.append( "</auth>" ); // Send the authentication to the server getSASLAuthentication().send( stanza.toString() ); } public static String getAuthCode( String username, String password ) throws IOException { StringBuilder urlToRead = new StringBuilder(); urlToRead.append( "https://www.google.com/accounts/ClientLogin?accountType=GOOGLE&service=mail&" ); urlToRead.append( "Email=" + username + "&" ); urlToRead.append( "Passwd=" + password ); URL url = new URL( urlToRead.toString() ); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod( "GET" ); BufferedReader rd = new BufferedReader( new InputStreamReader( conn.getInputStream() ) ); try { String line; while ( ( line = rd.readLine() ) != null ) { if ( line.startsWith( "Auth=" ) ) return line.substring( 5 ); } return null; } finally { rd.close(); } } public static void main( String[] args ) throws IOException { String username = ""; String password = ""; String authCode = getAuthCode( username, password ); String jidAndToken = "\0" + URLEncoder.encode( username, "utf-8" ) + "\0" + authCode; System.err.println( authCode ); System.err.println( "Code:" + jidAndToken ); } } 

Good luck.

+1
source share

All Articles