diff options
Diffstat (limited to 'src/com/p4square/restlet/oauth')
-rw-r--r-- | src/com/p4square/restlet/oauth/OAuthAuthenticator.java | 95 | ||||
-rw-r--r-- | src/com/p4square/restlet/oauth/OAuthAuthenticatorHelper.java | 177 | ||||
-rw-r--r-- | src/com/p4square/restlet/oauth/OAuthException.java | 25 | ||||
-rw-r--r-- | src/com/p4square/restlet/oauth/OAuthHelper.java | 149 | ||||
-rw-r--r-- | src/com/p4square/restlet/oauth/OAuthUser.java | 50 | ||||
-rw-r--r-- | src/com/p4square/restlet/oauth/Token.java | 52 |
6 files changed, 0 insertions, 548 deletions
diff --git a/src/com/p4square/restlet/oauth/OAuthAuthenticator.java b/src/com/p4square/restlet/oauth/OAuthAuthenticator.java deleted file mode 100644 index c33bb5a..0000000 --- a/src/com/p4square/restlet/oauth/OAuthAuthenticator.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2013 Jesse Morgan - */ - -package com.p4square.restlet.oauth; - -import org.apache.log4j.Logger; - -import org.restlet.Context; -import org.restlet.Request; -import org.restlet.Response; -import org.restlet.security.Authenticator; -import org.restlet.security.User; - -/** - * Authenticator which makes an OAuth request to authenticate the user. - * - * If this Authenticator is made optional than no requests are made to the - * service provider. - * - * @author Jesse Morgan <jesse@jesterpm.net> - */ -public class OAuthAuthenticator extends Authenticator { - private static Logger LOG = Logger.getLogger(OAuthAuthenticator.class); - - private static final String OAUTH_TOKEN = "oauth_token"; - private static final String COOKIE_NAME = "oauth_secret"; - - private final OAuthHelper mHelper; - - /** - * Create a new Authenticator. - * - * @param Context the current context. - * @param optional If true, unauthenticated users are allowed to continue. - * @param helper The OAuthHelper which will help with the requests. - */ - public OAuthAuthenticator(Context context, boolean optional, OAuthHelper helper) { - super(context, false, optional, null); - - mHelper = helper; - } - - protected boolean authenticate(Request request, Response response) { - /* - * The authentication workflow has three steps: - * 1. Get RequestToken - * 2. Authenticate the user - * 3. Get AccessToken - * - * The authentication workflow is broken into two stages. In the first, - * we generate the RequestToken (step 1) and redirect the user to the - * authentication page. When the user comes back, we will request the - * AccessToken (step 2). - * - * We determine which half we are in by the presence of the oauth_token - * parameter in the query string. - */ - - final String token = request.getResourceRef().getQueryAsForm().getFirstValue(OAUTH_TOKEN); - final String secret = request.getCookies().getFirstValue(COOKIE_NAME); - - try { - if (token == null) { - if (isOptional()) { - return false; - } - - // 1. Get RequestToken - Token requestToken = mHelper.getRequestToken(); - - if (requestToken == null) { - return false; - } - - // 2. Redirect user - // TODO Encrypt cookie - response.getCookieSettings().add(COOKIE_NAME, requestToken.getSecret()); - response.redirectSeeOther(mHelper.getLoginUrl(requestToken, request.getResourceRef().toString())); - return false; - - } else { - // 3. Get AccessToken - Token requestToken = new Token(token, secret); - User user = mHelper.getAccessToken(requestToken); - request.getClientInfo().setUser(user); - return true; - } - - } catch (OAuthException e) { - LOG.debug("Authentication failed: " + e); - return false; - } - } -} diff --git a/src/com/p4square/restlet/oauth/OAuthAuthenticatorHelper.java b/src/com/p4square/restlet/oauth/OAuthAuthenticatorHelper.java deleted file mode 100644 index 76ff044..0000000 --- a/src/com/p4square/restlet/oauth/OAuthAuthenticatorHelper.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright 2013 Jesse Morgan - */ - -package com.p4square.restlet.oauth; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; - -import java.net.URLEncoder; - -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; - -import java.util.Collections; -import java.util.Random; - -import javax.crypto.Mac; -import javax.crypto.SecretKey; -import javax.crypto.spec.SecretKeySpec; - -import org.restlet.Request; -import org.restlet.Response; -import org.restlet.data.ChallengeRequest; -import org.restlet.data.ChallengeResponse; -import org.restlet.data.ChallengeScheme; -import org.restlet.data.CharacterSet; -import org.restlet.data.Form; -import org.restlet.data.Method; -import org.restlet.data.Parameter; -import org.restlet.data.Reference; -import org.restlet.engine.header.ChallengeWriter; -import org.restlet.engine.header.Header; -import org.restlet.engine.security.AuthenticatorHelper; -import org.restlet.engine.util.Base64; -import org.restlet.util.Series; - -/** - * Authentication helper for signing OAuth Requests. - * - * This implementation is limited to one consumer token/secret per restlet - * engine. In practice this means you will only be able to interact with one - * service provider unless you loaded/unloaded the AuthenticationHelper for - * each request. - * - * @author Jesse Morgan <jesse@jesterpm.net> - */ -public class OAuthAuthenticatorHelper extends AuthenticatorHelper { - private static final String SIGNATURE_METHOD = "HMAC-SHA1"; - private static final String JAVA_SIGNATURE_METHOD = "HmacSHA1"; - private static final String ENCODING = "UTF-8"; - - private final Random mRandom; - private final Token mConsumerToken; - - /** - * Package-private constructor. - * - * This class should only be instantiated by OAuthHelper. - */ - OAuthAuthenticatorHelper(Token consumerToken) { - super(ChallengeScheme.HTTP_OAUTH, true, false); - - mRandom = new Random(); - mConsumerToken = consumerToken; - } - - @Override - public void formatRequest(ChallengeWriter cw, ChallengeRequest cr, - Response response, Series<Header> httpHeaders) throws IOException { - - throw new UnsupportedOperationException("OAuth Requests are not implemented"); - } - - @Override - public void formatResponse(ChallengeWriter cw, ChallengeResponse response, - Request request, Series<Header> httpHeaders) { - - try { - Series<Parameter> authParams = new Series<Parameter>(Parameter.class); - - String nonce = String.valueOf(mRandom.nextInt()); - String timestamp = String.valueOf(System.currentTimeMillis() / 1000); - - authParams.add(new Parameter("oauth_consumer_key", mConsumerToken.getToken())); - authParams.add(new Parameter("oauth_nonce", nonce)); - authParams.add(new Parameter("oauth_signature_method", SIGNATURE_METHOD)); - authParams.add(new Parameter("oauth_timestamp", timestamp)); - authParams.add(new Parameter("oauth_version", "1.0")); - - String accessToken = response.getIdentifier(); - if (accessToken != null) { - authParams.add(new Parameter("oauth_token", accessToken)); - } - - // Generate Signature - String signature = generateSignature(response, request, authParams); - authParams.add(new Parameter("oauth_signature", signature)); - - // Write Header - for (Parameter p : authParams) { - cw.appendQuotedChallengeParameter(encode(p.getName()), encode(p.getValue())); - } - - } catch (IOException e) { - throw new RuntimeException(e); - - } catch (InvalidKeyException e) { - throw new RuntimeException(e); - - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - } - - /** - * Helper method to generate an OAuth Signature. - */ - private String generateSignature(ChallengeResponse response, Request request, - Series<Parameter> authParams) - throws NoSuchAlgorithmException, InvalidKeyException, IOException, - UnsupportedEncodingException { - - // HTTP Request Method - String httpMethod = request.getMethod().getName(); - - // Request Url - Reference url = request.getResourceRef(); - String requestUrl = encode(url.getScheme() + ":" + url.getHierarchicalPart()); - - // Normalized parameters - Series<Parameter> params = new Series<Parameter>(Parameter.class); - - // OAUTH Params - params.addAll(authParams); - - // Query Params - Form query = url.getQueryAsForm(); - params.addAll(query); - - // Sort it - Collections.sort(params); - - StringBuilder normalizedParamsBuilder = new StringBuilder(); - for (Parameter p : params) { - normalizedParamsBuilder.append('&'); - normalizedParamsBuilder.append(p.encode(CharacterSet.UTF_8)); - } - String normalizedParams = encode(normalizedParamsBuilder.substring(1)); // remove the first & - - // Generate signature base - String sigBase = httpMethod + "&" + requestUrl + "&" + normalizedParams.toString(); - - // Sign the signature base - Mac mac = Mac.getInstance(JAVA_SIGNATURE_METHOD); - - String accessTokenSecret = ""; - if (response.getIdentifier() != null) { - accessTokenSecret = new String(response.getSecret()); - } - - byte[] keyBytes = (encode(mConsumerToken.getSecret()) + "&" + encode(accessTokenSecret)).getBytes(ENCODING); - SecretKey key = new SecretKeySpec(keyBytes, JAVA_SIGNATURE_METHOD); - mac.init(key); - - byte[] signature = mac.doFinal(sigBase.getBytes(ENCODING)); - - return Base64.encode(signature, false).trim(); - } - - /** - * Helper method to URL Encode Strings. - */ - private String encode(String input) throws UnsupportedEncodingException { - return URLEncoder.encode(input, ENCODING); - } -} diff --git a/src/com/p4square/restlet/oauth/OAuthException.java b/src/com/p4square/restlet/oauth/OAuthException.java deleted file mode 100644 index dd326d3..0000000 --- a/src/com/p4square/restlet/oauth/OAuthException.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2013 Jesse Morgan - */ - -package com.p4square.restlet.oauth; - -import org.restlet.data.Status; - -/** - * Exception throw when the service provider returns an error. - * - * @author Jesse Morgan <jesse@jesterpm.net> - */ -public class OAuthException extends Exception { - private final Status mStatus; - - public OAuthException(Status status) { - super("Service provider failed request: " + status.getDescription()); - mStatus = status; - } - - public Status getStatus() { - return mStatus; - } -} diff --git a/src/com/p4square/restlet/oauth/OAuthHelper.java b/src/com/p4square/restlet/oauth/OAuthHelper.java deleted file mode 100644 index 67dd238..0000000 --- a/src/com/p4square/restlet/oauth/OAuthHelper.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2013 Jesse Morgan - */ - -package com.p4square.restlet.oauth; - -import java.net.URLEncoder; - -import org.restlet.Context; -import org.restlet.Request; -import org.restlet.Response; -import org.restlet.Restlet; -import org.restlet.data.ChallengeResponse; -import org.restlet.data.ChallengeScheme; -import org.restlet.data.Form; -import org.restlet.data.Method; -import org.restlet.data.Reference; -import org.restlet.data.Status; -import org.restlet.engine.Engine; -import org.restlet.representation.Representation; - -/** - * Helper Class for OAuth 1.0 Authentication. - * - * @author Jesse Morgan <jesse@jesterpm.net> - */ -public abstract class OAuthHelper { - private final Restlet mDispatcher; - private final Token mConsumerToken; - - /** - * Create a new OAuth Helper. - * As currently implemented, there can only be one OAuthHelper per Restlet - * Engine since this class registers its own provider for the OAuth - * authentication protocol. - * - * FIXME: This could be improved by making OAuthAuthenticationHelper and - * maybe Token aware of multiple service providers. - * - * @param context The restlet context which provides a ClientDispatcher. - * @param consumerKey The OAuth consumer key for this application. - * @param consumerSecret the OAuth consumer secret for this application. - */ - public OAuthHelper(Context context, String consumerKey, String consumerSecret) { - mDispatcher = context.getClientDispatcher(); - mConsumerToken = new Token(consumerKey, consumerSecret); - - Engine.getInstance().getRegisteredAuthenticators().add(new OAuthAuthenticatorHelper(mConsumerToken)); - } - - /** - * @return the URL for the initial RequestToken request. - */ - protected abstract String getRequestTokenUrl(); - - /** - * Request a RequestToken. - * - * @return a Token containing the RequestToken. - * @throws OAuthException if the request fails. - */ - public Token getRequestToken() throws OAuthException { - Request request = new Request(Method.GET, getRequestTokenUrl()); - request.setChallengeResponse(new ChallengeResponse(ChallengeScheme.HTTP_OAUTH)); - - Response response = mDispatcher.handle(request); - - return processTokenRequest(response); - } - - /** - * @return the URL to redirect the user to for Authentication. - */ - public abstract String getLoginUrl(Token requestToken, String callback); - - /** - * @return the URL for the AccessToken request. - */ - protected abstract String getAccessTokenUrl(); - - /** - * Request an AccessToken for a previously authenticated RequestToken. - * - * @return an OAuthUser object containing the AccessToken. - * @throws OAuthException if the request fails. - */ - public OAuthUser getAccessToken(Token requestToken) throws OAuthException { - Request request = new Request(Method.GET, getAccessTokenUrl()); - request.setChallengeResponse(requestToken.getChallengeResponse()); - - return processAccessTokenRequest(request); - } - - /** - * Helper method to decode the token returned from an OAuth Request. - * - * @param response The Response object from the Request. - * @return the Token from the oauth_token and oauth_token_secret parameters. - * @throws OAuthException is the server reported an error. - */ - protected Token processTokenRequest(Response response) throws OAuthException { - Status status = response.getStatus(); - Representation entity = response.getEntity(); - - try { - if (status.isSuccess()) { - Form form = new Form(entity); - String token = form.getFirstValue("oauth_token"); - String secret = form.getFirstValue("oauth_token_secret"); - - return new Token(token, secret); - - } else { - throw new OAuthException(status); - } - } finally { - entity.release(); - } - } - - /** - * Helper method to create an OAuthUser from the AccessToken request. - * - * The User's identifier is set to the Content-Location header, if present. - * - * @param response The Response to the AccessToken Request. - * @return An OAuthUser object wrapping the AccessToken. - * @throws OAuthException if the request failed. - */ - public OAuthUser processAccessTokenRequest(Request request) throws OAuthException { - Response response = getResponse(request); - Token accessToken = processTokenRequest(response); - - Reference ref = response.getEntity().getLocationRef(); - if (ref != null) { - return new OAuthUser(ref.toString(), accessToken); - - } else { - return new OAuthUser(accessToken); - } - } - - /** - * Helper method to get a Response for a Request. - */ - public Response getResponse(Request request) { - return mDispatcher.handle(request); - } -} diff --git a/src/com/p4square/restlet/oauth/OAuthUser.java b/src/com/p4square/restlet/oauth/OAuthUser.java deleted file mode 100644 index 11dbac1..0000000 --- a/src/com/p4square/restlet/oauth/OAuthUser.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2013 Jesse Morgan - */ - -package com.p4square.restlet.oauth; - -import org.restlet.data.ChallengeResponse; -import org.restlet.security.User; - -/** - * Simple User object which also contains an OAuth AccessToken. - * - * @author Jesse Morgan <jesse@jesterpm.net> - */ -public class OAuthUser extends User { - private final Token mToken; - private final String mContentLocation; - - public OAuthUser(Token token) { - this(null, token); - } - - public OAuthUser(String location, Token token) { - super(); - mToken = token; - mContentLocation = location; - } - - /** - * @return the Location associated with the user. - */ - public String getLocation() { - return mContentLocation; - } - - /** - * @return The AccessToken. - */ - public Token getToken() { - return mToken; - } - - /** - * Convenience method for getToken().getChallengeResponse(). - * @return A ChallengeResponse based upon the access token. - */ - public ChallengeResponse getChallengeResponse() { - return mToken.getChallengeResponse(); - } -} diff --git a/src/com/p4square/restlet/oauth/Token.java b/src/com/p4square/restlet/oauth/Token.java deleted file mode 100644 index 51a9087..0000000 --- a/src/com/p4square/restlet/oauth/Token.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2013 Jesse Morgan - */ - -package com.p4square.restlet.oauth; - -import org.restlet.data.ChallengeResponse; -import org.restlet.data.ChallengeScheme; - -/** - * Token wraps the two Strings which make up an OAuth Token: the public - * component and the private component. - * - * @author Jesse Morgan <jesse@jesterpm.net> - */ -public class Token { - private final String mToken; - private final String mSecret; - - public Token(String token, String secret) { - mToken = token; - mSecret = secret; - } - - /** - * @return the public component. - */ - public String getToken() { - return mToken; - } - - /** - * @return the secret component. - */ - public String getSecret() { - return mSecret; - } - - @Override - public String toString() { - return mToken + "&" + mSecret; - } - - /** - * Generate a ChallengeResponse based on this Token. - * - * @return a ChallengeResponse object using the OAUTH ChallengeScheme. - */ - public ChallengeResponse getChallengeResponse() { - return new ChallengeResponse(ChallengeScheme.HTTP_OAUTH, mToken, mSecret); - } -} |