Home » Android » android – Gtalk XMPP SASL authentication failed using mechanism X-OAUTH2?

android – Gtalk XMPP SASL authentication failed using mechanism X-OAUTH2?

Posted by: admin May 14, 2020 Leave a comment

Questions:

I am using GoogleTalk XMPP in my application for chatting. unable to create XMPP connection by using username and AuthToken with Google authentication.

Now i am using GoogleAuth2 for authentication. i tried to authenticate like this using access_token and email. by using SASLMechanism. but i am not able to connect to xmpp serv
er, it gives error like this SASL authentication failed using mechanism X-OAUTH2

ConnectionConfiguration config = new ConnectionConfiguration(server_host, SERVER_PORT, SERVICE_NAME);
config.setSASLAuthenticationEnabled(true);
m_connection = new XMPPConnection(config);

SASLAuthentication.registerSASLMechanism("X-OAUTH2", GoogleConnectSASLMechanism.class);
SASLAuthentication.supportSASLMechanism("X-OAUTH2", 0);

config.setSecurityMode(ConnectionConfiguration.SecurityMode.enabled);   
try {           
    m_connection.connect();     
} catch (XMPPException e) {         
    e.printStackTrace();
}

this is the class i am using for SASLMechanism.

public class GoogleConnectSASLMechanism extends SASLMechanism {

public static final String NAME = "X-OAUTH2";

private String username = "";
private String sessionKey = "";

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

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

static void enable() {
}

@Override
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 =  "
public class GoogleConnectSASLMechanism extends SASLMechanism {
public static final String NAME = "X-OAUTH2";
private String username = "";
private String sessionKey = "";
public GoogleConnectSASLMechanism(SASLAuthentication saslAuthentication) {
super(saslAuthentication);
}
@Override
protected String getName() {
return NAME;
}
static void enable() {
}
@Override
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);
}
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();
}
}
}
" + username + "
public class GoogleConnectSASLMechanism extends SASLMechanism {
public static final String NAME = "X-OAUTH2";
private String username = "";
private String sessionKey = "";
public GoogleConnectSASLMechanism(SASLAuthentication saslAuthentication) {
super(saslAuthentication);
}
@Override
protected String getName() {
return NAME;
}
static void enable() {
}
@Override
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);
}
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();
}
}
}
" + 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); } 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(); } } }

How to authenticate the Google Auth by using SASL Mechanism ?

How to&Answers:

Here’s a version working for me, using OAUTH2 tokens. The OAUTH2 scope is https://www.googleapis.com/auth/googletalk .

This code uses the Smack XMPP library.

The OAuth2 authentication mechanism :

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

import javax.security.sasl.Sasl;

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

public class SALSGTalkOauthMechanism extends SASLMechanism {
    private static final Logger log = Logger.getLogger(SALSGTalkOauthMechanism.class.getName());
    public static final String NAME = "X-OAUTH2";


    /**
     * Constructor.
     */
    public SALSGTalkOauthMechanism(SASLAuthentication saslAuthentication) {
            super(saslAuthentication);
            log.info("Creating SASL mechanism for GTalk (X-OAUTH2)");
    }

    @Override
    public void authenticate(String username, String host, String accessToken) throws IOException, XMPPException {
        this.hostname = host;

        log.info("Authenticating to host "+host+" with key "+username);

        String[] mechanisms = { "X-OAUTH2" };
        Map<String, String> props = new HashMap<String, String>();
        this.sc = Sasl.createSaslClient(mechanisms, null, "xmpp", host, props, this);
        getSASLAuthentication().send(new AuthMechanism(getName(), Base64.encodeBytes(('
import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; import javax.security.sasl.Sasl; import org.jivesoftware.smack.SASLAuthentication; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.sasl.SASLMechanism; import org.jivesoftware.smack.util.Base64; public class SALSGTalkOauthMechanism extends SASLMechanism { private static final Logger log = Logger.getLogger(SALSGTalkOauthMechanism.class.getName()); public static final String NAME = "X-OAUTH2"; /** * Constructor. */ public SALSGTalkOauthMechanism(SASLAuthentication saslAuthentication) { super(saslAuthentication); log.info("Creating SASL mechanism for GTalk (X-OAUTH2)"); } @Override public void authenticate(String username, String host, String accessToken) throws IOException, XMPPException { this.hostname = host; log.info("Authenticating to host "+host+" with key "+username); String[] mechanisms = { "X-OAUTH2" }; Map<String, String> props = new HashMap<String, String>(); this.sc = Sasl.createSaslClient(mechanisms, null, "xmpp", host, props, this); getSASLAuthentication().send(new AuthMechanism(getName(), Base64.encodeBytes(('\0'+username+'\0'+accessToken).getBytes()))); } @Override protected String getName() { return NAME; } } 
'+username+'
import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; import javax.security.sasl.Sasl; import org.jivesoftware.smack.SASLAuthentication; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.sasl.SASLMechanism; import org.jivesoftware.smack.util.Base64; public class SALSGTalkOauthMechanism extends SASLMechanism { private static final Logger log = Logger.getLogger(SALSGTalkOauthMechanism.class.getName()); public static final String NAME = "X-OAUTH2"; /** * Constructor. */ public SALSGTalkOauthMechanism(SASLAuthentication saslAuthentication) { super(saslAuthentication); log.info("Creating SASL mechanism for GTalk (X-OAUTH2)"); } @Override public void authenticate(String username, String host, String accessToken) throws IOException, XMPPException { this.hostname = host; log.info("Authenticating to host "+host+" with key "+username); String[] mechanisms = { "X-OAUTH2" }; Map<String, String> props = new HashMap<String, String>(); this.sc = Sasl.createSaslClient(mechanisms, null, "xmpp", host, props, this); getSASLAuthentication().send(new AuthMechanism(getName(), Base64.encodeBytes(('\0'+username+'\0'+accessToken).getBytes()))); } @Override protected String getName() { return NAME; } } 
'+accessToken).getBytes()))); } @Override protected String getName() { return NAME; } }

And the code to make it work together :

import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ChatManager;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.SASLAuthentication;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Presence;

import revevol.applications.cloudpulse.client.Probe;
import revevol.applications.cloudpulse.client.ProbeClient;
import revevol.applications.cloudpulse.client.ProbeClientUtils;

import com.google.api.client.auth.oauth2.Credential;

public class GTalkProbe implements Probe {
    private static final Logger log = Logger.getLogger(GTalkProbe.class.getName());
    public static final String PROBE_GTALK_IDENTIFIER = "gtalkprobe";

    @Override
    public void run(ProbeClient client, Properties properties) throws Exception {
        log.info("Start running GTalkProbe.");
        long startTimestamp = new Date().getTime();
        Exception exception = null;
        MessageReboundResult result = new MessageReboundResult();
        Connection conn1 = null;

        try {
            Credential credential = ProbeClientUtils.getOAuth2Credentials(properties);

            ConnectionConfiguration config = new ConnectionConfiguration("talk.google.com", 5222, "gmail.com");
            config.setCompressionEnabled(true);
            config.setSASLAuthenticationEnabled(true);

            conn1 = new XMPPConnection(config);

            SASLAuthentication.registerSASLMechanism("X-OAUTH2", SALSGTalkOauthMechanism.class);
            SASLAuthentication.supportSASLMechanism("X-OAUTH2", 0);
            conn1.connect();

            log.info("Logging in");
            conn1.login(ProbeClientUtils.getOAuthConsumerId(properties), credential.getAccessToken());

            Presence presence = new Presence(Presence.Type.available);
            presence.setStatus("My status");
            conn1.sendPacket(presence);

            ChatManager chatmanager = conn1.getChatManager();

            String destination = "[email protected]";
            log.info("Sending chat message to " + destination);
            String message = "PING : " + UUID.randomUUID().toString();

            Chat chat = chatmanager.createChat(destination, new MessageListener(//TODO : here put your stuff));

            Message msg = new Message(destination, Message.Type.chat);

            msg.setBody(message);
            chat.sendMessage(msg);

            //Here you are
    }

}

Answer:

I have worked much on chatting application using XMPP/Openfire server.

Here is simplest way to connect/login to the server –

ConnectionConfiguration connConfig = new ConnectionConfiguration("abc.hostname.com",5222);
        configure(ProviderManager.getInstance());
        connection = new XMPPConnection(connConfig);
        connection.connect();
        connection.login(userName, password);   

To get the roster at the time of login

    roster = connection.getRoster();
    roster.setSubscriptionMode(Roster.SubscriptionMode.manual);

Here is the configure method for the provider instance

public void configure(ProviderManager pm) {
    // MUC Admin
    pm.addIQProvider("query", "http://jabber.org/protocol/muc#admin",new MUCAdminProvider());
    // MUC Owner
    pm.addIQProvider("query", "http://jabber.org/protocol/muc#owner",new MUCOwnerProvider());
    pm.addIQProvider("si", "http://jabber.org/protocol/si",new StreamInitiationProvider());
    pm.addIQProvider("query","http://jabber.org/protocol/bytestreams", new org.jivesoftware.smackx.provider.BytestreamsProvider());
    pm.addIQProvider("query","http://jabber.org/protocol/disco#items", new DiscoverItemsProvider());
    pm.addIQProvider("query","http://jabber.org/protocol/disco#info", new DiscoverInfoProvider());

    // Delayed Delivery
    pm.addExtensionProvider("x", "jabber:x:delay",new DelayInformationProvider());
    pm.addIQProvider("vCard", "vcard-temp", new VCardProvider());

    //  Group Chat Invitations
    pm.addExtensionProvider("x","jabber:x:conference", new GroupChatInvitation.Provider());
}

Let me know if you have any queries