package org.elephantt.javabook.client;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.NameValuePair;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* A PostMethod that supports signing the request according to FB signature rules.
*
* Once the sign(String) method is called, the parameters cannot be mutated.
*/
public class FacebookPostMethod extends PostMethod {
private boolean signed = false;
@Override
public boolean removeParameter(String s, String s1) throws IllegalArgumentException {
verifyState();
return super.removeParameter(s, s1);
}
@Override
public void addParameter(String s, String s1) throws IllegalArgumentException {
verifyState();
super.addParameter(s, s1);
}
@Override
public void addParameter(NameValuePair nameValuePair) throws IllegalArgumentException {
verifyState();
super.addParameter(nameValuePair);
}
@Override
public void addParameters(NameValuePair[] nameValuePairs) {
verifyState();
super.addParameters(nameValuePairs);
}
@Override
public boolean removeParameter(String s) throws IllegalArgumentException {
verifyState();
return super.removeParameter(s);
}
/**
* Signs the POST according to FB sig rules
*/
public void sign(String secretKey) {
NameValuePair[] params = getParameters();
List<String> sigParams = new ArrayList<String>(params.length);
for (NameValuePair nvp : params) {
sigParams.add(nvp.getName() + "=" + nvp.getValue());
}
addParameter("sig", generateSignature(sigParams, secretKey));
signed = true;
}
/**
* Generates a sig over the params according to FB sig rules
* @param params
* @return
*/
private String generateSignature(List<String> params, String secretKey) {
StringBuilder buffer = new StringBuilder();
Collections.sort(params);
for (String param: params) {
buffer.append(param);
}
buffer.append(secretKey);
StringBuilder result = new StringBuilder();
// wtf?
for (byte b : createDigester().digest(buffer.toString().getBytes())) {
result.append(Integer.toHexString((b & 0xf0) >>> 4));
result.append(Integer.toHexString(b & 0x0f));
}
return result.toString();
}
private MessageDigest createDigester() {
try {
return MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("MD5 MessageDigest algo missing");
}
}
private void verifyState() {
if (signed) throw new IllegalStateException("cannot modify parameters after parameter set is signed");
}
}
|