summaryrefslogtreecommitdiff
path: root/src/main/java/com/p4square/restlet
diff options
context:
space:
mode:
authorJesse Morgan <jesse@jesterpm.net>2016-04-09 15:53:24 -0700
committerJesse Morgan <jesse@jesterpm.net>2016-04-09 15:53:24 -0700
commit371ccae3d1f31ec38f4af77fb7fcd175d49b3cd5 (patch)
tree38c4f1e8828f9af9c4b77a173bee0d312b321698 /src/main/java/com/p4square/restlet
parentbbf907e51dfcf157bdee24dead1d531122aa25db (diff)
parent3102d8bce3426d9cf41aeaf201c360d342677770 (diff)
Merge pull request #10 from PuyallupFoursquare/maven
Switching from Ivy+Ant to Maven.
Diffstat (limited to 'src/main/java/com/p4square/restlet')
-rw-r--r--src/main/java/com/p4square/restlet/metrics/MetricRouter.java61
-rw-r--r--src/main/java/com/p4square/restlet/metrics/MetricsApplication.java43
-rw-r--r--src/main/java/com/p4square/restlet/metrics/MetricsResource.java32
-rw-r--r--src/main/java/com/p4square/restlet/oauth/OAuthAuthenticator.java95
-rw-r--r--src/main/java/com/p4square/restlet/oauth/OAuthAuthenticatorHelper.java177
-rw-r--r--src/main/java/com/p4square/restlet/oauth/OAuthException.java25
-rw-r--r--src/main/java/com/p4square/restlet/oauth/OAuthHelper.java149
-rw-r--r--src/main/java/com/p4square/restlet/oauth/OAuthUser.java50
-rw-r--r--src/main/java/com/p4square/restlet/oauth/Token.java52
9 files changed, 684 insertions, 0 deletions
diff --git a/src/main/java/com/p4square/restlet/metrics/MetricRouter.java b/src/main/java/com/p4square/restlet/metrics/MetricRouter.java
new file mode 100644
index 0000000..d4da270
--- /dev/null
+++ b/src/main/java/com/p4square/restlet/metrics/MetricRouter.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2014 Jesse Morgan
+ */
+
+package com.p4square.restlet.metrics;
+
+import com.codahale.metrics.Counter;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.Timer;
+
+import org.restlet.Context;
+import org.restlet.Request;
+import org.restlet.Response;
+import org.restlet.Restlet;
+import org.restlet.routing.TemplateRoute;
+import org.restlet.routing.Router;
+
+/**
+ *
+ * @author Jesse Morgan <jesse@jesterpm.net>
+ */
+public class MetricRouter extends Router {
+
+ private final MetricRegistry mMetricRegistry;
+
+ public MetricRouter(Context context, MetricRegistry metrics) {
+ super(context);
+ mMetricRegistry = metrics;
+ }
+
+ @Override
+ protected void doHandle(Restlet next, Request request, Response response) {
+ String baseName;
+ if (next instanceof TemplateRoute) {
+ TemplateRoute temp = (TemplateRoute) next;
+ baseName = MetricRegistry.name("MetricRouter", temp.getTemplate().getPattern());
+ } else {
+ baseName = MetricRegistry.name("MetricRouter", "unknown");
+ }
+
+ final Timer.Context aggTimer = mMetricRegistry.timer("MetricRouter.time").time();
+ final Timer.Context timer = mMetricRegistry.timer(baseName + ".time").time();
+
+ try {
+ super.doHandle(next, request, response);
+ } finally {
+ timer.stop();
+ aggTimer.stop();
+
+ // Record status code
+ boolean success = !response.getStatus().isError();
+ if (success) {
+ mMetricRegistry.counter("MetricRouter.success").inc();
+ mMetricRegistry.counter(baseName + ".response.success").inc();
+ } else {
+ mMetricRegistry.counter("MetricRouter.failure").inc();
+ mMetricRegistry.counter(baseName + ".response.failure").inc();
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/p4square/restlet/metrics/MetricsApplication.java b/src/main/java/com/p4square/restlet/metrics/MetricsApplication.java
new file mode 100644
index 0000000..6caf742
--- /dev/null
+++ b/src/main/java/com/p4square/restlet/metrics/MetricsApplication.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014 Jesse Morgan
+ */
+
+package com.p4square.restlet.metrics;
+
+import java.util.concurrent.TimeUnit;
+
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.json.MetricsModule;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.restlet.Application;
+import org.restlet.Restlet;
+import org.restlet.resource.Finder;
+
+/**
+ *
+ * @author Jesse Morgan <jesse@jesterpm.net>
+ */
+public class MetricsApplication extends Application {
+ static final ObjectMapper MAPPER;
+ static {
+ MAPPER = new ObjectMapper();
+ MAPPER.registerModule(new MetricsModule(TimeUnit.SECONDS, TimeUnit.MILLISECONDS, true));
+ }
+
+ private final MetricRegistry mMetricRegistry;
+
+ public MetricsApplication(MetricRegistry metrics) {
+ mMetricRegistry = metrics;
+ }
+
+ public MetricRegistry getMetricRegistry() {
+ return mMetricRegistry;
+ }
+
+ @Override
+ public Restlet createInboundRoot() {
+ return new Finder(getContext(), MetricsResource.class);
+ }
+}
diff --git a/src/main/java/com/p4square/restlet/metrics/MetricsResource.java b/src/main/java/com/p4square/restlet/metrics/MetricsResource.java
new file mode 100644
index 0000000..e2ab14d
--- /dev/null
+++ b/src/main/java/com/p4square/restlet/metrics/MetricsResource.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2014 Jesse Morgan
+ */
+
+package com.p4square.restlet.metrics;
+
+import com.codahale.metrics.MetricRegistry;
+
+import org.restlet.ext.jackson.JacksonRepresentation;
+import org.restlet.representation.Representation;
+import org.restlet.resource.ServerResource;
+
+/**
+ *
+ * @author Jesse Morgan <jesse@jesterpm.net>
+ */
+public class MetricsResource extends ServerResource {
+
+ private MetricRegistry mMetricRegistry;
+
+ @Override
+ public void doInit() {
+ mMetricRegistry = ((MetricsApplication) getApplication()).getMetricRegistry();
+ }
+
+ @Override
+ protected Representation get() {
+ JacksonRepresentation<MetricRegistry> rep = new JacksonRepresentation<>(mMetricRegistry);
+ rep.setObjectMapper(MetricsApplication.MAPPER);
+ return rep;
+ }
+}
diff --git a/src/main/java/com/p4square/restlet/oauth/OAuthAuthenticator.java b/src/main/java/com/p4square/restlet/oauth/OAuthAuthenticator.java
new file mode 100644
index 0000000..c33bb5a
--- /dev/null
+++ b/src/main/java/com/p4square/restlet/oauth/OAuthAuthenticator.java
@@ -0,0 +1,95 @@
+/*
+ * 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/main/java/com/p4square/restlet/oauth/OAuthAuthenticatorHelper.java b/src/main/java/com/p4square/restlet/oauth/OAuthAuthenticatorHelper.java
new file mode 100644
index 0000000..76ff044
--- /dev/null
+++ b/src/main/java/com/p4square/restlet/oauth/OAuthAuthenticatorHelper.java
@@ -0,0 +1,177 @@
+/*
+ * 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/main/java/com/p4square/restlet/oauth/OAuthException.java b/src/main/java/com/p4square/restlet/oauth/OAuthException.java
new file mode 100644
index 0000000..dd326d3
--- /dev/null
+++ b/src/main/java/com/p4square/restlet/oauth/OAuthException.java
@@ -0,0 +1,25 @@
+/*
+ * 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/main/java/com/p4square/restlet/oauth/OAuthHelper.java b/src/main/java/com/p4square/restlet/oauth/OAuthHelper.java
new file mode 100644
index 0000000..67dd238
--- /dev/null
+++ b/src/main/java/com/p4square/restlet/oauth/OAuthHelper.java
@@ -0,0 +1,149 @@
+/*
+ * 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/main/java/com/p4square/restlet/oauth/OAuthUser.java b/src/main/java/com/p4square/restlet/oauth/OAuthUser.java
new file mode 100644
index 0000000..11dbac1
--- /dev/null
+++ b/src/main/java/com/p4square/restlet/oauth/OAuthUser.java
@@ -0,0 +1,50 @@
+/*
+ * 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/main/java/com/p4square/restlet/oauth/Token.java b/src/main/java/com/p4square/restlet/oauth/Token.java
new file mode 100644
index 0000000..51a9087
--- /dev/null
+++ b/src/main/java/com/p4square/restlet/oauth/Token.java
@@ -0,0 +1,52 @@
+/*
+ * 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);
+ }
+}