Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
238 views
in Technique[技术] by (71.8m points)

java - Problems with connecting to Facebook XMMP MD5-DIGEST

I have tried all the things to connect Facebook with XMPP but i have faced only one error all the time which is :
SASL authentication failed using mechanism DIGEST-MD5
I am implementing following method to perform this task :

public class MySASLDigestMD5Mechanism extends SASLMechanism {

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

protected void authenticate() throws IOException, XMPPException {
    String[] mechanisms = { getName() };
    Map<String, String> props = new HashMap<String, String>();
    sc = Sasl.createSaslClient(mechanisms, null, "xmpp", hostname, props, this);

    super.authenticate();
}

public void authenticate(String username, String host, String password) throws IOException, XMPPException {
    this.authenticationId = username;
    this.password = password;
    this.hostname = host;

    String[] mechanisms = { getName() };
    Map<String,String> props = new HashMap<String,String>();
    sc = Sasl.createSaslClient(mechanisms, null, "xmpp", host, props, this);
    super.authenticate();
}

public void authenticate(String username, String host, CallbackHandler cbh) throws IOException, XMPPException {
    String[] mechanisms = { getName() };
    Map<String,String> props = new HashMap<String,String>();
    sc = Sasl.createSaslClient(mechanisms, null, "xmpp", host, props, (org.apache.harmony.javax.security.auth.callback.CallbackHandler) cbh);
    super.authenticate();
}

protected String getName() {
    return "DIGEST-MD5";
}

/*public void challengeReceived1(String challenge) throws IOException {
    // Build the challenge response stanza encoding the response text
    StringBuilder stanza = new StringBuilder();

    byte response[];
    if (challenge != null) {
        response = sc.evaluateChallenge(Base64.decode(challenge));
    } else {
        response = sc.evaluateChallenge(null);
    }

    String authenticationText="";

    if (response != null) { // fix from 3.1.1
        authenticationText = Base64.encodeBytes(response, Base64.DONT_BREAK_LINES);
        if (authenticationText.equals("")) {
            authenticationText = "=";
        }
    }

    stanza.append("<response xmlns="urn:ietf:params:xml:ns:xmpp-sasl">");
    stanza.append(authenticationText);
    stanza.append("</response>");

    // Send the authentication to the server
    getSASLAuthentication().send(stanza.toString());
}*/

 public void challengeReceived(String challenge)
 throws IOException {

 byte response[];

 if (challenge != null) {
     response = sc.evaluateChallenge(Base64.decode(challenge));
 } else {
     response = sc.evaluateChallenge(new byte[0]);
 }

 Packet responseStanza;

 if (response == null) {
     responseStanza = new Response();
 } else {
     responseStanza = new Response(Base64.encodeBytes(response, Base64.DONT_BREAK_LINES));
 }

 getSASLAuthentication().send(responseStanza);

}

}

And Connection Function is :

     try{
        SASLAuthentication.registerSASLMechanism("DIGEST-MD5",MySASLDigestMD5Mechanism. class);

        ConnectionConfiguration config = new ConnectionConfiguration("chat.facebook.com",5222);



        config.setSASLAuthenticationEnabled(true);

        config.setRosterLoadedAtLogin (true);



        connection = new XMPPConnection(config);

        connection.connect();
        Log.d("Connect...", "Afetr Connect");
        connection.login("username@chat.facebook.com", "password");
        Log.d("done","XMPP client logged in");
    }
    catch(XMPPException ex)
    {
        Log.d("not done","in catchhhhhhhhh");
        System.out.println(ex.getMessage ());
        connection.disconnect();
    }

}
but "After connect" it gone to the ctach and give me error like : 

  SASL authentication failed using mechanism DIGEST-MD5

I searched all blog and find same thing but i dont know what am i doing wrong here..

If is there any other way or solution to connect Facebook XMPP then please Help me ASAP

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Finally, thanks to the no.good.at.coding code and the suggestion of harism, I've been able to connect to the Facebook chat. This code is the Mechanism for the Asmack library (the Smack port for Android). For the Smack library is necessary to use the no.good.at.coding mechanism.

SASLXFacebookPlatformMechanism.java:

import java.io.IOException;
import java.io.UnsupportedEncodingException; 
import java.net.URLEncoder; 
import java.security.MessageDigest; 
import java.security.NoSuchAlgorithmException; 
import java.util.GregorianCalendar; 
import java.util.HashMap; 
import java.util.Map;  
import org.apache.harmony.javax.security.auth.callback.CallbackHandler; 
import org.apache.harmony.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 SASLXFacebookPlatformMechanism extends SASLMechanism 
{      
    private static final String NAME              = "X-FACEBOOK-PLATFORM";      
    private String              apiKey            = "";     
    private String              applicationSecret = "";     
    private String              sessionKey        = "";      
    /**      * Constructor.      */     
    public SASLXFacebookPlatformMechanism(SASLAuthentication saslAuthentication)     
    {         
        super(saslAuthentication);     
    }      
    @Override     
    protected void authenticate() throws IOException, XMPPException     
    {          
        getSASLAuthentication().send(new AuthMechanism(NAME, ""));     
    }      
    @Override     
    public void authenticate(String apiKeyAndSessionKey, String host,             String applicationSecret) throws IOException, XMPPException     
    {         
        if (apiKeyAndSessionKey == null || applicationSecret == null)         
        {             
            throw new IllegalArgumentException("Invalid parameters");         
        }          
        String[] keyArray = apiKeyAndSessionKey.split("\|", 2);         
        if (keyArray.length < 2)         
        {             
            throw new IllegalArgumentException(                     "API key or session key is not present");         }          
            this.apiKey = keyArray[0];         
            this.applicationSecret = applicationSecret;         
            this.sessionKey = keyArray[1];          
            this.authenticationId = sessionKey;         
            this.password = applicationSecret;         
            this.hostname = host;          
            String[] mechanisms = { "DIGEST-MD5" };         

            Map<String, String> props = new HashMap<String, String>();         
            this.sc = Sasl.createSaslClient(mechanisms, null, "xmpp", host, props,this);        
            authenticate();
        }      
        @Override     
        public void authenticate(String username, String host, CallbackHandler cbh)throws IOException, XMPPException     
        {         
            String[] mechanisms = { "DIGEST-MD5" };         
            Map<String, String> props = new HashMap<String, String>();         
            this.sc = Sasl.createSaslClient(mechanisms, null, "xmpp", host, props,cbh);         
            authenticate();
        }      @Override     protected String getName()

        {        
            return NAME;     
        }      
        @Override     
        public void challengeReceived(String challenge) throws IOException     
        {         
            byte[] response = null;          
            if (challenge != null)         
            {             
                String decodedChallenge = new String(Base64.decode(challenge));             
                Map<String, String> parameters = getQueryMap(decodedChallenge);              
                String version = "1.0";             
                String nonce = parameters.get("nonce");             
                String method = parameters.get("method");              
                long callId = new GregorianCalendar().getTimeInMillis();              
                String sig = "api_key=" + apiKey + "call_id=" + callId + "method=" + method + "nonce=" + nonce + "session_key=" + sessionKey + "v=" + version + applicationSecret;
                try             
                {                 
                    sig = md5(sig);             
                } 
                catch (NoSuchAlgorithmException e)             
                {                 
                    throw new IllegalStateException(e);             
                }              
                String composedResponse = "api_key=" + URLEncoder.encode(apiKey, "utf-8") + "&call_id=" + callId + "&method="+ URLEncoder.encode(method, "utf-8") + "&nonce="+ URLEncoder.encode(nonce, "utf-8")+ "&session_key="+ URLEncoder.encode(sessionKey, "utf-8") + "&v="+ URLEncoder.encode(version, "utf-8") + "&sig="+ URLEncoder.encode(sig, "utf-8");response = composedResponse.getBytes("utf-8");
                }          
                String authenticationText = "";          
                if (response != null)         
                {             
                    authenticationText = Base64.encodeBytes(response, Base64.DONT_BREAK_LINES);         
                }          

                // Send the authentication to the server         
                getSASLAuthentication().send(new Response(authenticationText));     
                }      
        private Map<String, String> getQueryMap(String query)     
        {         
            Map<String, String> map = new HashMap<String, String>();         
            String[] params = query.split("\&");          
            for (String param : params)         
            {             
                String[] fields = param.split("=", 2);             
                map.put(fields[0], (fields.length > 1 ? fields[1] : null));         
            }          
            return map;     
            }      
        private String md5(String text) throws NoSuchAlgorithmException,UnsupportedEncodingException     
        {         
            MessageDigest md = MessageDigest.getInstance("MD5");         
            md.update(text.getBytes("utf-8"), 0, text.length());         
            return convertToHex(md.digest());     
        }      
        private String convertToHex(byte[] data)     
        {         
            StringBuilder buf = new StringBuilder();         
            int len = data.length;          
            for (int i = 0; i < len; i++)         
            {             
                int halfByte = (data[i] >>> 4) & 0xF;             
                int twoHalfs = 0;              
                do             
                {                 
                    if (0 <= halfByte && halfByte <= 9)                 
                    {                     
                        buf.append((char) ('0' + halfByte));                 
                    }                 
                    else                 
                    {                     
                        buf.append((char) ('a' + halfByte - 10));                 
                    }                 
                    halfByte = data[i] & 0xF;             
                } 
                while (twoHalfs++ < 1);         
            }          
            return buf.toString();     
            } 
        }

To use it:

ConnectionConfiguration config = new ConnectionConfiguration("chat.facebook.com", 5222); 
config.setSASLAuthenticationEnabled(true); 
XMPPConnection xmpp = new XMPPConnection(config); 
try 
{     
    SASLAuthentication.registerSASLMechanism("X-FACEBOOK-PLATFORM", SASLXFacebookPlatformMechanism.class);     
    SASLAuthentication.supportSASLMechanism("X-FACEBOOK-PLATFORM", 0);     
    xmpp.connect();     
    xmpp.login(apiKey + "|" + sessionKey, sessionSecret, "Application"); 
} 
catch (XMPPException e) 
{     
    xmpp.disconnect();     
    e.printStackTrace(); 
}

apiKey is the API key given in the application settings page in Facebook. sessionKey is the second part of the access token. If the token is in this form, AAA|BBB|CCC, the BBB is the session key. sessionSecret is obtained using the old REST API with the method auth.promoteSession. To use it, it's needed to make a Http get to this url:

https://api.facebook.com/method/auth.promoteSession?access_token=yourAccessToken

Despite of the Facebook Chat documentation says that it's needed to use your application secret key, only when I used the key that returned that REST method I was able to make it works. To make that method works, you have to disable the Disable Deprecated Auth Methods option in the Advance tab in your application settings.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...