package evanq.game.auth.provider;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.codec.digest.DigestUtils;
import net.oauth.OAuthAccessor;
import net.oauth.OAuthConsumer;
import net.oauth.OAuthException;
import net.oauth.OAuthMessage;
import net.oauth.OAuthProblemException;
import net.oauth.OAuthValidator;
import net.oauth.SimpleOAuthValidator;
import net.oauth.server.OAuthServlet;
/**
* Utility methods for providers that store consumers, tokens and secrets in
* local cache (HashSet). Consumer key is used as the name, and its credentials are
* stored in HashSet.
*
* @author Praveen Alavilli
*/
public class SampleOAuthProvider {
public static final OAuthValidator VALIDATOR = new SimpleOAuthValidator();
private static final Map<String, OAuthConsumer> ALL_CONSUMERS
= Collections.synchronizedMap(new HashMap<String,OAuthConsumer>(10));
private static final Collection<OAuthAccessor> ALL_TOKENS = new HashSet<OAuthAccessor>();
private static Properties consumerProperties = null;
public static synchronized void loadConsumers(
ServletConfig config) throws IOException {
Properties p = consumerProperties;
if (p == null) {
p = new Properties();
String resourceName = "/"
+ SampleOAuthProvider.class.getPackage().getName().replace(
".", "/") + "/provider.properties";
URL resource = SampleOAuthProvider.class.getClassLoader()
.getResource(resourceName);
if (resource == null) {
throw new IOException("resource not found: " + resourceName);
}
InputStream stream = resource.openStream();
try {
p.load(stream);
} finally {
stream.close();
}
}
consumerProperties = p;
// for each entry in the properties file create a OAuthConsumer
for(Map.Entry prop : p.entrySet()) {
String consumer_key = (String) prop.getKey();
// make sure it's key not additional properties
if(!consumer_key.contains(".")){
String consumer_secret = (String) prop.getValue();
if(consumer_secret != null){
String consumer_description = (String) p.getProperty(consumer_key + ".description");
String consumer_callback_url = (String) p.getProperty(consumer_key + ".callbackURL");
// Create OAuthConsumer w/ key and secret
OAuthConsumer consumer = new OAuthConsumer(
consumer_callback_url,
consumer_key,
consumer_secret,
null);
consumer.setProperty("name", consumer_key);
consumer.setProperty("description", consumer_description);
ALL_CONSUMERS.put(consumer_key, consumer);
}
}
}
}
public static synchronized OAuthConsumer getConsumer(
OAuthMessage requestMessage)
throws IOException, OAuthProblemException {
OAuthConsumer consumer = null;
// try to load from local cache if not throw exception
String consumer_key = requestMessage.getConsumerKey();
consumer = SampleOAuthProvider.ALL_CONSUMERS.get(consumer_key);
if(consumer == null) {
OAuthProblemException problem = new OAuthProblemException("token_rejected");
throw problem;
}
return consumer;
}
/**
* Get the access token and token secret for the given oauth_token.
*/
public static synchronized OAuthAccessor getAccessor(OAuthMessage requestMessage)
throws IOException, OAuthProblemException {
// try to load from local cache if not throw exception
String consumer_token = requestMessage.getToken();
OAuthAccessor accessor = null;
for (OAuthAccessor a : SampleOAuthProvider.ALL_TOKENS) {
if(a.requestToken != null) {
if (a.requestToken.equals(consumer_token)) {
accessor = a;
break;
}
} else if(a.accessToken != null){
if (a.accessToken.equals(consumer_token)) {
accessor = a;
break;
}
}
}
if(accessor == null){
OAuthProblemException problem = new OAuthProblemException("token_expired");
throw problem;
}
return accessor;
}
/**
* Set the access token
*/
public static synchronized void markAsAuthorized(OAuthAccessor accessor, String userId)
throws OAuthException {
// first remove the accessor from cache
ALL_TOKENS.remove(accessor);
accessor.setProperty("user", userId);
accessor.setProperty("authorized", Boolean.TRUE);
// update token in local cache
ALL_TOKENS.add(accessor);
}
/**
* Generate a fresh request token and secret for a consumer.
*
* @throws OAuthException
*/
public static synchronized void generateRequestToken(
OAuthAccessor accessor)
throws OAuthException {
// generate oauth_token and oauth_secret
String consumer_key = (String) accessor.consumer.getProperty("name");
// generate token and secret based on consumer_key
// for now use md5 of name + current time as token
String token_data = consumer_key + System.nanoTime();
String token = DigestUtils.md5Hex(token_data);
// for now use md5 of name + current time + token as secret
String secret_data = consumer_key + System.nanoTime() + token;
String secret = DigestUtils.md5Hex(secret_data);
accessor.requestToken = token;
accessor.tokenSecret = secret;
accessor.accessToken = null;
// add to the local cache
ALL_TOKENS.add(accessor);
}
/**
* Generate a fresh request token and secret for a consumer.
*
* @throws OAuthException
*/
public static synchronized void generateAccessToken(OAuthAccessor accessor)
throws OAuthException {
// generate oauth_token and oauth_secret
String consumer_key = (String) accessor.consumer.getProperty("name");
// generate token and secret based on consumer_key
// for now use md5 of name + current time as token
String token_data = consumer_key + System.nanoTime();
String token = DigestUtils.md5Hex(token_data);
// first remove the accessor from cache
ALL_TOKENS.remove(accessor);
accessor.requestToken = null;
accessor.accessToken = token;
// update token in local cache
ALL_TOKENS.add(accessor);
}
public static void handleException(Exception e, HttpServletRequest request,
HttpServletResponse response, boolean sendBody)
throws IOException, ServletException {
String realm = (request.isSecure())?"https://":"http://";
realm += request.getLocalName();
OAuthServlet.handleException(response, e, realm, sendBody);
}
}