You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by li...@apache.org on 2009/04/23 09:40:08 UTC

svn commit: r767835 - in /incubator/shindig/trunk/java: server/src/main/webapp/WEB-INF/ social-api/src/main/java/org/apache/shindig/social/opensocial/oauth/ social-api/src/main/java/org/apache/shindig/social/sample/oauth/

Author: lindner
Date: Thu Apr 23 07:40:07 2009
New Revision: 767835

URL: http://svn.apache.org/viewvc?rev=767835&view=rev
Log:
SHINDIG-1027 | Address problems with three-legged OAuth

Modified:
    incubator/shindig/trunk/java/server/src/main/webapp/WEB-INF/authorize.jsp
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/oauth/OAuthDataStore.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/oauth/OAuthEntry.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/sample/oauth/SampleOAuthDataStore.java
    incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/sample/oauth/SampleOAuthServlet.java

Modified: incubator/shindig/trunk/java/server/src/main/webapp/WEB-INF/authorize.jsp
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/server/src/main/webapp/WEB-INF/authorize.jsp?rev=767835&r1=767834&r2=767835&view=diff
==============================================================================
--- incubator/shindig/trunk/java/server/src/main/webapp/WEB-INF/authorize.jsp (original)
+++ incubator/shindig/trunk/java/server/src/main/webapp/WEB-INF/authorize.jsp Thu Apr 23 07:40:07 2009
@@ -29,16 +29,15 @@
     // Bounce back to the servlet to handle redirecting to the callback URL
     request.getRequestDispatcher("/oauth/authorize?oauth_token=" + token + "&oauth_callback=" + callback)
             .forward(request,response);
+  } else if (request.getParameter("Deny") != null) {
+    dataStore.removeToken(entry);
   }
-
   // Gather some data
-  String appTitle =(String)consumer.getProperty("title");
-  String appDesc = (String)consumer.getProperty("description");
-  if (appDesc == null)
-    appDesc = consumer.consumerKey;
+  pageContext.setAttribute("appTitle", consumer.getProperty("title") , PageContext.PAGE_SCOPE);
+  pageContext.setAttribute("appDesc", consumer.getProperty("description"), PageContext.PAGE_SCOPE);
     
-  String appIcon = (String)consumer.getProperty("icon");
-  String appThumbnail = (String)consumer.getProperty("thumbnail");
+  pageContext.setAttribute("appIcon", consumer.getProperty("icon"));
+  pageContext.setAttribute("appThumbnail", consumer.getProperty("thumbnail"));
 %>
 <html>
 <head>
@@ -50,13 +49,21 @@
 
 The following application wants to access your account information<br/><br/>
 
-<h3><img src="<%= appIcon %>"/><%=appTitle %>" is trying to access your information.</h3>
-<img src="<%= appThumbnail%>" align="left" width="120" height="60"/>
-<c:out value="appDesc" default=""/>
+<h3><img src="${appIcon}"/> <b><c:out value="${appTitle}"/></b> is trying to access your information.</h3>
+<img src="${appThumbnail}" align="left" width="120" height="60"/>
+<c:out value="${appDesc}" default=""/>
 <br/>
+<c:if test="${SECURITY_THREAT_2009_1}">
+  <font color="red"><b>POSSIBLE SECURITY RISK</b> - 
+  Deny this request unless you directly initiated it from the Official 
+  <i><c:out value="${appTitle}"/></i> web site
+  </font>
+</c:if>
+
 <form name="authZForm" action="authorize" method="POST">
   <input type="hidden" name="oauth_token" value="<%= token %>"/>
   <input type="hidden" name="oauth_callback" value="<%= URLEncoder.encode(callback, "UTF-8") %>"/>
+  <input type="submit" name="Authorize" value="Deny"/>
   <input type="submit" name="Authorize" value="Authorize"/>
 </form>
 

Modified: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/oauth/OAuthDataStore.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/oauth/OAuthDataStore.java?rev=767835&r1=767834&r2=767835&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/oauth/OAuthDataStore.java (original)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/oauth/OAuthDataStore.java Thu Apr 23 07:40:07 2009
@@ -79,7 +79,7 @@
    * @return An OAuthEntry containing a valid request token.
    * @throws OAuthProblemException when the implementing class wants to control the error response
    */
-  OAuthEntry generateRequestToken(String consumerKey) throws OAuthProblemException;
+  OAuthEntry generateRequestToken(String consumerKey, String oauthVersion) throws OAuthProblemException;
 
 
   /**
@@ -101,4 +101,19 @@
    * @throws OAuthProblemException when the implementing class wants to control the error response
    */
   void authorizeToken(OAuthEntry entry, String userId) throws OAuthProblemException;
+
+  /**
+   * Mark a token DISABLED and store it.
+   * 
+   * @param entry A valid OAuthEntry
+   */
+  void disableToken(OAuthEntry entry);
+
+  /**
+   * Remove a token
+   * 
+   * @param entry A valid OAuthEntry
+   */
+  void removeToken(OAuthEntry entry);
+
 }

Modified: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/oauth/OAuthEntry.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/oauth/OAuthEntry.java?rev=767835&r1=767834&r2=767835&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/oauth/OAuthEntry.java (original)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/oauth/OAuthEntry.java Thu Apr 23 07:40:07 2009
@@ -32,7 +32,7 @@
   static final long serialVersionUID = 2;
 
   public static enum Type {
-    REQUEST, ACCESS
+    REQUEST, ACCESS, DISABLED
   }
 
   public String appId;
@@ -50,6 +50,7 @@
 
   public String domain;
   public String container;
+  public String oauthVersion;
 
   public OAuthEntry() {}
 
@@ -69,6 +70,7 @@
     this.issueTime = old.issueTime;
     this.domain = old.domain;
     this.container = old.container;
+    this.oauthVersion = old.oauthVersion;
   }
 
   public boolean isExpired() {

Modified: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/sample/oauth/SampleOAuthDataStore.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/sample/oauth/SampleOAuthDataStore.java?rev=767835&r1=767834&r2=767835&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/sample/oauth/SampleOAuthDataStore.java (original)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/sample/oauth/SampleOAuthDataStore.java Thu Apr 23 07:40:07 2009
@@ -85,7 +85,7 @@
   }
 
   // Generate a valid requestToken for the given consumerKey
-  public OAuthEntry generateRequestToken(String consumerKey) {
+  public OAuthEntry generateRequestToken(String consumerKey, String oauthVersion) {
     OAuthEntry entry = new OAuthEntry();
     entry.appId = consumerKey;
     entry.consumerKey = consumerKey;
@@ -97,6 +97,7 @@
       
     entry.type = OAuthEntry.Type.REQUEST;
     entry.issueTime = new Date();
+    entry.oauthVersion = oauthVersion;
 
     oauthEntries.put(entry.token, entry);
     return entry;
@@ -115,7 +116,6 @@
     accessEntry.type = OAuthEntry.Type.ACCESS;
     accessEntry.issueTime = new Date();
 
-    
     oauthEntries.remove(entry.token);
     oauthEntries.put(accessEntry.token, accessEntry);
 
@@ -129,6 +129,19 @@
     entry.userId = Preconditions.checkNotNull(userId);
   }
 
+  public void disableToken(OAuthEntry entry) {
+    Preconditions.checkNotNull(entry);
+    entry.type = OAuthEntry.Type.DISABLED;
+
+    oauthEntries.put(entry.token, entry);
+  }
+
+  public void removeToken(OAuthEntry entry) {
+    Preconditions.checkNotNull(entry);
+
+    oauthEntries.remove(entry.token);
+  }
+
   // Return the proper security token for a 2 legged oauth request that has been validated
   // for the given consumerKey. App specific checks like making sure the requested user has the
   // app installed should take place in this method

Modified: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/sample/oauth/SampleOAuthServlet.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/sample/oauth/SampleOAuthServlet.java?rev=767835&r1=767834&r2=767835&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/sample/oauth/SampleOAuthServlet.java (original)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/sample/oauth/SampleOAuthServlet.java Thu Apr 23 07:40:07 2009
@@ -92,7 +92,7 @@
     String consumerKey = requestMessage.getConsumerKey();
     if (consumerKey == null) {
       OAuthProblemException e = new OAuthProblemException(OAuth.Problems.PARAMETER_ABSENT);
-      e.setParameter(OAuth.Problems.OAUTH_PARAMETERS_ABSENT, "oauth_consumer_key");
+      e.setParameter(OAuth.Problems.OAUTH_PARAMETERS_ABSENT, OAuth.OAUTH_CONSUMER_KEY);
       throw e;
     }
     OAuthConsumer consumer = dataStore.getConsumer(consumerKey);
@@ -104,7 +104,7 @@
     VALIDATOR.validateMessage(requestMessage, accessor);
 
     // generate request_token and secret
-    OAuthEntry entry = dataStore.generateRequestToken(consumerKey);
+    OAuthEntry entry = dataStore.generateRequestToken(consumerKey, requestMessage.getParameter(OAuth.OAUTH_VERSION));
 
     sendResponse(servletResponse, OAuth.newList(OAuth.OAUTH_TOKEN, entry.token,
         OAuth.OAUTH_TOKEN_SECRET, entry.tokenSecret));
@@ -131,12 +131,35 @@
     }
 
     OAuthConsumer consumer = dataStore.getConsumer(entry.consumerKey);
-    String callback = requestMessage.getParameter("oauth_callback");
+
+    // Extremely rare case where consumer dissappears
+    if (consumer == null) {
+      servletResponse.sendError(HttpServletResponse.SC_NOT_FOUND, "consumer for entry not found");
+      return;
+    }
+    
+    // A flag to deal with protocol flaws in OAuth/1.0
+    Boolean securityThreat_2009_1 = (entry.oauthVersion == null || OAuth.VERSION_1_0.equals(entry.oauthVersion));
+
+    // Check for a callback in the oauth entry
+    String callback = entry.callbackUrl;
+
+    if (callback == null) {
+      // see if there's a callback in the url params
+      callback = requestMessage.getParameter(OAuth.OAUTH_CALLBACK);
+    }
+
     if (callback == null) {
       // see if the consumer has a callback
       callback = consumer.callbackURL;
     }
 
+    // The token is disabled if you try to convert to an access token prior to authorization
+    if (entry.type == OAuthEntry.Type.DISABLED) {
+      servletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "This token is disabled, please reinitate login");
+      return;
+    }
+
     // Redirect to a UI flow if the token is not authorized
     if (!entry.authorized) {
       // TBD -- need to decode encrypted payload somehow..
@@ -153,16 +176,18 @@
 
         servletRequest.setAttribute("TOKEN", entry.token);
         servletRequest.setAttribute("CONSUMER", consumer);
+        servletRequest.setAttribute("SECURITY_THREAT_2009_1", securityThreat_2009_1);
         
         servletRequest.getRequestDispatcher(oauthAuthorizeAction).forward(servletRequest,servletResponse);
       }
       return;
     }
 
-    // If we're here then the entry has been authorized out of band.
+    // If we're here then the entry has been authorized
 
-    // redirect to callback param oauth_callback
+    // redirect to callback
     if (callback == null) {
+      // consumer did not specify a callback
       servletResponse.setContentType("text/plain");
       OutputStream out = servletResponse.getOutputStream();
       out.write("Token successfully authorized.".getBytes());
@@ -188,7 +213,10 @@
       throw new OAuthProblemException(OAuth.Problems.TOKEN_REJECTED);
 
     if (!entry.authorized) {
-      throw new ServletException("additional_authorization_required");
+      // Catch consumers trying to convert a token to one that's not authorized
+      dataStore.disableToken(entry); 
+      servletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "This token is not authorized");
+      return;
     }
 
     // turn request token into access token
@@ -218,7 +246,7 @@
 
     if  (requestMessage.getConsumerKey() == null) {
       OAuthProblemException e = new OAuthProblemException(OAuth.Problems.PARAMETER_ABSENT);
-      e.setParameter(OAuth.Problems.OAUTH_PARAMETERS_ABSENT, "oauth_consumer");
+      e.setParameter(OAuth.Problems.OAUTH_PARAMETERS_ABSENT, OAuth.OAUTH_CONSUMER_KEY);
       throw e;
     }