aboutsummaryrefslogtreecommitdiff
path: root/src/org/jivesoftware/smack/sasl/SASLFacebookConnect.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/jivesoftware/smack/sasl/SASLFacebookConnect.java')
-rw-r--r--src/org/jivesoftware/smack/sasl/SASLFacebookConnect.java201
1 files changed, 201 insertions, 0 deletions
diff --git a/src/org/jivesoftware/smack/sasl/SASLFacebookConnect.java b/src/org/jivesoftware/smack/sasl/SASLFacebookConnect.java
new file mode 100644
index 0000000..3126d83
--- /dev/null
+++ b/src/org/jivesoftware/smack/sasl/SASLFacebookConnect.java
@@ -0,0 +1,201 @@
+package org.jivesoftware.smack.sasl;
+
+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 de.measite.smack.Sasl;
+
+import org.jivesoftware.smack.SASLAuthentication;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smack.sasl.SASLMechanism;
+import org.jivesoftware.smack.util.Base64;
+
+/**
+ * This class is originally from http://code.google.com/p/fbgc/source/browse/trunk/daemon/src/main/java/org/albino/mechanisms/FacebookConnectSASLMechanism.java
+ * I just adapted to match the SMACK package scheme and
+ */
+public class SASLFacebookConnect extends SASLMechanism {
+
+ private String sessionKey = "";
+ private String sessionSecret = "";
+ private String apiKey = "";
+
+ static{
+ SASLAuthentication.registerSASLMechanism("X-FACEBOOK-PLATFORM",
+ SASLFacebookConnect.class);
+ SASLAuthentication.supportSASLMechanism("X-FACEBOOK-PLATFORM", 0);
+ }
+
+ public SASLFacebookConnect(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();
+ // }
+
+ protected void authenticate() throws IOException, XMPPException {
+ final 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(new Packet(){
+
+ @Override
+ public String toXML() {
+ return stanza.toString();
+ }
+
+ });
+ }
+
+ public void authenticate(String apiKeyAndSessionKey, String host, String sessionSecret)
+ throws IOException, XMPPException {
+
+ if(apiKeyAndSessionKey==null || sessionSecret==null)
+ throw new IllegalStateException("Invalid parameters!");
+
+ String[] keyArray = apiKeyAndSessionKey.split("\\|");
+
+ if(keyArray==null || keyArray.length != 2)
+ throw new IllegalStateException("Api key or session key is not present!");
+
+ this.apiKey = keyArray[0];
+ this.sessionKey = keyArray[1];
+ this.sessionSecret = sessionSecret;
+
+ this.authenticationId = sessionKey;
+ this.password = sessionSecret;
+ this.hostname = host;
+
+ String[] mechanisms = { "DIGEST-MD5" };
+ Map<String, String> props = new HashMap<String, String>();
+ sc = Sasl.createSaslClient(mechanisms, null, "xmpp", host, props, this);
+ authenticate();
+ }
+
+ public void authenticate(String username, String host, CallbackHandler cbh)
+ throws IOException, XMPPException {
+ String[] mechanisms = { "DIGEST-MD5" };
+ Map<String, String> props = new HashMap<String, String>();
+ sc = Sasl.createSaslClient(mechanisms, null, "xmpp", host, props, cbh);
+ authenticate();
+ }
+
+ protected String getName() {
+ return "X-FACEBOOK-PLATFORM";
+ }
+
+ public void challengeReceived(String challenge) throws IOException {
+ // Build the challenge response stanza encoding the response text
+ final StringBuilder stanza = new StringBuilder();
+
+ byte response[] = null;
+ if (challenge != null) {
+ String decodedResponse = new String(Base64.decode(challenge));
+ Map<String, String> parameters = getQueryMap(decodedResponse);
+
+ String version = "1.0";
+ String nonce = parameters.get("nonce");
+ String method = parameters.get("method");
+
+ Long callId = new GregorianCalendar().getTimeInMillis()/1000;
+
+ String sig = "api_key="+apiKey
+ +"call_id="+callId
+ +"method="+method
+ +"nonce="+nonce
+ +"session_key="+sessionKey
+ +"v="+version
+ +sessionSecret;
+
+ try {
+ sig = MD5(sig);
+ } catch (NoSuchAlgorithmException e) {
+ throw new IllegalStateException(e);
+ }
+
+ String composedResponse = "api_key="+apiKey+"&"
+ +"call_id="+callId+"&"
+ +"method="+method+"&"
+ +"nonce="+nonce+"&"
+ +"session_key="+sessionKey+"&"
+ +"v="+version+"&"
+ +"sig="+sig;
+
+ response = composedResponse.getBytes();
+ }
+
+ 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(new Packet(){
+
+ @Override
+ public String toXML() {
+ return stanza.toString();
+ }
+
+ });
+ }
+
+ private Map<String, String> getQueryMap(String query) {
+ String[] params = query.split("&");
+ Map<String, String> map = new HashMap<String, String>();
+ for (String param : params) {
+ String name = param.split("=")[0];
+ String value = param.split("=")[1];
+ map.put(name, value);
+ }
+ return map;
+ }
+
+ private String convertToHex(byte[] data) {
+ StringBuffer buf = new StringBuffer();
+ for (int i = 0; i < data.length; i++) {
+ int halfbyte = (data[i] >>> 4) & 0x0F;
+ int two_halfs = 0;
+ do {
+ if ((0 <= halfbyte) && (halfbyte <= 9))
+ buf.append((char) ('0' + halfbyte));
+ else
+ buf.append((char) ('a' + (halfbyte - 10)));
+ halfbyte = data[i] & 0x0F;
+ } while(two_halfs++ < 1);
+ }
+ return buf.toString();
+ }
+
+ public String MD5(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException {
+ MessageDigest md;
+ md = MessageDigest.getInstance("MD5");
+ byte[] md5hash = new byte[32];
+ md.update(text.getBytes("iso-8859-1"), 0, text.length());
+ md5hash = md.digest();
+ return convertToHex(md5hash);
+ }
+}
+