package com.mime.qweibo;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import com.mime.qweibo.utils.Base64Encoder;
public class OAuth implements Serializable {
static final long serialVersionUID = -8736851024315996L;
private static final String OAuthVersion = "1.0";
private static final String OAuthQParameterPrefix = "oauth_";
private static final String OAuthConsumerKeyKey = "oauth_consumer_key";
private static final String OAuthCallbackKey = "oauth_callback";
private static final String OAuthVersionKey = "oauth_version";
private static final String OAuthSignatureMethodKey = "oauth_signature_method";
private static final String OAuthSignatureKey = "oauth_signature";
private static final String OAuthTimestampKey = "oauth_timestamp";
private static final String OAuthNonceKey = "oauth_nonce";
private static final String OAuthTokenKey = "oauth_token";
private static final String oAauthVerifier = "oauth_verifier";
private static final String OAuthTokenSecretKey = "oauth_token_secret";
private static final String HMACSHA1SignatureType = "HmacSHA1";
private static final String HMACSHA1SignatureType_TEXT = "HMAC-SHA1";
private Random random = new Random();
private String unreservedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
/**
* Get the URL based on the specified key.
*
* @param url
* The full url that needs to be signed including its non OAuth
* url parameters
* @param httpMethod
* The http method used. Must be a valid HTTP method verb
* (POST,GET,PUT, etc)
* @param customKey
* The consumer key
* @param customSecrect
* The consumer seceret
* @param tokenKey
* The token, if available. If not available pass null or an
* empty string
* @param tokenSecrect
* The token secret, if available. If not available pass null or
* an empty string
* @param verify
* The oAauth Verifier.
* @param callbackUrl
* The OAuth Callback URL(You should encode this url if it
* contains some unreserved characters).
* @param parameters
* @param queryString
* @return
*/
public String getOauthUrl(String url, String httpMethod, String customKey,
String customSecrect, String tokenKey, String tokenSecrect,
String verify, String callbackUrl, List<QParameter> parameters,
StringBuffer queryString) {
String parameterString = normalizeRequestParameters(parameters);
String urlWithQParameter = url;
if (parameterString != null && !parameterString.equals("")) {
urlWithQParameter += "?" + parameterString;
}
URL aUrl = null;
try {
aUrl = new URL(urlWithQParameter);
} catch (MalformedURLException e) {
System.err.println("URL parse error:" + e.getLocalizedMessage());
}
String nonce = generateNonce();
String timeStamp = generateTimeStamp();
parameters.add(new QParameter(OAuthVersionKey, OAuthVersion));
parameters.add(new QParameter(OAuthNonceKey, nonce));
parameters.add(new QParameter(OAuthTimestampKey, timeStamp));
parameters.add(new QParameter(OAuthSignatureMethodKey,
HMACSHA1SignatureType_TEXT));
parameters.add(new QParameter(OAuthConsumerKeyKey, customKey));
if (tokenKey != null && !tokenKey.equals("")) {
parameters.add(new QParameter(OAuthTokenKey, tokenKey));
}
if (verify != null && !verify.equals("")) {
parameters.add(new QParameter(oAauthVerifier, verify));
}
if (callbackUrl != null && !callbackUrl.equals("")) {
parameters.add(new QParameter(OAuthCallbackKey, callbackUrl));
}
StringBuffer normalizedUrl = new StringBuffer();
String signature = generateSignature(aUrl, customSecrect, tokenSecrect,
httpMethod, parameters, normalizedUrl, queryString);
queryString.append("&oauth_signature=");
queryString.append(encode(signature));
return normalizedUrl.toString();
}
/**
* Normalizes the request parameters according to the spec.
*
* @param parameters
* The list of parameters already sorted
* @return a string representing the normalized parameters
*/
private String normalizeRequestParameters(List<QParameter> parameters) {
StringBuffer sb = new StringBuffer();
QParameter p = null;
for (int i = 0, size = parameters.size(); i < size; i++) {
p = parameters.get(i);
sb.append(p.mName);
sb.append("=");
sb.append(p.mValue);
if (i < size - 1) {
sb.append("&");
}
}
return sb.toString();
}
/**
* Generate the timestamp for the signature.
*
* @return
*/
private String generateTimeStamp() {
return String.valueOf(System.currentTimeMillis() / 1000);
}
/**
* Just a simple implementation of a random number between 123400 and
* 9999999
*
* @return
*/
private String generateNonce() {
return String.valueOf(random.nextInt(9876599) + 123400);
}
/**
* @param value
* string to be encoded
* @return encoded string
* @see <a href="http://wiki.oauth.net/TestCases">OAuth / TestCases</a>
* @see <a
* href="http://groups.google.com/group/oauth/browse_thread/thread/a8398d0521f4ae3d/9d79b698ab217df2?hl=en&lnk=gst&q=space+encoding#9d79b698ab217df2">Space
* encoding - OAuth | Google Groups</a>
* @see <a href="http://tools.ietf.org/html/rfc3986#section-2.1">RFC 3986 -
* Uniform Resource Identifier (URI): Generic Syntax - 2.1.
* Percent-Encoding</a>
*/
public static String encode(String value) {
String encoded = null;
try {
encoded = URLEncoder.encode(value, "UTF-8");
} catch (UnsupportedEncodingException ignore) {
}
StringBuffer buf = new StringBuffer(encoded.length());
char focus;
for (int i = 0; i < encoded.length(); i++) {
focus = encoded.charAt(i);
if (focus == '*') {
buf.append("%2A");
} else if (focus == '+') {
buf.append("%20");
} else if (focus == '%' && (i + 1) < encoded.length()
&& encoded.charAt(i + 1) == '7'
&& encoded.charAt(i + 2) == 'E') {
buf.append('~');
i += 2;
} else {
buf.append(focus);
}
}
return buf.toString();
}
/**
* Generates a signature using the HMAC-SHA1 algorithm
*
* @param url
* The full url that needs to be signed including its non OAuth
* url parameters
* @param consumerSecret
* The consumer seceret
* @param tokenSecret
* The token secret, if available. If not available pass null or
* an empty string
* @param httpMethod
* The http method used. Must be a valid HTTP method verb
* (POST,GET,PUT, etc)
* @param parameters
* @param normalizedUrl
* @param normalizedRequestParameters
* @return A base64 string of the hash value
*/
private String generateSignature(URL url, String consumerSecret,
String tokenSecret, String httpMethod, List<QParameter> parameters,
StringBuffer normalizedUrl, StringBuffer normalizedRequestParameters) {
String signatureBase = generateSignatureBase(url, httpMethod,
parameters, normalizedUrl, normalizedRequestParameters);
byte[] oauthSignature = null;
try {
Mac mac = Mac.getInstance(HMACSHA1SignatureType);
String oauthKey = encode(consumerSecret)
+ "&"
+ ((tokenSecret == null || tokenSecret.equals("")) ? ""
: encode(tokenSecret));
SecretKeySpec spec = new SecretKeySpec(
oauthKey.getBytes("US-ASCII"), HMACSHA1SignatureType);
mac.init(spec);
oauthSignature = mac.doFinal(signatureBase.getBytes("US-ASCII"));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return Base64Encoder.encode(oauthSignature);
}
/**
* Generate the signature base that is used to produce the signature
*
* @param url
* The full url that needs to be signed including its non OAuth
* url parameters
* @param httpMethod
* The http method used. Must be a valid HTTP method verb
* (POST,GET,PUT, etc)
* @param parameters
* @param normalizedUrl
* @param normalizedRequestParameters
* @return
*/
private String generateSignatureBase(URL url, String httpMethod,
List<QParameter> parameters, StringBuffer normalizedUrl,
StringBuffer normalizedRequestParameters) {
Collections.sort(parameters);
normalizedUrl.append(url.getProtocol());
normalizedUrl.append("://");
normalizedUrl.append(url.getHost());
if ((url.getProtocol().equals("http") || url.getProtocol().equals(
"https"))
&& url.getPort() != -1) {
normalizedUrl.append(":");
normalizedUrl.append(url.getPort());
}
normalizedUrl.append(url.getPath());
normalizedRequestParameters.append(formEncodeParameters(parameters));
StringBuffer signatureBase = new StringBuffer();
signatureBase.append(httpMethod.toUpperCase());
signatureBase.append("&");
signatureBase.append(encode(normalizedUrl.toString()));
signatureBase.append("&");
signatureBase.append(encode(normalizedRequestParameters.toString()));
return signatureBase.toString();
}
/**
* Encode each parameters in list.
*
* @param parameters
* List of parameters
* @return Encoded parameters
*/
private String formEncodeParameters(List<QParameter> parameters) {
List<QParameter> encodeParams = new ArrayList<QParameter>();
for (QParameter a : parameters) {
encodeParams.add(new QParameter(a.mName, encode(a.mValue)));
}
return normalizeRequestParameters(encodeParams);
}
}