diff options
Diffstat (limited to 'src/org/jivesoftware/smack/sasl/SASLFacebookConnect.java')
-rw-r--r-- | src/org/jivesoftware/smack/sasl/SASLFacebookConnect.java | 201 |
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); + } +} + |