package com.cattong.commons.oauth;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import com.cattong.commons.util.StringUtil;
public class OAuth {
public static final String VERSION_1_0 = "1.0";
/** The encoding used to represent characters as bytes. */
public static final String ENCODING = "UTF-8";
/** The MIME type for a sequence of OAuth parameters. */
public static final String FORM_ENCODED = "application/x-www-form-urlencoded";
public static final String OAUTH_CONSUMER_KEY = "oauth_consumer_key";
public static final String OAUTH_TOKEN = "oauth_token";
public static final String OAUTH_TOKEN_SECRET = "oauth_token_secret";
public static final String OAUTH_SIGNATURE_METHOD = "oauth_signature_method";
public static final String OAUTH_SIGNATURE = "oauth_signature";
public static final String OAUTH_TIMESTAMP = "oauth_timestamp";
public static final String OAUTH_NONCE = "oauth_nonce";
public static final String OAUTH_VERSION = "oauth_version";
public static final String OAUTH_CALLBACK = "oauth_callback";
public static final String OAUTH_CALLBACK_CONFIRMED = "oauth_callback_confirmed";
public static final String OAUTH_VERIFIER = "oauth_verifier";
public static final String HMAC_SHA1 = "HMAC-SHA1";
public static final String RSA_SHA1 = "RSA-SHA1";
/**
* Strings used for <a href="http://wiki.oauth.net/ProblemReporting">problem
* reporting</a>.
*/
public static class Problems {
public static final String VERSION_REJECTED = "version_rejected";
public static final String PARAMETER_ABSENT = "parameter_absent";
public static final String PARAMETER_REJECTED = "parameter_rejected";
public static final String TIMESTAMP_REFUSED = "timestamp_refused";
public static final String NONCE_USED = "nonce_used";
public static final String SIGNATURE_METHOD_REJECTED = "signature_method_rejected";
public static final String SIGNATURE_INVALID = "signature_invalid";
public static final String CONSUMER_KEY_UNKNOWN = "consumer_key_unknown";
public static final String CONSUMER_KEY_REJECTED = "consumer_key_rejected";
public static final String CONSUMER_KEY_REFUSED = "consumer_key_refused";
public static final String TOKEN_USED = "token_used";
public static final String TOKEN_NOT_AUTHORIZED = "token_not_authorized";
public static final String TOKEN_EXPIRED = "token_expired";
public static final String TOKEN_REVOKED = "token_revoked";
public static final String TOKEN_REJECTED = "token_rejected";
public static final String ADDITIONAL_AUTHORIZATION_REQUIRED = "additional_authorization_required";
public static final String PERMISSION_UNKNOWN = "permission_unknown";
public static final String PERMISSION_DENIED = "permission_denied";
public static final String USER_REFUSED = "user_refused";
public static final String OAUTH_ACCEPTABLE_VERSIONS = "oauth_acceptable_versions";
public static final String OAUTH_ACCEPTABLE_TIMESTAMPS = "oauth_acceptable_timestamps";
public static final String OAUTH_PARAMETERS_ABSENT = "oauth_parameters_absent";
public static final String OAUTH_PARAMETERS_REJECTED = "oauth_parameters_rejected";
public static final String OAUTH_PROBLEM_ADVICE = "oauth_problem_advice";
public static final Map<String, Integer> TO_HTTP_CODE = mapToHttpCode();
private static Map<String, Integer> mapToHttpCode() {
Integer badRequest = Integer.valueOf(400);
Integer unauthorized = Integer.valueOf(401);
Integer serviceUnavailable = Integer.valueOf(503);
Map<String, Integer> map = new HashMap<String, Integer>();
map.put(Problems.VERSION_REJECTED, badRequest);
map.put(Problems.PARAMETER_ABSENT, badRequest);
map.put(Problems.PARAMETER_REJECTED, badRequest);
map.put(Problems.TIMESTAMP_REFUSED, badRequest);
map.put(Problems.SIGNATURE_METHOD_REJECTED, badRequest);
map.put(Problems.NONCE_USED, unauthorized);
map.put(Problems.TOKEN_USED, unauthorized);
map.put(Problems.TOKEN_EXPIRED, unauthorized);
map.put(Problems.TOKEN_REVOKED, unauthorized);
map.put(Problems.TOKEN_REJECTED, unauthorized);
map.put(Problems.TOKEN_NOT_AUTHORIZED, unauthorized);
map.put(Problems.SIGNATURE_INVALID, unauthorized);
map.put(Problems.CONSUMER_KEY_UNKNOWN, unauthorized);
map.put(Problems.CONSUMER_KEY_REJECTED, unauthorized);
map.put(Problems.ADDITIONAL_AUTHORIZATION_REQUIRED, unauthorized);
map.put(Problems.PERMISSION_UNKNOWN, unauthorized);
map.put(Problems.PERMISSION_DENIED, unauthorized);
map.put(Problems.USER_REFUSED, serviceUnavailable);
map.put(Problems.CONSUMER_KEY_REFUSED, serviceUnavailable);
return Collections.unmodifiableMap(map);
}
}
private static String characterEncoding = ENCODING;
public static void setCharacterEncoding(String encoding) {
OAuth.characterEncoding = encoding;
}
public static String decodeCharacters(byte[] from) {
if (characterEncoding != null) {
try {
return new String(from, characterEncoding);
} catch (UnsupportedEncodingException e) {
System.err.println(e + "");
}
}
return new String(from);
}
public static byte[] encodeCharacters(String from) {
if (characterEncoding != null) {
try {
return from.getBytes(characterEncoding);
} catch (UnsupportedEncodingException e) {
System.err.println(e + "");
}
}
return from.getBytes();
}
/** Return true if the given Content-Type header means FORM_ENCODED. */
public static boolean isFormEncoded(String contentType) {
if (contentType == null) {
return false;
}
int semi = contentType.indexOf(";");
if (semi >= 0) {
contentType = contentType.substring(0, semi);
}
return FORM_ENCODED.equalsIgnoreCase(contentType.trim());
}
/**
* Construct a form-urlencoded document containing the given sequence of
* name/value pairs. Use OAuth percent encoding (not exactly the encoding
* mandated by HTTP).
*/
public static String formEncode(Map<String, Object> parameters)
throws IOException {
ByteArrayOutputStream b = new ByteArrayOutputStream();
formEncode(parameters, b);
return decodeCharacters(b.toByteArray());
}
/**
* Write a form-urlencoded document into the given stream, containing the
* given sequence of name/value pairs.
*/
public static void formEncode(Map<String, Object> parameters,
OutputStream into) throws IOException {
if (parameters != null) {
boolean first = true;
for (Map.Entry<String, Object> parameter : parameters.entrySet()) {
if (first) {
first = false;
} else {
into.write('&');
}
into.write(encodeCharacters(percentEncode(parameter.getKey())));
into.write('=');
into.write(encodeCharacters(percentEncode(String.valueOf(parameter.getValue()))));
}
}
}
/** Parse a form-urlencoded document. */
public static Map<String, String> decodeForm(String form) {
Map<String, String> parameters = new HashMap<String, String>();
if (StringUtil.isNotEmpty(form)) {
for (String nvp : form.split("\\&")) {
int equals = nvp.indexOf('=');
String name;
String value;
if (equals < 0) {
name = decodePercent(nvp);
value = null;
} else {
name = decodePercent(nvp.substring(0, equals));
value = decodePercent(nvp.substring(equals + 1));
}
parameters.put(name, value);
}
}
return parameters;
}
/** Construct a &-separated list of the given values, percentEncoded. */
public static String percentEncode(Iterable<?> values) {
StringBuilder p = new StringBuilder();
for (Object v : values) {
if (p.length() > 0) {
p.append("&");
}
p.append(OAuth.percentEncode(String.valueOf(v)));
}
return p.toString();
}
public static String percentEncode(String s) {
if (s == null) {
return "";
}
try {
return URLEncoder.encode(s, ENCODING)
// OAuth encodes some characters differently:
.replace("+", "%20").replace("*", "%2A").replace("%7E", "~");
// This could be done faster with more hand-crafted code.
} catch (UnsupportedEncodingException wow) {
throw new RuntimeException(wow.getMessage(), wow);
}
}
public static String decodePercent(String s) {
try {
return URLDecoder.decode(s, ENCODING);
// This implements http://oauth.pbwiki.com/FlexibleDecoding
} catch (java.io.UnsupportedEncodingException wow) {
throw new RuntimeException(wow.getMessage(), wow);
}
}
}