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!
Michel
source share