Hello, I’m just an amateur with smack api, and I’m trying hard to connect to facebook chat using x-facebook platform. I have gone through several blog posts and forums for getting it done. Facebook offers very unconcise documentation for this.
I have found a custom SASL mechanism class for facebook authentication. But getting errors, actually I do not know exactly how to perform this.
public class SASLXFacebookPlatformMechanism extends SASLMechanism {
public static final String NAME = "X-FACEBOOK-PLATFORM"; private String apiKey = "";
private String applicationSecret = "";
private String sessionKey = ""; /**
* Constructor.
*/
public SASLXFacebookPlatformMechanism1(SASLAuthentication saslAuthentication) {
super(saslAuthentication);
} @Override
protected void authenticate() throws IOException, XMPPException {
StringBuilder stanza = new StringBuilder();
stanza.append("<auth mechanism=\"").append(getName());
stanza.append("\" xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">");
stanza.append("</auth>"); // Send the authentication to the server
getSASLAuthentication().send(stanza.toString());
} @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 {
StringBuilder stanza = new StringBuilder();
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() / 1000L; 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); 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());
} 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();
}
}
So now I have this class, but I don’t know where I am doing wrong, may be I’m calling it in wrong manner, here is how I made use of this class.
ConnectionConfiguration config = new ConnectionConfiguration("chat.facebook.com", 5222);
config.setSASLAuthenticationEnabled(true);
config.setDebuggerEnabled(true); SASLAuthentication.registerSASLMechanism(SASLXFacebookPlatformMechanism.NAME, SASLXFacebookPlatformMechanism.class);
SASLAuthentication.supportSASLMechanism(SASLXFacebookPlatformMechanism1.NAME, 0); XMPPConnection connection = new XMPPConnection(config);
try {
connection.connect();
} catch (XMPPException ex) {
Logger.getLogger(FB.class.getName()).log(Level.SEVERE, null, ex);
}
SASLXFacebookPlatformMechanism1 mech=new SASLXFacebookPlatformMechanism1(connection.getSASLAuthentication());
try {
mech.authenticate();
} catch (IOException ex) {
Logger.getLogger(FB.class.getName()).log(Level.SEVERE, null, ex);
} catch (XMPPException ex) {
Logger.getLogger(FB.class.getName()).log(Level.SEVERE, null, ex);
}
When I execute this code, I get a NullPointerException
java.lang.NullPointerException
at org.jivesoftware.smack.SASLAuthentication.challengeReceived(SASLAuthentication.java:514)
at org.jivesoftware.smack.PacketReader.parsePackets(PacketReader.java:296)
at org.jivesoftware.smack.PacketReader.access$000(PacketReader.java:43)
at org.jivesoftware.smack.PacketReader$1.run(PacketReader.java:70)