summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamuel Padgett2012-01-19 13:12:54 (EST)
committer Michael Fiedler2012-01-20 08:53:58 (EST)
commitdd576f91a1b27b827c170629b08497ae37bb8f83 (patch)
tree581a29a4dd36a0f140c1ef93f64e080dd38b95b7
parent25abdec954b4e96614566e9a6bbf29fd9b1b2770 (diff)
downloadorg.eclipse.lyo.server-dd576f91a1b27b827c170629b08497ae37bb8f83.zip
org.eclipse.lyo.server-dd576f91a1b27b827c170629b08497ae37bb8f83.tar.gz
org.eclipse.lyo.server-dd576f91a1b27b827c170629b08497ae37bb8f83.tar.bz2
Bug 368872 - OAuth Framework - Fix authorization flow
The framework wasn't handling authorization properly. It assumed the consumer key would be passed to the authorization page, which isn't always the case. Also it was not appending the oauth_token parameter to the callback URL.
-rw-r--r--org.eclipse.lyo.server.oauth.core/src/main/java/org/eclipse/lyo/server/oauth/core/OAuthRequest.java4
-rw-r--r--org.eclipse.lyo.server.oauth.core/src/main/java/org/eclipse/lyo/server/oauth/core/token/SimpleTokenStrategy.java63
-rw-r--r--org.eclipse.lyo.server.oauth.core/src/main/java/org/eclipse/lyo/server/oauth/core/token/TokenStrategy.java40
-rw-r--r--org.eclipse.lyo.server.oauth.webapp/src/main/java/org/eclipse/lyo/server/oauth/webapp/services/OAuthService.java68
-rw-r--r--org.eclipse.lyo.server.oauth.webapp/src/main/webapp/oauth/key.pngbin0 -> 6203 bytes
-rw-r--r--org.eclipse.lyo.server.oauth.webapp/src/main/webapp/oauth/login.js3
-rw-r--r--org.eclipse.lyo.server.oauth.webapp/src/main/webapp/oauth/login.jsp8
7 files changed, 137 insertions, 49 deletions
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 0504500..92ae6ec 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
@@ -57,7 +57,7 @@ public class OAuthRequest {
private HttpServletRequest httpRequest;
private OAuthMessage message;
private OAuthAccessor accessor;
-
+
public OAuthRequest(HttpServletRequest request)
throws OAuthProblemException, IOException {
this.httpRequest = request;
@@ -79,7 +79,7 @@ public class OAuthRequest {
.getTokenStrategy().getTokenSecret(this.httpRequest, token);
}
}
-
+
public HttpServletRequest getHttpRequest() {
return httpRequest;
}
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 93064c3..a20d7a5 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
@@ -26,6 +26,7 @@ import org.eclipse.lyo.server.oauth.core.OAuthRequest;
import net.oauth.OAuth;
import net.oauth.OAuthAccessor;
import net.oauth.OAuthException;
+import net.oauth.OAuthMessage;
import net.oauth.OAuthProblemException;
/**
@@ -39,9 +40,31 @@ public class SimpleTokenStrategy implements TokenStrategy {
private final static int REQUEST_TOKEN_MAX_ENTIRES = 500;
private final static int ACCESS_TOKEN_MAX_ENTRIES = 5000;
- // key is request token, value is boolean indicating if the token is
- // authorized
- private Map<String, Boolean> requestTokens;
+ protected class RequestTokenData {
+ private String consumerKey;
+ private boolean authorized;
+
+ public RequestTokenData(String consumerKey) {
+ this.consumerKey = consumerKey;
+ this.authorized = false;
+ }
+
+ 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;
+ }
+ }
+
+ // key is request token string, value is RequestTokenData
+ private Map<String, RequestTokenData> requestTokens;
// key is access token, value is consumer key
private Map<String, String> accessTokens;
@@ -54,7 +77,7 @@ public class SimpleTokenStrategy implements TokenStrategy {
}
public SimpleTokenStrategy(int requestTokenMaxCount, int accessTokenMaxCount) {
- requestTokens = new LRUCache<String, Boolean>(requestTokenMaxCount);
+ requestTokens = new LRUCache<String, RequestTokenData>(requestTokenMaxCount);
accessTokens = new LRUCache<String, String>(accessTokenMaxCount);
tokenSecrets = new LRUCache<String, String>(requestTokenMaxCount
+ accessTokenMaxCount);
@@ -66,7 +89,8 @@ public class SimpleTokenStrategy implements TokenStrategy {
accessor.requestToken = generateTokenString();
accessor.tokenSecret = generateTokenString();
synchronized (requestTokens) {
- requestTokens.put(accessor.requestToken, Boolean.FALSE); // not yet authorized
+ requestTokens.put(accessor.requestToken, new RequestTokenData(
+ accessor.consumer.consumerKey));
}
synchronized (tokenSecrets) {
tokenSecrets.put(accessor.requestToken, accessor.tokenSecret);
@@ -74,20 +98,27 @@ public class SimpleTokenStrategy implements TokenStrategy {
}
@Override
- public String validateRequestToken(OAuthRequest oAuthRequest) throws OAuthException, IOException {
- String requestToken = oAuthRequest.getMessage().getToken();
- if (!requestTokens.containsKey(requestToken)) {
- throw new OAuthProblemException(OAuth.Problems.TOKEN_REJECTED);
+ 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 tokenData.getConsumerKey();
}
-
- return requestToken;
}
@Override
public void markRequestTokenAuthorized(HttpServletRequest httpRequest,
- String requestToken) {
+ String requestToken) throws OAuthProblemException {
synchronized (requestTokens) {
- requestTokens.put(requestToken, Boolean.TRUE);
+ RequestTokenData tokenData = requestTokens.get(requestToken);
+ if (tokenData == null) {
+ throw new OAuthProblemException(OAuth.Problems.TOKEN_REJECTED);
+ }
+ tokenData.setAuthorized(true);
}
}
@@ -95,12 +126,12 @@ public class SimpleTokenStrategy implements TokenStrategy {
public boolean isRequestTokenAuthorized(HttpServletRequest httpRequest,
String requestToken) {
synchronized (requestTokens) {
- Boolean authorized = requestTokens.get(requestToken);
- if (authorized == null) {
+ RequestTokenData tokenData = requestTokens.get(requestToken);
+ if (tokenData == null) {
return false;
}
- return authorized.booleanValue();
+ return tokenData.isAuthorized();
}
}
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 3529640..cdd3ec5 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
@@ -21,6 +21,7 @@ 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;
@@ -34,29 +35,36 @@ import org.eclipse.lyo.server.oauth.core.OAuthRequest;
*/
public interface TokenStrategy {
/**
- * Generates a request token and token secret and sets it in the accessor.
+ * Generates a request token and token secret and sets it in the accessor in
+ * the {@link OAuthRequest}.
*
* @param oAuthRequest
* the OAuth request
+ * @see OAuthRequest#getAccessor()
*/
public void generateRequestToken(OAuthRequest oAuthRequest);
/**
- * Validates that the request token and token secret are valid, throwing an
- * exception if not.
+ * Validates that the request token is valid, throwing an exception if not.
+ * Returns the consumer key so that the authorization page can display
+ * information about the consumer. The token strategy must track what
+ * request tokens belong to what consumers since the consumer key is not
+ * guaranteed to be in the request.
*
- * @param oAuthRequest
- * the OAuth request
+ * @param httpRequest
+ * the HTTP request
+ * @param message
+ * the OAuth message
*
- * @return the request token
+ * @return the consumer key associated with the request
*
* @throws OAuthException
* if the tokens are not valid
* @throws IOException
* on I/O errors
*/
- public String validateRequestToken(OAuthRequest oAuthRequest)
- throws OAuthException, IOException;
+ public String validateRequestToken(HttpServletRequest httpRequest,
+ OAuthMessage message) throws OAuthException, IOException;
/**
* Indicates that a user has typed in a valid ID and password, and that the
@@ -66,9 +74,13 @@ public interface TokenStrategy {
* the servlet request
* @param requestToken
* the request token string
+ * @throws OAuthProblemException
+ * if the token is not valid
+ *
+ * @see #isRequestTokenAuthorized(HttpServletRequest, String)
*/
public void markRequestTokenAuthorized(HttpServletRequest httpRequest,
- String requestToken);
+ String requestToken) throws OAuthProblemException;
/**
* Checks with the request token has been authorized by the end user.
@@ -86,8 +98,8 @@ public interface TokenStrategy {
String requestToken);
/**
- * Generates an access token and token secret and sets it in the accessor.
- * Clears any request tokens set.
+ * Generates an access token and token secret and sets it in the accessor in
+ * the {@link OAuthRequest}. Clears any request tokens set.
*
* @param oAuthRequest
* the OAuth request
@@ -95,18 +107,18 @@ public interface TokenStrategy {
* on OAuth problems
* @throws IOException
* on I/O errors
+ * @see OAuthRequest#getAccessor()
*/
public void generateAccessToken(OAuthRequest oAuthRequest)
throws OAuthProblemException, IOException;
/**
- * Validates that the access token and token secret are valid, throwing an
- * exception if not.
+ * Validates that the access token is valid, throwing an exception if not.
*
* @param oAuthRequest
* the OAuth request
* @throws OAuthException
- * if the tokens are not valid
+ * if the token is invalid
* @throws IOException
* on I/O errors
*/
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 c380cc5..982bc6e 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
@@ -30,10 +30,13 @@ import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriBuilder;
import net.oauth.OAuth;
import net.oauth.OAuthAccessor;
import net.oauth.OAuthException;
+import net.oauth.OAuthMessage;
+import net.oauth.OAuthProblemException;
import net.oauth.OAuthValidator;
import net.oauth.server.OAuthServlet;
@@ -41,6 +44,8 @@ import org.eclipse.lyo.server.oauth.core.Authentication;
import org.eclipse.lyo.server.oauth.core.AuthenticationException;
import org.eclipse.lyo.server.oauth.core.OAuthConfiguration;
import org.eclipse.lyo.server.oauth.core.OAuthRequest;
+import org.eclipse.lyo.server.oauth.core.consumer.ConsumerRegistry;
+import org.eclipse.lyo.server.oauth.core.consumer.LyoOAuthConsumer;
import org.eclipse.lyo.server.oauth.core.token.TokenStrategy;
/**
@@ -103,18 +108,25 @@ public class OAuthService {
@Path("/authorize")
public Response authorize() throws ServletException, IOException {
try {
- // Check that the request is valid.
- OAuthRequest oAuthRequest = validateRequest();
- OAuthConfiguration config = OAuthConfiguration.getInstance();
- String requestToken = config.getTokenStrategy()
- .validateRequestToken(oAuthRequest);
+ /*
+ * Check that the request token is valid and determine what consumer
+ * it's for. The OAuth spec does not require that consumers pass the
+ * consumer key to the authorization page, so we must track this in
+ * the TokenStrategy implementation.
+ */
+ OAuthMessage message = OAuthServlet.getMessage(httpRequest, null);
+ OAuthConfiguration config = OAuthConfiguration.getInstance();
+ String consumerKey = config.getTokenStrategy()
+ .validateRequestToken(httpRequest, message);
+ LyoOAuthConsumer consumer = ConsumerRegistry.getInstance()
+ .getConsumer(consumerKey);
+
// Pass some data to the JSP.
- httpRequest.setAttribute("requestToken", requestToken);
- httpRequest.setAttribute("consumerName", oAuthRequest.getConsumer()
- .getName());
+ httpRequest.setAttribute("requestToken", message.getToken());
+ httpRequest.setAttribute("consumerName", consumer.getName());
httpRequest.setAttribute("callback",
- oAuthRequest.getConsumer().callbackURL);
+ getCallbackURL(message, consumer));
Authentication auth = config.getAuthentication();
if (auth == null) {
@@ -137,6 +149,23 @@ 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;
+ }
+
+ if (callback == null) {
+ return null;
+ }
+
+ return UriBuilder.fromUri(callback)
+ .queryParam(OAuth.OAUTH_TOKEN, message.getToken()).build()
+ .toString();
+ }
+
/**
* Validates the ID and password on the authorization form. This is intended
* to be invoked by an XHR on the login page.
@@ -162,8 +191,15 @@ public class OAuthService {
.type(MediaType.TEXT_PLAIN).build();
}
- OAuthConfiguration.getInstance().getTokenStrategy()
- .markRequestTokenAuthorized(httpRequest, requestToken);
+ try {
+ OAuthConfiguration.getInstance().getTokenStrategy()
+ .markRequestTokenAuthorized(httpRequest, requestToken);
+ } catch (OAuthProblemException e) {
+ return Response.status(Status.CONFLICT)
+ .entity("Request token invalid.")
+ .type(MediaType.TEXT_PLAIN).build();
+ }
+
return Response.noContent().build();
}
@@ -182,13 +218,17 @@ public class OAuthService {
public Response getAccessToken() throws IOException, ServletException {
try {
+ // Validate the request is signed and check that the request token is valid.
OAuthRequest oAuthRequest = validateRequest();
-
TokenStrategy strategy = OAuthConfiguration.getInstance()
.getTokenStrategy();
- strategy.validateRequestToken(oAuthRequest);
+ strategy.validateRequestToken(httpRequest,
+ oAuthRequest.getMessage());
+
+ // Generate a new access token for this accessor.
strategy.generateAccessToken(oAuthRequest);
-
+
+ // Send the new token and secret back to the consumer.
OAuthAccessor accessor = oAuthRequest.getAccessor();
return respondWithToken(accessor.accessToken, accessor.tokenSecret);
diff --git a/org.eclipse.lyo.server.oauth.webapp/src/main/webapp/oauth/key.png b/org.eclipse.lyo.server.oauth.webapp/src/main/webapp/oauth/key.png
new file mode 100644
index 0000000..a3ddf0b
--- /dev/null
+++ b/org.eclipse.lyo.server.oauth.webapp/src/main/webapp/oauth/key.png
Binary files differ
diff --git a/org.eclipse.lyo.server.oauth.webapp/src/main/webapp/oauth/login.js b/org.eclipse.lyo.server.oauth.webapp/src/main/webapp/oauth/login.js
index dffcb80..c788d51 100644
--- a/org.eclipse.lyo.server.oauth.webapp/src/main/webapp/oauth/login.js
+++ b/org.eclipse.lyo.server.oauth.webapp/src/main/webapp/oauth/login.js
@@ -51,7 +51,8 @@ require([ "dojo/dom", "dojo/dom-construct", "dojo/on", "dojo/_base/event",
}
function cancel() {
- alert('canceled!');
+ dom.byId('content').innerHTML =
+ '<div class="message">Access denied. Close the browser window to continue.</div>';
}
ready(function() {
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 7ff3a8e..00524ae 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
@@ -21,10 +21,14 @@
<body>
<div id="content">
+ <%-- 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">Another application, <c:out value="${consumerName}">[Unknwon]</c:out>,
- is requesting access to your <c:out value="${applicationName}">application</c:out> data. Enter your
+ <div class="message"><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>
<div id="error" class="error" style="display: hidden;"></div>