Author: beaton
Date: Thu Jul 10 17:24:55 2008
New Revision: 675815

URL: http://svn.apache.org/viewvc?rev=675815&view=rev
Log:
Improve OAuth error handling.  We treat all 401s as "ask the user for
permission" and anything else between 400 and 499 inclusive as "go away."

Added:
    
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/OAuthProtocolExceptionTest.java
   (with props)
Modified:
    
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetcher.java
    
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthProtocolException.java
    
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/FakeOAuthServiceProvider.java
    
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/OAuthFetcherTest.java

Modified: 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetcher.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetcher.java?rev=675815&r1=675814&r2=675815&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetcher.java
 (original)
+++ 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetcher.java
 Thu Jul 10 17:24:55 2008
@@ -280,7 +280,6 @@
     return buildNonDataResponse();
   }
 
-  // TODO(beaton) test case
   private boolean handleProtocolException(
       OAuthProtocolException pe, int attempts) throws OAuthStoreException {
     if (pe.startFromScratch()) {
@@ -495,13 +494,11 @@
                                  HttpRequest.DEFAULT_OPTIONS);
 
     HttpResponse response = nextFetcher.fetch(oauthRequest);
+    checkForProtocolProblem(response);
     OAuthMessage reply = new OAuthMessage(null, null, null);
     
     reply.addParameters(OAuth.decodeForm(response.getResponseAsString()));
     reply = parseAuthHeader(reply, response);
-    if (reply.getParameter(OAuthProblemException.OAUTH_PROBLEM) != null) {
-      throw new OAuthProtocolException(reply);
-    }
     return reply;
   }
 
@@ -684,14 +681,7 @@
 
       HttpResponse response = nextFetcher.fetch(oauthHttpRequest);
       
-      // TODO is there a better way to detect an SP error?
-      int statusCode = response.getHttpStatusCode();
-      if (statusCode >= 400 && statusCode < 500) {
-        OAuthMessage message = parseAuthHeader(null, response);
-        if (message.getParameter(OAuthProblemException.OAUTH_PROBLEM) != null) 
{
-          throw new OAuthProtocolException(message);
-        }
-      }
+      checkForProtocolProblem(response);
   
       // Track metadata on the response
       addResponseMetadata(response);
@@ -706,6 +696,20 @@
       throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
     }
   }
+  
+  private void checkForProtocolProblem(HttpResponse response)
+      throws OAuthProtocolException, IOException {
+    int status = response.getHttpStatusCode();
+    if (status >= 400 && status < 500) {
+      OAuthMessage message = parseAuthHeader(null, response);
+      if (message.getParameter(OAuthProblemException.OAUTH_PROBLEM) != null) {
+        // SP reported extended error information
+        throw new OAuthProtocolException(message);
+      }
+      // No extended information, guess based on HTTP response code.
+      throw new OAuthProtocolException(status);
+    }
+  }
 
   /**
    * Extracts only those parameters from an OAuthMessage that are 
OAuth-related.

Modified: 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthProtocolException.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthProtocolException.java?rev=675815&r1=675814&r2=675815&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthProtocolException.java
 (original)
+++ 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthProtocolException.java
 Thu Jul 10 17:24:55 2008
@@ -44,8 +44,6 @@
  *   
  * TODO: add a third category to cope with reauthorization per the 
ScalableOAuth
  * extension.
- * 
- * TODO(beaton) test case
  */
 class OAuthProtocolException extends Exception {
 
@@ -108,6 +106,23 @@
   }
 
   /**
+   * Handle OAuth protocol errors for SPs that don't support the problem
+   * reporting extension
+   * @param status HTTP status code, assumed to be between 400 and 499 
inclusive
+   */
+  public OAuthProtocolException(int status) {
+    problemCode = Integer.toString(status);
+    problemText = null;
+    if (status == 401) {
+      startFromScratch = true;
+      canRetry = true;
+    } else {
+      startFromScratch = true;
+      canRetry = false;
+    }
+  }
+
+  /**
    * @return true if we've gotten confused to the point where we should give
    * up and ask the user for approval again.
    */

Modified: 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/FakeOAuthServiceProvider.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/FakeOAuthServiceProvider.java?rev=675815&r1=675814&r2=675815&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/FakeOAuthServiceProvider.java
 (original)
+++ 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/FakeOAuthServiceProvider.java
 Thu Jul 10 17:24:55 2008
@@ -35,7 +35,6 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
@@ -110,6 +109,7 @@
   private final OAuthConsumer consumer;
 
   private boolean throttled;
+  private boolean vagueErrors;
   
   private int requestTokenCount = 0;
   
@@ -124,6 +124,11 @@
         null, CONSUMER_KEY, CONSUMER_SECRET, provider);
     tokenState = new HashMap<String, TokenState>();
     validator = new SimpleOAuthValidator();
+    vagueErrors = false;
+  }
+  
+  public void setVagueErrors(boolean vagueErrors) {
+    this.vagueErrors = vagueErrors;
   }
   
   @SuppressWarnings("unused")
@@ -177,6 +182,13 @@
 
   private HttpResponse makeOAuthProblemReport(String code, String text)
       throws IOException {
+    if (vagueErrors) {
+      int rc = 401;
+      if ("consumer_key_unknown".equals(code)) {
+        rc = 403;
+      }
+      return new HttpResponse(rc, null, null);
+    }
     OAuthMessage msg = new OAuthMessage(null, null, null);
     msg.addParameter("oauth_problem", code);
     msg.addParameter("oauth_problem_advice", text);

Modified: 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/OAuthFetcherTest.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/OAuthFetcherTest.java?rev=675815&r1=675814&r2=675815&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/OAuthFetcherTest.java
 (original)
+++ 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/OAuthFetcherTest.java
 Thu Jul 10 17:24:55 2008
@@ -242,6 +242,60 @@
     response = fetcher.fetch(request);
     assertEquals("User data is reapproved", response.getResponseAsString());
   }
+  
+
+  @Test
+  public void testError401() throws Exception {
+    HttpFetcher fetcher;
+    HttpRequest request;
+    HttpResponse response;
+    
+    serviceProvider.setVagueErrors(true);
+
+    fetcher = getFetcher(
+        getSecurityToken("owner", "owner"),
+        new OAuthRequestParams(SERVICE_NAME, null, null, false));
+    request = new HttpRequest(
+        new URI(FakeOAuthServiceProvider.RESOURCE_URL));
+    response = fetcher.fetch(request);
+    String clientState = response.getMetadata().get("oauthState");
+    assertNotNull(clientState);
+    String approvalUrl = response.getMetadata().get("oauthApprovalUrl");
+    assertNotNull(approvalUrl);
+
+    serviceProvider.browserVisit(approvalUrl + "&user_data=hello-oauth");
+
+    fetcher = getFetcher(
+        getSecurityToken("owner", "owner"),
+        new OAuthRequestParams(SERVICE_NAME, null, clientState, false));
+    request = new HttpRequest(
+        new URI(FakeOAuthServiceProvider.RESOURCE_URL));
+    response = fetcher.fetch(request);
+    assertEquals("User data is hello-oauth", response.getResponseAsString());
+
+    serviceProvider.revokeAllAccessTokens();
+
+    fetcher = getFetcher(
+        getSecurityToken("owner", "owner"),
+        new OAuthRequestParams(SERVICE_NAME, null, clientState, false));
+    request = new HttpRequest(
+        new URI(FakeOAuthServiceProvider.RESOURCE_URL));
+    response = fetcher.fetch(request);
+
+    clientState = response.getMetadata().get("oauthState");
+    assertNotNull(clientState);
+    approvalUrl = response.getMetadata().get("oauthApprovalUrl");
+    assertNotNull(approvalUrl);
+
+    serviceProvider.browserVisit(approvalUrl + "&user_data=reapproved");
+    fetcher = getFetcher(
+        getSecurityToken("owner", "owner"),
+        new OAuthRequestParams(SERVICE_NAME, null, clientState, false));
+    request = new HttpRequest(
+        new URI(FakeOAuthServiceProvider.RESOURCE_URL));
+    response = fetcher.fetch(request);
+    assertEquals("User data is reapproved", response.getResponseAsString());
+  }
 
   @Test
   public void testUnknownConsumerKey() throws Exception {
@@ -262,6 +316,26 @@
         "invalid consumer: garbage_key",
         metadata.get("oauthErrorText"));
   }
+  
+  @Test
+  public void testError403() throws Exception {
+    HttpFetcher fetcher;
+    HttpRequest request;
+    HttpResponse response;
+    
+    serviceProvider.setVagueErrors(true);
+
+    fetcher = getFetcher(
+        getNokeySecurityToken("owner", "owner"),
+        new OAuthRequestParams(SERVICE_NAME_NO_KEY, null, null, false));
+    request = new HttpRequest(
+        new URI(FakeOAuthServiceProvider.RESOURCE_URL));
+    response = fetcher.fetch(request);
+    Map<String, String> metadata = response.getMetadata();
+    assertNotNull(metadata);
+    assertEquals("403", metadata.get("oauthError"));
+    assertNull(metadata.get("oauthErrorText"));
+  }
 
   @Test
   public void testConsumerThrottled() throws Exception {

Added: 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/OAuthProtocolExceptionTest.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/OAuthProtocolExceptionTest.java?rev=675815&view=auto
==============================================================================
--- 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/OAuthProtocolExceptionTest.java
 (added)
+++ 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/OAuthProtocolExceptionTest.java
 Thu Jul 10 17:24:55 2008
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package org.apache.shindig.gadgets.oauth;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Map;
+
+import net.oauth.OAuthMessage;
+
+import org.apache.shindig.gadgets.http.HttpResponse;
+import org.junit.Test;
+
+/**
+ * Test cases for OAuthProtocolException
+ */
+public class OAuthProtocolExceptionTest {
+
+  @Test
+  public void testProblemReportingExtension() throws Exception {
+    OAuthMessage m = new OAuthMessage(null, null, null);
+    m.addParameter("oauth_problem", "consumer_key_refused");
+    m.addParameter("oauth_problem_advice", "stuff it");
+    OAuthProtocolException e = new OAuthProtocolException(m);
+    assertFalse(e.canRetry());
+    HttpResponse r = e.getResponseForGadget();
+    Map<String, String> metadata = r.getMetadata();
+    assertEquals("stuff it", metadata.get("oauthErrorText"));
+    assertEquals("consumer_key_refused", metadata.get("oauthError"));
+  }
+}

Propchange: 
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/OAuthProtocolExceptionTest.java
------------------------------------------------------------------------------
    svn:eol-style = native


Reply via email to