| author | Samuel Padgett | 2012-01-26 15:30:16 (EST) |
|---|---|---|
| committer | Michael Fiedler | 2012-01-27 09:26:05 (EST) |
| commit | 4dcf25385c224374d4615518878731965b2cb745 (patch) (side-by-side diff) | |
| tree | fa244d95c18973fa34b8f832a00f91846342ca1d | |
| parent | 6e83cb30f8c37ba728bd8722953267917c3f6d36 (diff) | |
| download | org.eclipse.lyo.server-4dcf25385c224374d4615518878731965b2cb745.zip org.eclipse.lyo.server-4dcf25385c224374d4615518878731965b2cb745.tar.gz org.eclipse.lyo.server-4dcf25385c224374d4615518878731965b2cb745.tar.bz2 | |
Bug 369863 - Add OAuth 1.0a support to the OAuth framework
The first version of the framework only supported OAuth 1.0
authentication flows. We should add 1.0a support (and add a warning to
the login page if consumers are using 1.0). The OAuth version can be
negotiated at runtime depending on whether the consumer passes an
oauth_callback parameter when asking for a request token.
8 files changed, 357 insertions, 65 deletions
diff --git a/org.eclipse.lyo.server.oauth.core/src/main/java/org/eclipse/lyo/server/oauth/core/OAuthConfiguration.java b/org.eclipse.lyo.server.oauth.core/src/main/java/org/eclipse/lyo/server/oauth/core/OAuthConfiguration.java index 1f59bb0..8ead740 100644 --- a/org.eclipse.lyo.server.oauth.core/src/main/java/org/eclipse/lyo/server/oauth/core/OAuthConfiguration.java +++ b/org.eclipse.lyo.server.oauth.core/src/main/java/org/eclipse/lyo/server/oauth/core/OAuthConfiguration.java @@ -37,6 +37,7 @@ public class OAuthConfiguration { private TokenStrategy tokenStrategy; private ConsumerStore consumerStore = null; private Authentication authentication = null; + private boolean v1_0Allowed = true; private static final OAuthConfiguration instance = new OAuthConfiguration(); @@ -131,4 +132,26 @@ public class OAuthConfiguration { public void setAuthentication(Authentication authentication) { this.authentication = authentication; } + + /** + * Is OAuth version 1.0 allowed, or do we require 1.0a? + * + * @return true if version 1.0 is allowed + * @see <a href="http://oauth.net/advisories/2009-1/">OAuth Security Advisory: 2009.1</a> + */ + public boolean isV1_0Allowed() { + return v1_0Allowed; + } + + /** + * Sets if we allow OAuth 1.0. + * + * @param allowed + * true to allow OAuth version 1.0 requests or false to require + * OAuth version 1.0a + * @see <a href="http://oauth.net/advisories/2009-1/">OAuth Security Advisory: 2009.1</a> + */ + public void setV1_0Allowed(boolean allowed) { + this.v1_0Allowed = allowed; + } } diff --git a/org.eclipse.lyo.server.oauth.core/src/main/java/org/eclipse/lyo/server/oauth/core/OAuthRequest.java b/org.eclipse.lyo.server.oauth.core/src/main/java/org/eclipse/lyo/server/oauth/core/OAuthRequest.java index 92ae6ec..ad8876d 100644 --- a/org.eclipse.lyo.server.oauth.core/src/main/java/org/eclipse/lyo/server/oauth/core/OAuthRequest.java +++ b/org.eclipse.lyo.server.oauth.core/src/main/java/org/eclipse/lyo/server/oauth/core/OAuthRequest.java @@ -59,7 +59,7 @@ public class OAuthRequest { private OAuthAccessor accessor; public OAuthRequest(HttpServletRequest request) - throws OAuthProblemException, IOException { + throws OAuthException, IOException { this.httpRequest = request; this.message = OAuthServlet.getMessage(httpRequest, null); diff --git a/org.eclipse.lyo.server.oauth.core/src/main/java/org/eclipse/lyo/server/oauth/core/consumer/LyoOAuthConsumer.java b/org.eclipse.lyo.server.oauth.core/src/main/java/org/eclipse/lyo/server/oauth/core/consumer/LyoOAuthConsumer.java index f61a3b0..3e45bf4 100644 --- a/org.eclipse.lyo.server.oauth.core/src/main/java/org/eclipse/lyo/server/oauth/core/consumer/LyoOAuthConsumer.java +++ b/org.eclipse.lyo.server.oauth.core/src/main/java/org/eclipse/lyo/server/oauth/core/consumer/LyoOAuthConsumer.java @@ -26,9 +26,18 @@ import net.oauth.OAuthServiceProvider; public class LyoOAuthConsumer extends OAuthConsumer { private static final long serialVersionUID = 7634987410903334464L; + public enum OAuthVersion { OAUTH_1_0, OAUTH_1_0A }; + private String name; private boolean trusted = false; + /* + * Assume 1.0 until we learn otherwise. This can be determined if the + * consumer passes an oauth_callback parameter when asking for a request + * token. + */ + private OAuthVersion oAuthVersion = OAuthVersion.OAUTH_1_0; + public LyoOAuthConsumer(String consumerKey, String consumerSecret) { super(null, consumerKey, consumerSecret, null); } @@ -85,4 +94,25 @@ public class LyoOAuthConsumer extends OAuthConsumer { public void setTrusted(boolean trusted) { this.trusted = trusted; } + + /** + * Gets the OAuth version that the consumer supports. + * + * @return the OAuth version + */ + public OAuthVersion getOAuthVersion() { + return oAuthVersion; + } + + /** + * Sets the OAuth version that the consumer supports. This should be set by + * the OAuth service depending on whether the consumer specified an + * oauth_callback parameter when asking for a request token. + * + * @param oAuthVersion + * the OAuth version + */ + public void setOAuthVersion(OAuthVersion oAuthVersion) { + this.oAuthVersion = oAuthVersion; + } } diff --git a/org.eclipse.lyo.server.oauth.core/src/main/java/org/eclipse/lyo/server/oauth/core/token/SimpleTokenStrategy.java b/org.eclipse.lyo.server.oauth.core/src/main/java/org/eclipse/lyo/server/oauth/core/token/SimpleTokenStrategy.java index a20d7a5..bfd3a07 100644 --- a/org.eclipse.lyo.server.oauth.core/src/main/java/org/eclipse/lyo/server/oauth/core/token/SimpleTokenStrategy.java +++ b/org.eclipse.lyo.server.oauth.core/src/main/java/org/eclipse/lyo/server/oauth/core/token/SimpleTokenStrategy.java @@ -32,7 +32,8 @@ import net.oauth.OAuthProblemException; /** * A simple strategy for generating and validating tokens. Generates random * tokens and stores them in memory. Tokens are only good for the life of the - * process. + * process. Least recently used tokens are invalidated when cached limits are + * reached. * * @author Samuel Padgett <spadgett@us.ibm.com> */ @@ -40,27 +41,61 @@ public class SimpleTokenStrategy implements TokenStrategy { private final static int REQUEST_TOKEN_MAX_ENTIRES = 500; private final static int ACCESS_TOKEN_MAX_ENTRIES = 5000; + /** + * Holds information associated with a request token such as the callback + * URL and OAuth verification code. + * + * @author Samuel Padgett <spadgett@us.ibm.com> + */ protected class RequestTokenData { private String consumerKey; private boolean authorized; + private String callback; + private String verificationCode; public RequestTokenData(String consumerKey) { this.consumerKey = consumerKey; this.authorized = false; + this.callback = null; + } + + public RequestTokenData(String consumerKey, String callback) { + this.consumerKey = consumerKey; + this.authorized = false; + this.callback = callback; } public String getConsumerKey() { return consumerKey; } + public void setConsumerKey(String consumerKey) { this.consumerKey = consumerKey; } + public boolean isAuthorized() { return authorized; } + public void setAuthorized(boolean authorized) { this.authorized = authorized; } + + public String getCallback() { + return callback; + } + + public void setCallback(String callback) { + this.callback = callback; + } + + public String getVerificationCode() { + return verificationCode; + } + + public void setVerificationCode(String verificationCode) { + this.verificationCode = verificationCode; + } } // key is request token string, value is RequestTokenData @@ -72,10 +107,25 @@ public class SimpleTokenStrategy implements TokenStrategy { // key is token, value is token secret private Map<String, String> tokenSecrets; + /** + * Constructs a SimpleTokenStrategy using the defaults for cache limits on request and access tokens. + * + * @see SimpleTokenStrategy#SimpleTokenStrategy(int, int) + */ public SimpleTokenStrategy() { this(REQUEST_TOKEN_MAX_ENTIRES, ACCESS_TOKEN_MAX_ENTRIES); } + /** + * Constructs a SimpleTokenStrategy with cache limits on the number of + * request and access tokens. Least recently used tokens are invalidated + * when cache limits are reached. + * + * @param requestTokenMaxCount + * the maximum number of request tokens to track + * @param accessTokenMaxCount + * the maximum number of access tokens to track + */ public SimpleTokenStrategy(int requestTokenMaxCount, int accessTokenMaxCount) { requestTokens = new LRUCache<String, RequestTokenData>(requestTokenMaxCount); accessTokens = new LRUCache<String, String>(accessTokenMaxCount); @@ -84,13 +134,16 @@ public class SimpleTokenStrategy implements TokenStrategy { } @Override - public void generateRequestToken(OAuthRequest oAuthRequest) { + public void generateRequestToken(OAuthRequest oAuthRequest) + throws IOException { OAuthAccessor accessor = oAuthRequest.getAccessor(); accessor.requestToken = generateTokenString(); accessor.tokenSecret = generateTokenString(); + String callback = oAuthRequest.getMessage() + .getParameter(OAuth.OAUTH_CALLBACK); synchronized (requestTokens) { requestTokens.put(accessor.requestToken, new RequestTokenData( - accessor.consumer.consumerKey)); + accessor.consumer.consumerKey, callback)); } synchronized (tokenSecrets) { tokenSecrets.put(accessor.requestToken, accessor.tokenSecret); @@ -100,38 +153,50 @@ public class SimpleTokenStrategy implements TokenStrategy { @Override public String validateRequestToken(HttpServletRequest httpRequest, OAuthMessage message) throws OAuthException, IOException { - synchronized (requestTokens) { - RequestTokenData tokenData = requestTokens.get(message.getToken()); - if (tokenData == null) { - throw new OAuthProblemException(OAuth.Problems.TOKEN_REJECTED); - } + return getRequestTokenData(message.getToken()).getConsumerKey(); + } - return tokenData.getConsumerKey(); - } + @Override + public String getCallback(HttpServletRequest httpRequest, + String requestToken) throws OAuthProblemException { + return getRequestTokenData(requestToken).getCallback(); } @Override public void markRequestTokenAuthorized(HttpServletRequest httpRequest, String requestToken) throws OAuthProblemException { - synchronized (requestTokens) { - RequestTokenData tokenData = requestTokens.get(requestToken); - if (tokenData == null) { - throw new OAuthProblemException(OAuth.Problems.TOKEN_REJECTED); - } - tokenData.setAuthorized(true); - } + getRequestTokenData(requestToken).setAuthorized(true); } @Override public boolean isRequestTokenAuthorized(HttpServletRequest httpRequest, - String requestToken) { - synchronized (requestTokens) { - RequestTokenData tokenData = requestTokens.get(requestToken); - if (tokenData == null) { - return false; - } + String requestToken) throws OAuthProblemException { + return getRequestTokenData(requestToken).isAuthorized(); + } + + @Override + public String generateVerificationCode(HttpServletRequest httpRequest, + String requestToken) throws OAuthProblemException { + String verificationCode = generateTokenString(); + getRequestTokenData(requestToken).setVerificationCode(verificationCode); + + return verificationCode; + } - return tokenData.isAuthorized(); + @Override + public void validateVerificationCode(OAuthRequest oAuthRequest) + throws OAuthException, IOException { + String verificationCode = oAuthRequest.getMessage().getParameter( + OAuth.OAUTH_VERIFIER); + if (verificationCode == null) { + throw new OAuthProblemException( + OAuth.Problems.OAUTH_PARAMETERS_ABSENT); + } + + RequestTokenData tokenData = getRequestTokenData(oAuthRequest); + if (!verificationCode.equals(tokenData.getVerificationCode())) { + throw new OAuthProblemException( + OAuth.Problems.OAUTH_PARAMETERS_REJECTED); } } @@ -153,7 +218,7 @@ public class SimpleTokenStrategy implements TokenStrategy { // Generate a new access token. accessor.accessToken = generateTokenString(); - synchronized (requestTokens) { + synchronized (accessTokens) { accessTokens.put(accessor.accessToken, accessor.consumer.consumerKey); } @@ -204,4 +269,40 @@ public class SimpleTokenStrategy implements TokenStrategy { protected String generateTokenString() { return UUID.randomUUID().toString(); } + + /** + * Gets the request token data from this OAuth request. + * + * @param oAuthRequest + * the OAuth request + * @return the request token data + * @throws OAuthProblemException + * if the request token is invalid + * @throws IOException + * on reading OAuth parameters + */ + protected RequestTokenData getRequestTokenData(OAuthRequest oAuthRequest) + throws OAuthProblemException, IOException { + return getRequestTokenData(oAuthRequest.getMessage().getToken()); + } + + /** + * Gets the request token data for this request token. + * + * @param requestToken + * the request token string + * @return the request token data + * @throws OAuthProblemException + * if the request token is invalid + */ + protected RequestTokenData getRequestTokenData(String requestToken) + throws OAuthProblemException { + synchronized (requestTokens) { + RequestTokenData tokenData = requestTokens.get(requestToken); + if (tokenData == null) { + throw new OAuthProblemException(OAuth.Problems.TOKEN_REJECTED); + } + return tokenData; + } + } } diff --git a/org.eclipse.lyo.server.oauth.core/src/main/java/org/eclipse/lyo/server/oauth/core/token/TokenStrategy.java b/org.eclipse.lyo.server.oauth.core/src/main/java/org/eclipse/lyo/server/oauth/core/token/TokenStrategy.java index cdd3ec5..3caf571 100644 --- a/org.eclipse.lyo.server.oauth.core/src/main/java/org/eclipse/lyo/server/oauth/core/token/TokenStrategy.java +++ b/org.eclipse.lyo.server.oauth.core/src/main/java/org/eclipse/lyo/server/oauth/core/token/TokenStrategy.java @@ -22,7 +22,6 @@ import javax.servlet.http.HttpServletRequest; import net.oauth.OAuthAccessor; import net.oauth.OAuthException; import net.oauth.OAuthMessage; -import net.oauth.OAuthProblemException; import org.eclipse.lyo.server.oauth.core.OAuthRequest; @@ -40,9 +39,13 @@ public interface TokenStrategy { * * @param oAuthRequest * the OAuth request + * @throws IOException + * on errors reading from the request message + * @throws OAuthException + * on OAuth problems * @see OAuthRequest#getAccessor() */ - public void generateRequestToken(OAuthRequest oAuthRequest); + public void generateRequestToken(OAuthRequest oAuthRequest) throws OAuthException, IOException; /** * Validates that the request token is valid, throwing an exception if not. @@ -67,6 +70,23 @@ public interface TokenStrategy { OAuthMessage message) throws OAuthException, IOException; /** + * Gets the OAuth callback associated with this consumer for OAuth 1.0a + * authentication flows. Returns null if the consumer did not specify a + * callback when asking for a request token. + * + * @param httpRequest + * the HTTP request + * @param requestToken + * the request token + * @return the callback URL + * + * @throws OAuthException + * on OAuth problems + */ + public String getCallback(HttpServletRequest httpRequest, + String requestToken) throws OAuthException; + + /** * Indicates that a user has typed in a valid ID and password, and that the * request token can now be exchanged for an access token. * @@ -74,13 +94,13 @@ public interface TokenStrategy { * the servlet request * @param requestToken * the request token string - * @throws OAuthProblemException + * @throws OAuthException * if the token is not valid * * @see #isRequestTokenAuthorized(HttpServletRequest, String) */ public void markRequestTokenAuthorized(HttpServletRequest httpRequest, - String requestToken) throws OAuthProblemException; + String requestToken) throws OAuthException; /** * Checks with the request token has been authorized by the end user. @@ -91,11 +111,44 @@ public interface TokenStrategy { * the request token * @return answers if the request token is authorized and can be exchanged * for an access token + * @throws OAuthException + * on OAuth problems * * @see #markRequestTokenAuthorized(HttpServletRequest, OAuthAccessor) */ public boolean isRequestTokenAuthorized(HttpServletRequest httpRequest, - String requestToken); + String requestToken) throws OAuthException; + + /** + * Generates an "unguessable" OAuth verification code. The consumer must + * supply the verification code when exchanging the request token for an + * access token. This is specific to OAuth 1.0a. + * + * @param httpRequest + * the HTTP request + * @param requestToken + * the request token + * @return a verification code + * @throws OAuthException + * on OAuth problems (e.g., the request token is invalid) + */ + public String generateVerificationCode(HttpServletRequest httpRequest, + String requestToken) throws OAuthException; + + /** + * Validates that the verification code is recognized and associated with + * the request token. This must be called before the request token is + * exchanged for the access token in an OAuth 1.0a authentication flow. + * + * @param oAuthRequest + * the OAuth request + * @throws OAuthException + * on OAuth problems (e.g., the request token is invalid) + * @throws IOException + * on I/O errors + */ + public void validateVerificationCode(OAuthRequest oAuthRequest) + throws OAuthException, IOException; /** * Generates an access token and token secret and sets it in the accessor in @@ -103,14 +156,14 @@ public interface TokenStrategy { * * @param oAuthRequest * the OAuth request - * @throws OAuthProblemException + * @throws OAuthException * on OAuth problems * @throws IOException * on I/O errors * @see OAuthRequest#getAccessor() */ public void generateAccessToken(OAuthRequest oAuthRequest) - throws OAuthProblemException, IOException; + throws OAuthException, IOException; /** * Validates that the access token is valid, throwing an exception if not. @@ -134,9 +187,9 @@ public interface TokenStrategy { * the token string, either a request token or access token * * @return the token secret - * @throws OAuthProblemException + * @throws OAuthException * on OAuth problems (e.g., the token is invalid) */ public String getTokenSecret(HttpServletRequest httpRequest, String token) - throws OAuthProblemException; + throws OAuthException; } diff --git a/org.eclipse.lyo.server.oauth.webapp/src/main/java/org/eclipse/lyo/server/oauth/webapp/services/OAuthService.java b/org.eclipse.lyo.server.oauth.webapp/src/main/java/org/eclipse/lyo/server/oauth/webapp/services/OAuthService.java index 982bc6e..e1f7c59 100644 --- a/org.eclipse.lyo.server.oauth.webapp/src/main/java/org/eclipse/lyo/server/oauth/webapp/services/OAuthService.java +++ b/org.eclipse.lyo.server.oauth.webapp/src/main/java/org/eclipse/lyo/server/oauth/webapp/services/OAuthService.java @@ -17,6 +17,7 @@ package org.eclipse.lyo.server.oauth.webapp.services; import java.io.IOException; import java.net.URISyntaxException; +import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -33,6 +34,7 @@ import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.UriBuilder; import net.oauth.OAuth; +import net.oauth.OAuth.Parameter; import net.oauth.OAuthAccessor; import net.oauth.OAuthException; import net.oauth.OAuthMessage; @@ -65,6 +67,12 @@ public class OAuthService { @Context protected HttpServletResponse httpResponse; + @GET + @Path("/requestToken") + public Response doGetRequestToken() throws IOException, ServletException { + return doPostRequestToken(); + } + /** * Responds with a request token and token secret. * @@ -76,21 +84,49 @@ public class OAuthService { */ @POST @Path("/requestToken") - public Response getRequestToken() throws IOException, ServletException { + public Response doPostRequestToken() throws IOException, ServletException { try { - OAuthRequest oAuthRequest = validateRequest(); - OAuthConfiguration.getInstance() - .getTokenStrategy().generateRequestToken(oAuthRequest); - OAuthAccessor accessor = oAuthRequest.getAccessor(); - return respondWithToken(accessor.requestToken, accessor.tokenSecret); + // Generate the token. + OAuthConfiguration.getInstance().getTokenStrategy() + .generateRequestToken(oAuthRequest); + // Check for OAuth 1.0a authentication. + boolean callbackConfirmed = confirmCallback(oAuthRequest); + + // Respond to the consumer. + OAuthAccessor accessor = oAuthRequest.getAccessor(); + return respondWithToken(accessor.requestToken, + accessor.tokenSecret, callbackConfirmed); } catch (OAuthException e) { return respondWithOAuthProblem(e); } } + protected boolean confirmCallback(OAuthRequest oAuthRequest) + throws OAuthException { + boolean callbackConfirmed = OAuthConfiguration + .getInstance() + .getTokenStrategy() + .getCallback(httpRequest, + oAuthRequest.getAccessor().requestToken) != null; + if (callbackConfirmed) { + oAuthRequest.getConsumer().setOAuthVersion( + LyoOAuthConsumer.OAuthVersion.OAUTH_1_0A); + } else { + if (!OAuthConfiguration.getInstance().isV1_0Allowed()) { + throw new OAuthProblemException( + OAuth.Problems.OAUTH_PARAMETERS_ABSENT); + } + + oAuthRequest.getConsumer().setOAuthVersion( + LyoOAuthConsumer.OAuthVersion.OAUTH_1_0); + } + + return callbackConfirmed; + } + /* * TODO: Give providers a way to show their own branded login page. */ @@ -127,6 +163,10 @@ public class OAuthService { httpRequest.setAttribute("consumerName", consumer.getName()); httpRequest.setAttribute("callback", getCallbackURL(message, consumer)); + boolean callbackConfirmed = + consumer.getOAuthVersion() == LyoOAuthConsumer.OAuthVersion.OAUTH_1_0A; + httpRequest.setAttribute("callbackConfirmed", new Boolean( + callbackConfirmed)); Authentication auth = config.getAuthentication(); if (auth == null) { @@ -150,20 +190,40 @@ public class OAuthService { } private String getCallbackURL(OAuthMessage message, - LyoOAuthConsumer consumer) throws IOException { - // Find the callback URL. - String callback = message.getParameter(OAuth.OAUTH_CALLBACK); - if (callback == null) { - callback = consumer.callbackURL; + LyoOAuthConsumer consumer) throws IOException, OAuthException { + String callback = null; + switch (consumer.getOAuthVersion()) { + case OAUTH_1_0: + if (!OAuthConfiguration.getInstance().isV1_0Allowed()) { + throw new OAuthProblemException(OAuth.Problems.VERSION_REJECTED); + } + + // If this is OAuth 1.0, the callback should be a request parameter. + callback = message.getParameter(OAuth.OAUTH_CALLBACK); + break; + + case OAUTH_1_0A: + // If this is OAuth 1.0a, the callback was passed when the consumer + // asked for a request token. + String requestToken = message.getToken(); + callback = OAuthConfiguration.getInstance().getTokenStrategy() + .getCallback(httpRequest, requestToken); } if (callback == null) { return null; } - return UriBuilder.fromUri(callback) - .queryParam(OAuth.OAUTH_TOKEN, message.getToken()).build() - .toString(); + UriBuilder uriBuilder = UriBuilder.fromUri(callback) + .queryParam(OAuth.OAUTH_TOKEN, message.getToken()); + if (consumer.getOAuthVersion() == LyoOAuthConsumer.OAuthVersion.OAUTH_1_0A) { + String verificationCode = OAuthConfiguration.getInstance() + .getTokenStrategy() + .generateVerificationCode(httpRequest, message.getToken()); + uriBuilder.queryParam(OAuth.OAUTH_VERIFIER, verificationCode); + } + + return uriBuilder.build().toString(); } /** @@ -194,7 +254,7 @@ public class OAuthService { try { OAuthConfiguration.getInstance().getTokenStrategy() .markRequestTokenAuthorized(httpRequest, requestToken); - } catch (OAuthProblemException e) { + } catch (OAuthException e) { return Response.status(Status.CONFLICT) .entity("Request token invalid.") .type(MediaType.TEXT_PLAIN).build(); @@ -203,6 +263,12 @@ public class OAuthService { return Response.noContent().build(); } + @GET + @Path("/accessToken") + public Response doGetAccessToken() throws IOException, ServletException { + return doPostAccessToken(); + } + /** * Responds with an access token and token secret for valid OAuth requests. * The request must be signed and the request token valid. @@ -215,15 +281,22 @@ public class OAuthService { */ @POST @Path("/accessToken") - public Response getAccessToken() throws IOException, ServletException { + public Response doPostAccessToken() throws IOException, ServletException { try { - - // Validate the request is signed and check that the request token is valid. + // Validate the request is signed and check that the request token + // is valid. OAuthRequest oAuthRequest = validateRequest(); - TokenStrategy strategy = OAuthConfiguration.getInstance() - .getTokenStrategy(); + OAuthConfiguration config = OAuthConfiguration.getInstance(); + TokenStrategy strategy = config.getTokenStrategy(); strategy.validateRequestToken(httpRequest, oAuthRequest.getMessage()); + + // The verification code MUST be passed in the request if this is + // OAuth 1.0a. + if (!config.isV1_0Allowed() + || oAuthRequest.getConsumer().getOAuthVersion() == LyoOAuthConsumer.OAuthVersion.OAUTH_1_0A) { + strategy.validateVerificationCode(oAuthRequest); + } // Generate a new access token for this accessor. strategy.generateAccessToken(oAuthRequest); @@ -231,7 +304,6 @@ public class OAuthService { // Send the new token and secret back to the consumer. OAuthAccessor accessor = oAuthRequest.getAccessor(); return respondWithToken(accessor.accessToken, accessor.tokenSecret); - } catch (OAuthException e) { return respondWithOAuthProblem(e); } @@ -264,9 +336,19 @@ public class OAuthService { protected Response respondWithToken(String token, String tokenSecret) throws IOException { - String responseBody = OAuth.formEncode(OAuth.newList(OAuth.OAUTH_TOKEN, - token, OAuth.OAUTH_TOKEN_SECRET, tokenSecret)); + return respondWithToken(token, tokenSecret, false); + } + protected Response respondWithToken(String token, String tokenSecret, + boolean callbackConfirmed) throws IOException { + List<Parameter> oAuthParameters = OAuth.newList(OAuth.OAUTH_TOKEN, + token, OAuth.OAUTH_TOKEN_SECRET, tokenSecret); + if (callbackConfirmed) { + oAuthParameters.add(new Parameter(OAuth.OAUTH_CALLBACK_CONFIRMED, + "true")); + } + + String responseBody = OAuth.formEncode(oAuthParameters); return Response.ok(responseBody) .type(MediaType.APPLICATION_FORM_URLENCODED).build(); } diff --git a/org.eclipse.lyo.server.oauth.webapp/src/main/webapp/oauth/login.jsp b/org.eclipse.lyo.server.oauth.webapp/src/main/webapp/oauth/login.jsp index 00524ae..91fdc4e 100644 --- a/org.eclipse.lyo.server.oauth.webapp/src/main/webapp/oauth/login.jsp +++ b/org.eclipse.lyo.server.oauth.webapp/src/main/webapp/oauth/login.jsp @@ -24,13 +24,20 @@ <%-- Creative Commons Image: http://openclipart.org/detail/211/shiny-key-by-tiothy --%> <img src="<%=request.getContextPath()%>/oauth/key.png" style="float: right;"> <h1>Connect to <c:out value="${applicationName}">Your Application</c:out></h1> - + <form id="loginForm"> - <div class="message"><b><c:out value="${consumerName}">Another application</c:out></b> + <div><b><c:out value="${consumerName}">Another application</c:out></b> is requesting access to your <b><c:out value="${applicationName}">application</c:out></b> data. Enter your username and password to continue or click cancel to exit.</div> - + + <c:if test="${not callbackConfirmed}"> + <p> + Only continue if you initiated this request directly from + <c:out value="${consumerName}">the consumer's website</c:out>. + </p> + </c:if> + <div id="error" class="error" style="display: hidden;"></div> <input type="hidden" name="requestToken" value="<c:out value="${requestToken}"/>"> <input type="hidden" id="callback" value="<c:out value="${callback}"/>"> diff --git a/org.eclipse.lyo.server.oauth.webapp/src/main/webapp/oauth/theme.css b/org.eclipse.lyo.server.oauth.webapp/src/main/webapp/oauth/theme.css index 77bf42a..aa2c16e 100644 --- a/org.eclipse.lyo.server.oauth.webapp/src/main/webapp/oauth/theme.css +++ b/org.eclipse.lyo.server.oauth.webapp/src/main/webapp/oauth/theme.css @@ -8,10 +8,6 @@ label { text-align: right; } -.message { - font-size: 120t; -} - .textField { width: 400px; margin-bottom: 1em; |

