Created
February 1, 2011 17:52
-
-
Save shin1ogawa/806263 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package appengine.util; | |
import java.io.UnsupportedEncodingException; | |
import java.net.URLEncoder; | |
import java.security.InvalidKeyException; | |
import java.security.NoSuchAlgorithmException; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.Collections; | |
import java.util.LinkedHashMap; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.Random; | |
import javax.crypto.Mac; | |
import javax.crypto.spec.SecretKeySpec; | |
/** | |
* utilities for oauth of google app engine. | |
* @author shin1ogawa | |
*/ | |
public class OAuthUtil { | |
static final String ENC = "utf-8"; | |
static final String HMAC_SHA1_ALGORITHM = "HmacSHA1"; | |
/** | |
* @param method | |
* @param requestUrlBase | |
* @param parameters | |
* @param consumerKey | |
* @param consumerSecret | |
* @param accessToken | |
* @param accessTokenSecret | |
* @return value for Authorization Header | |
* @throws UnsupportedEncodingException | |
* @throws InvalidKeyException | |
* @throws NoSuchAlgorithmException | |
* @author shin1ogawa | |
*/ | |
public static String getAuthorizationHeaderValue(String method, String requestUrlBase, | |
Map<String, String> parameters, String consumerKey, String consumerSecret, | |
String accessToken, String accessTokenSecret) throws UnsupportedEncodingException, | |
InvalidKeyException, NoSuchAlgorithmException { | |
Map<String, String> _params = new LinkedHashMap<String, String>(); | |
if (parameters != null && parameters.isEmpty() == false) { | |
_params.putAll(parameters); | |
} | |
_params.put("oauth_consumer_key", consumerKey); | |
_params.put("oauth_nonce", generateNonce()); | |
_params.put("oauth_signature_method", "HMAC-SHA1"); | |
_params.put("oauth_timestamp", generateTimestamp()); | |
_params.put("oauth_token", accessToken); | |
_params.put("oauth_version", "1.0"); | |
String baseString = generateSignatureBaseString(method, requestUrlBase, _params); | |
String key = | |
URLEncoder.encode(consumerKey, "utf-8") + "&" | |
+ URLEncoder.encode(accessTokenSecret, "utf-8"); | |
String signature = URLEncoder.encode(generateHmacSha1Signature(key, baseString), ENC); | |
StringBuilder b = new StringBuilder("OAuth "); | |
if (_params.containsKey("oauth_body_hash")) { | |
b.append("oauth_body_hash").append("=\"").append(_params.get("oauth_body_hash")) | |
.append("\","); | |
} | |
b.append("oauth_consumer_key").append("=\"") | |
.append(URLEncoder.encode(consumerKey, "utf-8")).append("\""); | |
b.append(",oauth_token").append("=\"").append(URLEncoder.encode(accessToken, "utf-8")) | |
.append("\""); | |
b.append(",oauth_version").append("=\"").append("1.0").append("\""); | |
b.append(",oauth_timestamp").append("=\"").append(_params.get("oauth_timestamp")) | |
.append("\""); | |
b.append(",oauth_nonce").append("=\"").append(_params.get("oauth_nonce")).append("\""); | |
b.append(",oauth_signature_method").append("=\"").append("HMAC-SHA1").append("\""); | |
b.append(",oauth_signature").append("=\"").append(signature).append("\""); | |
return b.toString(); | |
} | |
static String generateSignatureBaseString(String method, String requestUrlBase, | |
Map<String, String> params) throws UnsupportedEncodingException { | |
return escapeAndJoinStrings(Arrays.asList(method, requestUrlBase, | |
escapeAndJoinParameters(params))); | |
} | |
static String escapeAndJoinParameters(Map<String, String> params) | |
throws UnsupportedEncodingException { | |
StringBuilder b = new StringBuilder(); | |
boolean first = true; | |
for (String key : sortedKeyList(params)) { | |
if (first == false) { | |
b.append('&'); | |
} else { | |
first = false; | |
} | |
b.append(key).append('=') | |
.append(URLEncoder.encode(params.get(key), ENC).replace("+", "%20")); | |
} | |
return b.toString(); | |
} | |
static List<String> sortedKeyList(Map<String, String> map) { | |
List<String> list = new ArrayList<String>(map.keySet()); | |
Collections.sort(list); | |
return list; | |
} | |
static String escapeAndJoinStrings(Iterable<String> params) throws UnsupportedEncodingException { | |
StringBuilder b = new StringBuilder(); | |
boolean first = true; | |
for (String s : params) { | |
if (first == false) { | |
b.append('&'); | |
} else { | |
first = false; | |
} | |
b.append(URLEncoder.encode(s, ENC)); | |
} | |
return b.toString(); | |
} | |
static String generateHmacSha1Signature(String key, String data) | |
throws NoSuchAlgorithmException, InvalidKeyException, IllegalStateException, | |
UnsupportedEncodingException { | |
SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(ENC), HMAC_SHA1_ALGORITHM); | |
Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM); | |
mac.init(signingKey); | |
return byteArrayToBase64String(mac.doFinal(data.getBytes(ENC))); | |
} | |
static String generateTimestamp() { | |
return Long.toString(System.currentTimeMillis() / 1000L); | |
} | |
static String generateNonce() { | |
return Long.toString(new Random().nextLong()); | |
} | |
static String byteArrayToBase64String(byte[] bytes) { | |
int bytesLength = bytes.length; | |
int fullGroups = bytesLength / 3; | |
int partialGroup = bytesLength - 3 * fullGroups; | |
int resultLength = 4 * ((bytesLength + 2) / 3); | |
StringBuilder b = new StringBuilder(resultLength); | |
int cursor = 0; | |
for (int i = 0; i < fullGroups; i++) { | |
int byte0 = bytes[cursor++] & 0xff; | |
int byte1 = bytes[cursor++] & 0xff; | |
int byte2 = bytes[cursor++] & 0xff; | |
b.append(intToBase64[byte0 >> 2]); | |
b.append(intToBase64[(byte0 << 4) & 0x3f | (byte1 >> 4)]); | |
b.append(intToBase64[(byte1 << 2) & 0x3f | (byte2 >> 6)]); | |
b.append(intToBase64[byte2 & 0x3f]); | |
} | |
if (partialGroup != 0) { | |
int byte0 = bytes[cursor++] & 0xff; | |
b.append(intToBase64[byte0 >> 2]); | |
if (partialGroup == 1) { | |
b.append(intToBase64[(byte0 << 4) & 0x3f]); | |
b.append("=="); | |
} else { | |
int byte1 = bytes[cursor++] & 0xff; | |
b.append(intToBase64[(byte0 << 4) & 0x3f | (byte1 >> 4)]); | |
b.append(intToBase64[(byte1 << 2) & 0x3f]); | |
b.append('='); | |
} | |
} | |
return b.toString(); | |
} | |
static final char intToBase64[] = { | |
'A', | |
'B', | |
'C', | |
'D', | |
'E', | |
'F', | |
'G', | |
'H', | |
'I', | |
'J', | |
'K', | |
'L', | |
'M', | |
'N', | |
'O', | |
'P', | |
'Q', | |
'R', | |
'S', | |
'T', | |
'U', | |
'V', | |
'W', | |
'X', | |
'Y', | |
'Z', | |
'a', | |
'b', | |
'c', | |
'd', | |
'e', | |
'f', | |
'g', | |
'h', | |
'i', | |
'j', | |
'k', | |
'l', | |
'm', | |
'n', | |
'o', | |
'p', | |
'q', | |
'r', | |
's', | |
't', | |
'u', | |
'v', | |
'w', | |
'x', | |
'y', | |
'z', | |
'0', | |
'1', | |
'2', | |
'3', | |
'4', | |
'5', | |
'6', | |
'7', | |
'8', | |
'9', | |
'+', | |
'/' | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment