Vijay,
Su código me ayudó mucho, gracias! Estoy publicando aquí para ofrecer mi solución al problema de usar AccountManager para iniciar sesión en Google Talk. Hasta ahora no he encontrado una solución completa, pero he desarrollado la mía basándose en el código anterior y corrigiendo algunas líneas que no funcionan.
La solución tiene dos partes. El primero se basa en la idea y el código anteriores. Es crear una subclase de 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();
}
}
}
La segunda parte es su uso. Lo más importante que ningún otro ejemplo me dio es que al obtener el token del sistema AccountManager, el tipo de token no es "ah" sino "correo". La idea estaba en ejemplos que hacen una comunicación directa con los servidores de google para obtener el token pero no al solicitarlo desde AccountManager. Poniéndolos juntos le indica que debe hacer lo siguiente en su código de controlador. Crear una función para obtener el 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;
}
Y luego llamarlo después de asegurarse de que se utilizará el sistema de SASL derecha:
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
}
feliz Google Hablar!
Miré esto antes, pero nunca lo intenté realmente. ¿Te importaría publicar tu código para poder intentarlo y quizás encuentre una solución? Gracias – Guillaume