You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@shindig.apache.org by be...@apache.org on 2008/09/10 03:50:42 UTC

svn commit: r693675 [2/4] - in /incubator/shindig/trunk: config/ java/common/src/main/java/org/apache/shindig/common/crypto/ java/gadgets/conf/ java/gadgets/src/main/java/org/apache/shindig/gadgets/ java/gadgets/src/main/java/org/apache/shindig/gadgets...

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=693675&r1=693674&r2=693675&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 Tue Sep  9 18:50:41 2008
@@ -18,20 +18,25 @@
 
 import org.apache.shindig.auth.SecurityToken;
 import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.common.uri.UriBuilder;
 import org.apache.shindig.gadgets.ChainedContentFetcher;
 import org.apache.shindig.gadgets.GadgetException;
+import org.apache.shindig.gadgets.RequestSigningException;
 import org.apache.shindig.gadgets.http.HttpCacheKey;
 import org.apache.shindig.gadgets.http.HttpFetcher;
 import org.apache.shindig.gadgets.http.HttpRequest;
 import org.apache.shindig.gadgets.http.HttpResponse;
 import org.apache.shindig.gadgets.http.HttpResponseBuilder;
-import org.apache.shindig.gadgets.oauth.OAuthStore.OAuthParamLocation;
+import org.apache.shindig.gadgets.oauth.AccessorInfo.HttpMethod;
+import org.apache.shindig.gadgets.oauth.AccessorInfo.OAuthParamLocation;
+import org.apache.shindig.gadgets.oauth.OAuthStore.TokenInfo;
 
 import net.oauth.OAuth;
 import net.oauth.OAuthAccessor;
 import net.oauth.OAuthException;
 import net.oauth.OAuthMessage;
 import net.oauth.OAuthProblemException;
+import net.oauth.OAuth.Parameter;
 
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -41,15 +46,22 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.regex.Pattern;
 
 /**
- * Implements the OAuth dance (http://oauth.net/core/1.0/) for gadgets.
- *
- * Reading the example in the appendix to the OAuth spec will be helpful to
- * those reading this code.
- *
- * This class is not thread-safe; create a new one for each request that
- * requires OAuth signing.
+ * Implements both signed fetch and full OAuth for gadgets, as well as a combination of the two that
+ * is necessary to build OAuth enabled gadgets for social sites.
+ * 
+ * Signed fetch sticks identity information in the query string, signed either with the container's
+ * private key, or else with a secret shared between the container and the gadget.
+ * 
+ * Full OAuth redirects the user to the OAuth service provider site to obtain the user's permission
+ * to access their data.  Read the example in the appendix to the OAuth spec for a summary of how
+ * this works (The spec is at http://oauth.net/core/1.0/).
+ * 
+ * The combination protocol works by sending identity information in all requests, and allows the
+ * OAuth dance to happen as well when owner == viewer.  This lets OAuth service providers build up
+ * an identity mapping from ids on social network sites to their own local ids.
  */
 public class OAuthFetcher extends ChainedContentFetcher {
 
@@ -57,12 +69,26 @@
   private static final int MAX_ATTEMPTS = 2;
 
   // names of additional OAuth parameters we include in outgoing requests
+  // TODO(beaton): can we do away with this bit in favor of the opensocial param?
   public static final String XOAUTH_APP_URL = "xoauth_app_url";
+  
+  protected static final String OPENSOCIAL_OWNERID = "opensocial_owner_id";
+
+  protected static final String OPENSOCIAL_VIEWERID = "opensocial_viewer_id";
+
+  protected static final String OPENSOCIAL_APPID = "opensocial_app_id";
+  
+  // TODO(beaton): figure out if this is the name in the 0.8 spec.
+  protected static final String OPENSOCIAL_APPURL = "opensocial_app_url";
+
+  protected static final String XOAUTH_PUBLIC_KEY = "xoauth_signature_publickey";
+  
+  protected static final Pattern ALLOWED_PARAM_NAME = Pattern.compile("[-:\\w~!@$*()_\\[\\]:,./]+");
 
   /**
-   * Per request configuration for this OAuth fetch.
+   * State information from client
    */
-  protected final OAuthFetchParams fetchParams;
+  protected final OAuthClientState clientState;
 
   /**
    * Configuration options for the fetcher.
@@ -79,7 +105,7 @@
    * the service provider, such as their URLs and the keys we use to access
    * those URLs.
    */
-  private OAuthStore.AccessorInfo accessorInfo;
+  private AccessorInfo accessorInfo;
 
   /**
    * The request the client really wants to make.
@@ -89,20 +115,17 @@
   /**
    * @param fetcherConfig configuration options for the fetcher
    * @param nextFetcher fetcher to use for actually making requests
-   * @param authToken user's gadget security token
-   * @param params OAuth fetch parameters sent from makeRequest
+   * @param request request that will be sent through the fetcher
    */
   public OAuthFetcher(
       OAuthFetcherConfig fetcherConfig,
       HttpFetcher nextFetcher,
-      SecurityToken authToken,
-      OAuthArguments params) {
+      HttpRequest request) {
     super(nextFetcher);
     this.fetcherConfig = fetcherConfig;
-    this.fetchParams = new OAuthFetchParams(
-        params,
-        new OAuthClientState(fetcherConfig.getStateCrypter(), params.getOrigClientState()),
-        authToken);
+    this.clientState = new OAuthClientState(
+        fetcherConfig.getStateCrypter(),
+        request.getOAuthArguments().getOrigClientState());
     this.responseParams = new OAuthResponseParams(fetcherConfig.getStateCrypter());
   }
 
@@ -115,43 +138,13 @@
    * @throws GadgetException
    */
   private void lookupOAuthMetadata() throws GadgetException {
-    OAuthStore.TokenKey tokenKey = buildTokenKey();
     accessorInfo = fetcherConfig.getTokenStore().getOAuthAccessor(
-        tokenKey, fetchParams.getArguments().getBypassSpecCache());
-
-    // The persistent data store may be out of sync with reality; we trust
-    // the state we stored on the client to be accurate.
-    OAuthAccessor accessor = accessorInfo.getAccessor();
-    if (fetchParams.getClientState().getRequestToken() != null) {
-      accessor.requestToken = fetchParams.getClientState().getRequestToken();
-      accessor.tokenSecret = fetchParams.getClientState().getRequestTokenSecret();
-    } else if (fetchParams.getClientState().getAccessToken() != null) {
-      accessor.accessToken = fetchParams.getClientState().getAccessToken();
-      accessor.tokenSecret = fetchParams.getClientState().getAccessTokenSecret();
-    } else if (accessor.accessToken == null &&
-               fetchParams.getArguments().getRequestToken() != null) {
-      // We don't have an access token yet, but the client sent us a
-      // (hopefully) preapproved request token.
-      accessor.requestToken = fetchParams.getArguments().getRequestToken();
-      accessor.tokenSecret = fetchParams.getArguments().getRequestTokenSecret();
-    }
-  }
-
-  private OAuthStore.TokenKey buildTokenKey() {
-    OAuthStore.TokenKey tokenKey = new OAuthStore.TokenKey();
-    tokenKey.setGadgetUri(fetchParams.getAuthToken().getAppUrl());
-    tokenKey.setModuleId(fetchParams.getAuthToken().getModuleId());
-    tokenKey.setServiceName(fetchParams.getArguments().getServiceName());
-    tokenKey.setTokenName(fetchParams.getArguments().getTokenName());
-    // At some point we might want to let gadgets specify whether to use OAuth
-    // for the owner, the viewer, or someone else. For now always using the
-    // owner identity seems reasonable.
-    tokenKey.setUserId(fetchParams.getAuthToken().getOwnerId());
-    return tokenKey;
+        realRequest.getSecurityToken(), realRequest.getOAuthArguments(), clientState);
   }
 
   public HttpResponse fetch(HttpRequest request) throws GadgetException {
-    HttpCacheKey cacheKey = makeCacheKey(request);
+    this.realRequest = request;
+    HttpCacheKey cacheKey = makeCacheKey();
     HttpResponse response = fetcherConfig.getHttpCache().getResponse(cacheKey, request);
     if (response != null) {
       return response;
@@ -164,8 +157,6 @@
       return buildErrorResponse(e);
     }
 
-    this.realRequest = request;
-
     int attempts = 0;
     boolean retry;
     do {
@@ -189,19 +180,30 @@
     return fetcherConfig.getHttpCache().addResponse(cacheKey, request, response);
   }
 
-  // Builds up a cache key based on the same key that we use into the OAuth
-  // token storage, which should identify precisely which data to return for the
-  // response.  Using the OAuth access token as the cache key is another
-  // possibility.
-  private HttpCacheKey makeCacheKey(HttpRequest request) {
-    HttpCacheKey key = new HttpCacheKey(request);
+  // Builds up a cache key.  Full OAuth and signed fetch have slightly different cache semantics
+  // that both need to be accounted for here.  For signed fetch, we need to remember what identity
+  // information we passed along (owner only?  viewer only?  both?).  For OAuth, we need to
+  // remember whose OAuth token we used.  We only use the OAuth token when owner == viewer, and
+  // it's possible we won't do it even then.
+  private HttpCacheKey makeCacheKey() {
+    HttpCacheKey key = new HttpCacheKey(realRequest);
+    SecurityToken st = realRequest.getSecurityToken();
     key.set("authentication", "oauth");
-    OAuthStore.TokenKey tokenKey = buildTokenKey();
-    key.set("user", tokenKey.getUserId());
-    key.set("gadget", tokenKey.getGadgetUri());
-    key.set("instance", Long.toString(tokenKey.getModuleId()));
-    key.set("service", tokenKey.getServiceName());
-    key.set("token", tokenKey.getTokenName());
+    if (realRequest.getOAuthArguments().getSignOwner()) {
+      key.set("owner", st.getOwnerId());
+    }
+    if (realRequest.getOAuthArguments().getSignViewer()) {
+      key.set("viewer", st.getViewerId());
+    }
+    if (st.getOwnerId() != null
+        && st.getOwnerId().equals(st.getViewerId())
+        && realRequest.getOAuthArguments().mayUseToken()) {
+      key.set("tokenOwner", st.getOwnerId());
+    }
+    key.set("gadget", st.getAppUrl());
+    key.set("instance", Long.toString(st.getModuleId()));
+    key.set("service", realRequest.getOAuthArguments().getServiceName());
+    key.set("token", realRequest.getOAuthArguments().getTokenName());
     return key;
   }
 
@@ -226,14 +228,13 @@
   }
 
   private boolean handleProtocolException(
-      OAuthProtocolException pe, int attempts) throws OAuthStoreException {
+      OAuthProtocolException pe, int attempts) throws GadgetException {
     if (pe.startFromScratch()) {
-      OAuthStore.TokenKey tokenKey = buildTokenKey();
-      fetcherConfig.getTokenStore().removeToken(tokenKey);
-
-      accessorInfo.accessor.accessToken = null;
-      accessorInfo.accessor.requestToken = null;
-      accessorInfo.accessor.tokenSecret = null;
+      fetcherConfig.getTokenStore().removeToken(realRequest.getSecurityToken(),
+          accessorInfo.getConsumer(), realRequest.getOAuthArguments());
+      accessorInfo.getAccessor().accessToken = null;
+      accessorInfo.getAccessor().requestToken = null;
+      accessorInfo.getAccessor().tokenSecret = null;
     }
     return (attempts < MAX_ATTEMPTS && pe.canRetry());
   }
@@ -264,7 +265,8 @@
    * Do we need to get the user's approval to access the data?
    */
   private boolean needApproval() {
-    return (accessorInfo.getAccessor().requestToken == null
+    return (realRequest.getOAuthArguments().mustUseToken()
+            && accessorInfo.getAccessor().requestToken == null
             && accessorInfo.getAccessor().accessToken == null);
   }
 
@@ -275,9 +277,9 @@
    * @throws GadgetException
    */
   private void checkCanApprove() throws GadgetException {
-    String pageOwner = fetchParams.getAuthToken().getOwnerId();
-    String pageViewer = fetchParams.getAuthToken().getViewerId();
-    String stateOwner = fetchParams.getClientState().getOwner();
+    String pageOwner = realRequest.getSecurityToken().getOwnerId();
+    String pageViewer = realRequest.getSecurityToken().getViewerId();
+    String stateOwner = clientState.getOwner();
     if (!pageOwner.equals(pageViewer)) {
       throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR,
           "Only page owners can grant OAuth approval");
@@ -292,11 +294,17 @@
       throws GadgetException, OAuthProtocolException {
     try {
       OAuthAccessor accessor = accessorInfo.getAccessor();
-      String url = accessor.consumer.serviceProvider.requestTokenURL;
-      List<OAuth.Parameter> msgParams = new ArrayList<OAuth.Parameter>();
-      msgParams.add(new OAuth.Parameter(XOAUTH_APP_URL, fetchParams.getAuthToken().getAppUrl()));
-      OAuthMessage request = newRequestMessage(url, msgParams);
-      OAuthMessage reply = sendOAuthMessage(request);
+      HttpRequest request = new HttpRequest(
+          Uri.parse(accessor.consumer.serviceProvider.requestTokenURL));
+      request.setMethod(accessorInfo.getHttpMethod().toString());
+      if (accessorInfo.getHttpMethod() == HttpMethod.POST) {
+        request.setHeader("Content-Type", OAuth.FORM_ENCODED);
+      }
+      
+      HttpRequest signed = sanitizeAndSign(request, null);
+ 
+      OAuthMessage reply = sendOAuthMessage(signed);
+      
       reply.requireParameters(OAuth.OAUTH_TOKEN, OAuth.OAUTH_TOKEN_SECRET);
       accessor.requestToken = reply.getParameter(OAuth.OAUTH_TOKEN);
       accessor.tokenSecret = reply.getParameter(OAuth.OAUTH_TOKEN_SECRET);
@@ -304,50 +312,73 @@
       throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
     } catch (IOException e) {
       throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
-    } catch (URISyntaxException e) {
-      throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
     }
   }
 
-  private OAuthMessage newRequestMessage(String method,
-      String url, List<OAuth.Parameter> params)
-      throws OAuthException, IOException, URISyntaxException {
-
-    if (params == null) {
-      throw new IllegalArgumentException("params was null in " +
-          "newRequestMessage(String, String, List<OAuth.Parameter> " +
-          "Use newRequesMessage(String) if you don't have a params to pass");
+  /**
+   * Strip out any owner or viewer identity information passed by the client.
+   * 
+   * @throws RequestSigningException
+   */
+  private List<Parameter> sanitize(List<Parameter> params)
+      throws RequestSigningException {
+    ArrayList<Parameter> list = new ArrayList<Parameter>();
+    for (Parameter p : params) {
+      String name = p.getKey();
+      if (allowParam(name)) {
+        list.add(p);
+      } else {
+        throw new RequestSigningException("invalid parameter name " + name);
+      }
     }
-
-    switch (accessorInfo.signatureType) {
-      case RSA_SHA1:
-        params.add(new OAuth.Parameter(OAuth.OAUTH_SIGNATURE_METHOD,
-                                       OAuth.RSA_SHA1));
-        break;
-
-      case PLAINTEXT:
-        params.add(new OAuth.Parameter(OAuth.OAUTH_SIGNATURE_METHOD,
-                                       "PLAINTEXT"));
-        break;
-
-      default:
-        params.add(new OAuth.Parameter(OAuth.OAUTH_SIGNATURE_METHOD,
-                                       OAuth.HMAC_SHA1));
+    return list;
+  }
+  
+  private boolean allowParam(String paramName) {
+    String canonParamName = paramName.toLowerCase();
+    return (!(canonParamName.startsWith("oauth") ||
+        canonParamName.startsWith("xoauth") ||
+        canonParamName.startsWith("opensocial")) &&
+        ALLOWED_PARAM_NAME.matcher(canonParamName).matches());
+  }
+   
+  /**
+   * Add identity information, such as owner/viewer/gadget.
+   */
+  private void addIdentityParams(List<Parameter> params) {
+    String owner = realRequest.getSecurityToken().getOwnerId();
+    if (owner != null && realRequest.getOAuthArguments().getSignOwner()) {
+      params.add(new Parameter(OPENSOCIAL_OWNERID, owner));
     }
 
-    OAuthAccessor accessor = accessorInfo.getAccessor();
+    String viewer = realRequest.getSecurityToken().getViewerId();
+    if (viewer != null && realRequest.getOAuthArguments().getSignViewer()) {
+      params.add(new Parameter(OPENSOCIAL_VIEWERID, viewer));
+    }
 
-    return accessor.newRequestMessage(method, url, params);
+    String app = realRequest.getSecurityToken().getAppId();
+    if (app != null) {
+      params.add(new Parameter(OPENSOCIAL_APPID, app));
+    }
+    
+    String appUrl = realRequest.getSecurityToken().getAppUrl();
+    if (appUrl != null) {
+      params.add(new Parameter(OPENSOCIAL_APPURL, appUrl));
+    }
+    
+    if (accessorInfo.getConsumer().getConsumer().consumerKey == null) {
+      params.add(
+          new Parameter(OAuth.OAUTH_CONSUMER_KEY, realRequest.getSecurityToken().getDomain()));
+    }
   }
-
-  private OAuthMessage newRequestMessage(String url,
-      List<OAuth.Parameter> params)
-      throws OAuthException, IOException, URISyntaxException {
-    String method = "POST";
-    if (accessorInfo.getHttpMethod() == OAuthStore.HttpMethod.GET) {
-      method = "GET";
+  
+  /**
+   * Add signature type to the message.
+   */
+  private void addSignatureParams(List<Parameter> params) {
+    if (accessorInfo.getConsumer().getKeyName() != null) {
+      params.add(new Parameter(XOAUTH_PUBLIC_KEY, accessorInfo.getConsumer().getKeyName()));
     }
-    return newRequestMessage(method, url, params);
   }
 
   private String getAuthorizationHeader(
@@ -369,10 +400,49 @@
     return result.toString();
   }
 
+  
+  /*
+    Start with an HttpRequest.
+    Throw if there are any attacks in the query.
+    Throw if there are any attacks in the post body.
+    Build up OAuth parameter list
+    Sign it.
+    Add OAuth parameters to new request
+    Send it.
+  */
+  public HttpRequest sanitizeAndSign(HttpRequest base, List<Parameter> params)
+      throws GadgetException {
+    if (params == null) {
+      params = new ArrayList<Parameter>();
+    }
+    UriBuilder target = new UriBuilder(base.getUri());
+    String query = target.getQuery();
+    target.setQuery(null);
+    params.addAll(sanitize(OAuth.decodeForm(query)));
+    params.addAll(sanitize(OAuth.decodeForm(base.getPostBodyAsString())));
+
+    addIdentityParams(params);
+    
+    addSignatureParams(params);
+
+    try {
+      OAuthMessage signed = accessorInfo.getAccessor().newRequestMessage(
+          base.getMethod(), target.toString(), params);
+      HttpRequest oauthHttpRequest = createHttpRequest(base, selectOAuthParams(signed));
+      return oauthHttpRequest;
+    } catch (IOException e) {
+      throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
+    } catch (OAuthException e) {
+      throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
+    } catch (URISyntaxException e) {
+      throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
+    }
+  }
+
   private HttpRequest createHttpRequest(HttpRequest base,
       List<Map.Entry<String, String>> oauthParams) throws IOException, GadgetException {
 
-    OAuthStore.OAuthParamLocation paramLocation = accessorInfo.getParamLocation();
+    OAuthParamLocation paramLocation = accessorInfo.getParamLocation();
 
     // paramLocation could be overriden by a run-time parameter to fetchRequest
 
@@ -383,9 +453,9 @@
     // can't have a body, or we can stick the parameters somewhere else, like, say, the header.
     // We opt to put them in the header, since that stands some chance of working with some
     // OAuth service providers.
-    if (paramLocation == OAuthStore.OAuthParamLocation.POST_BODY &&
+    if (paramLocation == OAuthParamLocation.POST_BODY &&
         !result.getMethod().equals("POST")) {
-      paramLocation = OAuthStore.OAuthParamLocation.AUTH_HEADER;
+      paramLocation = OAuthParamLocation.AUTH_HEADER;
     }
 
     switch (paramLocation) {
@@ -394,7 +464,8 @@
         break;
 
       case POST_BODY:
-        if (!OAuth.isFormEncoded(result.getContentType())) {
+        String contentType = result.getHeader("Content-Type");
+        if (!OAuth.isFormEncoded(contentType)) {
           throw new GadgetException(GadgetException.Code.INVALID_PARAMETER,
               "OAuth param location can only be post_body if post body if of " +
               "type x-www-form-urlencoded");
@@ -417,22 +488,13 @@
 
   /**
    * Sends OAuth request token and access token messages.
-   */
-  private OAuthMessage sendOAuthMessage(OAuthMessage request)
-      throws IOException, OAuthProtocolException, GadgetException {
-
-    HttpRequest req = new HttpRequest(Uri.parse(request.URL))
-        .setMethod(request.method)
-        .setIgnoreCache(true);
-    
-    // Per section 5.2 of OAuth spec
-    if (accessorInfo.paramLocation == OAuthParamLocation.POST_BODY) {
-      req.setHeader("Content-Type", "application/x-www-form-urlencoded");
-    }
-
-    HttpRequest oauthRequest = createHttpRequest(req, filterOAuthParams(request));
-
-    HttpResponse response = nextFetcher.fetch(oauthRequest);
+   * @throws GadgetException 
+   * @throws IOException 
+   * @throws OAuthProtocolException 
+   */
+  private OAuthMessage sendOAuthMessage(HttpRequest request)
+      throws GadgetException, OAuthProtocolException, IOException {
+    HttpResponse response = nextFetcher.fetch(request);
     checkForProtocolProblem(response);
     OAuthMessage reply = new OAuthMessage(null, null, null);
 
@@ -468,7 +530,7 @@
     OAuthAccessor accessor = accessorInfo.getAccessor();
     responseParams.getNewClientState().setRequestToken(accessor.requestToken);
     responseParams.getNewClientState().setRequestTokenSecret(accessor.tokenSecret);
-    responseParams.getNewClientState().setOwner(fetchParams.getAuthToken().getOwnerId());
+    responseParams.getNewClientState().setOwner(realRequest.getSecurityToken().getOwnerId());
   }
 
   /**
@@ -506,7 +568,8 @@
    * Do we need to exchange a request token for an access token?
    */
   private boolean needAccessToken() {
-    return (accessorInfo.getAccessor().requestToken != null
+    return (realRequest.getOAuthArguments().mustUseToken()
+            && accessorInfo.getAccessor().requestToken != null
             && accessorInfo.getAccessor().accessToken == null);
   }
 
@@ -518,13 +581,20 @@
       throws GadgetException, OAuthProtocolException {
     try {
       OAuthAccessor accessor = accessorInfo.getAccessor();
-      String url = accessor.consumer.serviceProvider.accessTokenURL;
-      List<OAuth.Parameter> msgParams = new ArrayList<OAuth.Parameter>();
-      msgParams.add(new OAuth.Parameter(XOAUTH_APP_URL, fetchParams.getAuthToken().getAppUrl()));
-      msgParams.add(
-          new OAuth.Parameter(OAuth.OAUTH_TOKEN, accessor.requestToken));
-      OAuthMessage request = newRequestMessage(url, msgParams);
-      OAuthMessage reply = sendOAuthMessage(request);
+      HttpRequest request = new HttpRequest(
+          Uri.parse(accessor.consumer.serviceProvider.accessTokenURL));
+      request.setMethod(accessorInfo.getHttpMethod().toString());
+      if (accessorInfo.getHttpMethod() == HttpMethod.POST) {
+        request.setHeader("Content-Type", OAuth.FORM_ENCODED);
+      }
+      
+      List<Parameter> msgParams = new ArrayList<Parameter>();
+      msgParams.add(new Parameter(OAuth.OAUTH_TOKEN, accessor.requestToken));
+      
+      HttpRequest signed = sanitizeAndSign(request, msgParams);
+      
+      OAuthMessage reply = sendOAuthMessage(signed);
+      
       reply.requireParameters(OAuth.OAUTH_TOKEN, OAuth.OAUTH_TOKEN_SECRET);
       accessor.accessToken = reply.getParameter(OAuth.OAUTH_TOKEN);
       accessor.tokenSecret = reply.getParameter(OAuth.OAUTH_TOKEN_SECRET);
@@ -532,8 +602,6 @@
       throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
     } catch (IOException e) {
       throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
-    } catch (URISyntaxException e) {
-      throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
     }
   }
 
@@ -544,10 +612,9 @@
    */
   private void saveAccessToken() throws GadgetException {
     OAuthAccessor accessor = accessorInfo.getAccessor();
-    OAuthStore.TokenKey tokenKey = buildTokenKey();
-    OAuthStore.TokenInfo tokenInfo = new OAuthStore.TokenInfo(
-        accessor.accessToken, accessor.tokenSecret);
-    fetcherConfig.getTokenStore().storeTokenKeyAndSecret(tokenKey, tokenInfo);
+    TokenInfo tokenInfo = new TokenInfo(accessor.accessToken, accessor.tokenSecret);
+    fetcherConfig.getTokenStore().storeTokenKeyAndSecret(realRequest.getSecurityToken(),
+        accessorInfo.getConsumer(), realRequest.getOAuthArguments(), tokenInfo);
   }
 
   /**
@@ -557,7 +624,7 @@
     OAuthAccessor accessor = accessorInfo.getAccessor();
     responseParams.getNewClientState().setAccessToken(accessor.accessToken);
     responseParams.getNewClientState().setAccessTokenSecret(accessor.tokenSecret);
-    responseParams.getNewClientState().setOwner(fetchParams.getAuthToken().getOwnerId());
+    responseParams.getNewClientState().setOwner(realRequest.getSecurityToken().getOwnerId());
   }
 
   /**
@@ -569,28 +636,10 @@
   private HttpResponse fetchData()
       throws GadgetException, OAuthProtocolException {
     try {
-      List<OAuth.Parameter> msgParams =
-        OAuth.isFormEncoded(realRequest.getContentType())
-        ? OAuth.decodeForm(realRequest.getPostBodyAsString())
-        : new ArrayList<OAuth.Parameter>();
-
-      String method = realRequest.getMethod();
-
-      msgParams.add(new OAuth.Parameter(XOAUTH_APP_URL, fetchParams.getAuthToken().getAppUrl()));
-
-      // Build and sign the message.
-      OAuthMessage oauthRequest = newRequestMessage(
-          method, realRequest.getUri().toString(), msgParams);
-
-      HttpRequest oauthHttpRequest = createHttpRequest(
-          realRequest,
-          filterOAuthParams(oauthRequest));
-
-      // Not externally cacheable.
-      oauthHttpRequest.setIgnoreCache(true);
-
-      HttpResponse response = nextFetcher.fetch(oauthHttpRequest);
-
+      HttpRequest signed = sanitizeAndSign(realRequest, null);
+      
+      HttpResponse response = nextFetcher.fetch(signed);
+      
       checkForProtocolProblem(response);
 
       // Track metadata on the response
@@ -601,10 +650,6 @@
       throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
     } catch (IOException e) {
       throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
-    } catch (URISyntaxException e) {
-      throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
-    } catch (OAuthException e) {
-      throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
     }
   }
 
@@ -640,15 +685,19 @@
    * @throws IOException
    */
   private List<Map.Entry<String, String>>
-      filterOAuthParams(OAuthMessage message) throws IOException {
+      selectOAuthParams(OAuthMessage message) throws IOException {
     List<Map.Entry<String, String>> result =
         new ArrayList<Map.Entry<String, String>>();
     for (Map.Entry<String, String> param : message.getParameters()) {
-      if (param.getKey().toLowerCase().startsWith("oauth")
-          || param.getKey().toLowerCase().startsWith("xoauth")) {
+      if (isContainerInjectedParameter(param.getKey())) {
         result.add(param);
       }
     }
     return result;
   }
+
+  private boolean isContainerInjectedParameter(String key) {
+    key = key.toLowerCase();
+    return key.startsWith("oauth") || key.startsWith("xoauth") || key.startsWith("opensocial");
+  }
 }

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetcherConfig.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetcherConfig.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetcherConfig.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetcherConfig.java Tue Sep  9 18:50:41 2008
@@ -17,7 +17,11 @@
 
 package org.apache.shindig.gadgets.oauth;
 
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+
 import org.apache.shindig.common.crypto.BlobCrypter;
+import org.apache.shindig.gadgets.DefaultGuiceModule;
 import org.apache.shindig.gadgets.http.HttpCache;
 
 /**
@@ -29,6 +33,16 @@
   private final GadgetOAuthTokenStore tokenStore;
   private final HttpCache httpCache;
   
+  @Inject
+  public OAuthFetcherConfig(
+      @Named(DefaultGuiceModule.OAUTH_STATE_CRYPTER_ANNOTATION) BlobCrypter stateCrypter,
+      GadgetOAuthTokenStore tokenStore,
+      HttpCache httpCache) {
+    this.stateCrypter = stateCrypter;
+    this.tokenStore = tokenStore;
+    this.httpCache = httpCache;
+  }
+  
   /**
    * Used to encrypt state stored on the client.
    */
@@ -50,10 +64,4 @@
     return httpCache;
   }
 
-  public OAuthFetcherConfig(BlobCrypter stateCrypter, GadgetOAuthTokenStore tokenStore,
-      HttpCache httpCache) {
-    this.stateCrypter = stateCrypter;
-    this.tokenStore = tokenStore;
-    this.httpCache = httpCache;
-  }
 }

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetcherFactory.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetcherFactory.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetcherFactory.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetcherFactory.java Tue Sep  9 18:50:41 2008
@@ -18,20 +18,12 @@
  */
 package org.apache.shindig.gadgets.oauth;
 
-import org.apache.shindig.auth.SecurityToken;
-import org.apache.shindig.common.crypto.BasicBlobCrypter;
-import org.apache.shindig.common.crypto.BlobCrypter;
-import org.apache.shindig.common.crypto.Crypto;
-import org.apache.shindig.gadgets.GadgetException;
-import org.apache.shindig.gadgets.GadgetSpecFactory;
-import org.apache.shindig.gadgets.http.HttpCache;
-import org.apache.shindig.gadgets.http.HttpFetcher;
-
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
-import java.util.logging.Level;
-import java.util.logging.Logger;
+import org.apache.shindig.gadgets.GadgetException;
+import org.apache.shindig.gadgets.http.HttpFetcher;
+import org.apache.shindig.gadgets.http.HttpRequest;
 
 /**
  * Produces OAuth content fetchers for input tokens.
@@ -41,35 +33,12 @@
 
   protected OAuthFetcherConfig fetcherConfig;
 
-  private static final Logger logger
-      = Logger.getLogger(OAuthFetcherFactory.class.getName());
-
-  /**
-   * Initialize the OAuth factory with a default implementation of
-   * BlobCrypter and consumer keys/secrets read from oauth.js
-   */
-  @Inject
-  public OAuthFetcherFactory(GadgetSpecFactory specFactory, HttpCache cache) {
-    try {
-      BlobCrypter oauthCrypter = new BasicBlobCrypter(
-          Crypto.getRandomBytes(BasicBlobCrypter.MASTER_KEY_MIN_LEN));
-
-      BasicGadgetOAuthTokenStore store =
-          new BasicGadgetOAuthTokenStore(new BasicOAuthStore(), specFactory);
-      store.initFromConfigFile();
-      fetcherConfig = new OAuthFetcherConfig(oauthCrypter, store, cache);
-    } catch (Throwable t) {
-      // Since this happens at startup, we don't want to kill the server just
-      // because we can't initialize the OAuth config.
-      logger.log(Level.WARNING, "Failed to initialize OAuth", t);
-    }
-  }
-
   /**
    * Creates an OAuthFetcherFactory based on prepared crypter and token store.
    *
    * @param fetcherConfig configuration
    */
+  @Inject
   protected OAuthFetcherFactory(OAuthFetcherConfig fetcherConfig) {
     this.fetcherConfig = fetcherConfig;
   }
@@ -79,17 +48,16 @@
    * network retrieval to the {@code nextFetcher}
    *
    * @param nextFetcher The fetcher that will fetch real content
-   * @param token The gadget token used to identity the user and gadget
-   * @param params The parsed parameters the gadget requested
+   * @param request request that will be sent through the fetcher
    * @return The oauth fetcher.
    * @throws GadgetException
    */
   @SuppressWarnings("unused")
-  public OAuthFetcher getOAuthFetcher(
-      HttpFetcher nextFetcher,
-      SecurityToken token,
-      OAuthArguments params) throws GadgetException {
-    OAuthFetcher fetcher = new OAuthFetcher(fetcherConfig, nextFetcher, token, params);
+  public OAuthFetcher getOAuthFetcher(HttpFetcher nextFetcher, HttpRequest request)
+      throws GadgetException {
+    OAuthFetcher fetcher = new OAuthFetcher(fetcherConfig, nextFetcher, request);
     return fetcher;
   }
+  
+  
 }

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthStore.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthStore.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthStore.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthStore.java Tue Sep  9 18:50:41 2008
@@ -17,7 +17,10 @@
  */
 package org.apache.shindig.gadgets.oauth;
 
-import net.oauth.OAuthAccessor;
+import org.apache.shindig.auth.SecurityToken;
+import org.apache.shindig.gadgets.GadgetException;
+
+import net.oauth.OAuthConsumer;
 import net.oauth.OAuthServiceProvider;
 
 /**
@@ -44,306 +47,37 @@
 public interface OAuthStore {
 
   /**
-   * If we or a gadget negotiate a separate consumer key and secret with a
-   * service provider, use this method to store it. The "secret" can either
-   * be a consumer secret in the strict OAuth sense, or it can be a
-   * PKCS8-then-Base64 encoded private key that we'll be using with this
-   * service provider. Even if we never set a consumer secret, an implementation
-   * of this interface may still be able to return useful OAuthAccessors in
-   * the getOAuthAccessor method, e.g. by returning a fallback private key and
-   * default consumer key, which could be used with service providers that we
-   * haven't negotiated a consumer secret with.
-   *
-   * @param providerKey the gadget that wants to use the service provider, and
-   *                    a nickName under which the gadget will refer to this
-   *                    service provider in the future.
-   * @param keyAndSecret the consumer key and secret. If the secret is an RSA
-   *                     private key, it must be PKCS8-then-Base64 encoded.
-   * @throws OAuthStoreException if something goes wrong accessing the
-   *                                   data store.
-   * @throws OAuthNoDataException if no provider info can be found for the
-   *                              provider specified in the providerKey.
-   */
-  public void setOAuthConsumerKeyAndSecret(ProviderKey providerKey,
-                                           ConsumerKeyAndSecret keyAndSecret)
-      throws OAuthStoreException, OAuthNoDataException;
-
-  /**
-   * Stores an access token.
-   * @param tokenKey a structure uniquely identifying the key under which this
-   *                 access token should be retrievable: a userId, a gadgetId,
-   *                 a moduleId (in case there are more than one gadget of the
-   *                 same type on a page), a tokenName (which distinguishes
-   *                 this token from others that the same gadget might hold for
-   *                 the same service provider) and a serviceName (which is the
-   *                 same as the service name in the ProviderKey structure).
-   * @param tokenInfo an access token and token secret.
-   * @throws OAuthStoreException if an error occurs talking to the
-   *                                   data store.
+   * Information about an OAuth consumer.
    */
-  public void setTokenAndSecret(TokenKey tokenKey, TokenInfo tokenInfo)
-      throws OAuthStoreException;
-
-
-  /**
-   * Removes an access token
-   * @param tokenKey the identifier for the access token
-   * @throws OAuthStoreException if an error occurs talking to the data store.
-   * @throws OAuthNoDataException if no existing access token is found.
-   */
-  public void removeToken(TokenKey tokenKey)
-      throws OAuthStoreException, OAuthNoDataException;
+  public static class ConsumerInfo {
+    private final OAuthConsumer consumer;
+    private final String keyName;
+    
+    /**
+     * @param consumer the OAuth consumer
+     * @param keyName the name of the key to use for this consumer (passed on query parameters to
+     * help with key rotation.)
+     */
+    public ConsumerInfo(OAuthConsumer consumer, String keyName) {
+      this.consumer = consumer;
+      this.keyName = keyName;
+    }
+    
+    public OAuthConsumer getConsumer() {
+      return consumer;
+    }
+    
+    public String getKeyName() {
+      return keyName;
+    }
+  }
   
   /**
-   * Retrieve an OAuthAccessor that is ready to sign OAuthMessages for
-   * resource access.
-   * @param tokenKey a structure uniquely identifying the token: a userId,
-   *                 a gadgetId, a moduleId (in case there are more than one
-   *                 gadget of the same type on a page), a tokenName (which
-   *                 distinguishes this token from others that the same gadget
-   *                 might hold for the same service provider) and a serviceName
-   *                 (which is the same as the service name in the ProviderKey
-   *                 structure).
-   * @param provInfo provider information. The store combines information stored
-   *                 in the store (consumer key/secret, token, token secret,
-   *                 etc.) with the provider information (access URL, request
-   *                 URL etc.) passed in here to create an AccessorInfo object.
-   *                 If no information can be found in the
-   *                 store, it may use default keys that identify the container,
-   *                 as opposed to consumer keys and secrets that are specific
-   *                 to this gadget.
-   * @return an OAuthAccessor object than can be passed to an OAuthMessage.sign
-   *         method.
-   * @throws OAuthNoDataException if the token couldn't be found
-   * @throws OAuthStoreException if an error occurred accessing the data
-   *                                   store.
+   * Information about an access token.
    */
-  public AccessorInfo getOAuthAccessor(TokenKey tokenKey,
-      ProviderInfo provInfo)
-      throws OAuthNoDataException, OAuthStoreException;
-
-
-  //////////////////////////////////////////////////////////////////////////////
-  // Auxiliary types needed to work with this interface
-  //////////////////////////////////////////////////////////////////////////////
-
-  public static enum HttpMethod { GET, POST }
-  public static enum SignatureType {HMAC_SHA1, RSA_SHA1, PLAINTEXT}
-  public static enum KeyType { HMAC_SYMMETRIC, RSA_PRIVATE }
-  public static enum OAuthParamLocation {
-    AUTH_HEADER,
-    POST_BODY,
-    URI_QUERY
-  }
-
-  public static class AccessorInfo {
-    OAuthAccessor accessor;
-    HttpMethod httpMethod;
-    SignatureType signatureType;
-    OAuthParamLocation paramLocation;
-
-    public OAuthParamLocation getParamLocation() {
-      return paramLocation;
-    }
-    public void setParamLocation(OAuthParamLocation paramLocation) {
-      this.paramLocation = paramLocation;
-    }
-    public OAuthAccessor getAccessor() {
-      return accessor;
-    }
-    public void setAccessor(OAuthAccessor accessor) {
-      this.accessor = accessor;
-    }
-    public HttpMethod getHttpMethod() {
-      return httpMethod;
-    }
-    public void setHttpMethod(HttpMethod httpMethod) {
-      this.httpMethod = httpMethod;
-    }
-    public SignatureType getSignatureType() {
-      return signatureType;
-    }
-    public void setSignatureType(SignatureType signatureType) {
-      this.signatureType = signatureType;
-    }
-  }
-
-  public static class ConsumerKeyAndSecret {
-    private String consumerKey;
-    private String consumerSecret;
-    private KeyType keyType;
-
-    public ConsumerKeyAndSecret(String key, String secret, KeyType type) {
-      consumerKey = key;
-      consumerSecret = secret;
-      keyType = type;
-    }
-    public String getConsumerKey() {
-      return consumerKey;
-    }
-    public String getConsumerSecret() {
-      return consumerSecret;
-    }
-    public KeyType getKeyType() {
-      return keyType;
-    }
-  }
-
-  public static class ProviderKey {
-    private String gadgetUri;
-    private String serviceName;
-
-    public String getGadgetUri() {
-      return gadgetUri;
-    }
-    public void setGadgetUri(String gadgetUri) {
-      this.gadgetUri = gadgetUri;
-    }
-    public String getServiceName() {
-      return serviceName;
-    }
-    public void setServiceName(String serviceName) {
-      this.serviceName = serviceName;
-    }
-
-    @Override
-    public int hashCode() {
-      final int prime = 31;
-      int result = 1;
-      result =
-          prime * result + ((gadgetUri == null) ? 0 : gadgetUri.hashCode());
-      result =
-          prime * result + ((serviceName == null) ? 0 : serviceName.hashCode());
-      return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-      if (this == obj) return true;
-      if (obj == null) return false;
-      if (getClass() != obj.getClass()) return false;
-      final ProviderKey other = (ProviderKey) obj;
-      if (gadgetUri == null) {
-        if (other.gadgetUri != null) return false;
-      } else if (!gadgetUri.equals(other.gadgetUri)) return false;
-      if (serviceName == null) {
-        if (other.serviceName != null) return false;
-      } else if (!serviceName.equals(other.serviceName)) return false;
-      return true;
-    }
-  }
-
-  public static class ProviderInfo {
-    private OAuthServiceProvider provider;
-    private HttpMethod httpMethod;
-    private SignatureType signatureType;
-    private OAuthParamLocation paramLocation;
-
-    public OAuthParamLocation getParamLocation() {
-      return paramLocation;
-    }
-    public void setParamLocation(OAuthParamLocation paramLocation) {
-      this.paramLocation = paramLocation;
-    }
-    public OAuthServiceProvider getProvider() {
-      return provider;
-    }
-    public void setProvider(OAuthServiceProvider provider) {
-      this.provider = provider;
-    }
-    public HttpMethod getHttpMethod() {
-      return httpMethod;
-    }
-    public void setHttpMethod(HttpMethod httpMethod) {
-      this.httpMethod = httpMethod;
-    }
-    public SignatureType getSignatureType() {
-      return signatureType;
-    }
-    public void setSignatureType(SignatureType signatureType) {
-      this.signatureType = signatureType;
-    }
-  }
-
-  public static class TokenKey {
-    private String userId;
-    private String gadgetUri;
-    private long moduleId;
-    private String tokenName;
-    private String serviceName;
-
-    public String getUserId() {
-      return userId;
-    }
-    public void setUserId(String userId) {
-      this.userId = userId;
-    }
-    public String getGadgetUri() {
-      return gadgetUri;
-    }
-    public void setGadgetUri(String gadgetUri) {
-      this.gadgetUri = gadgetUri;
-    }
-    public long getModuleId() {
-      return moduleId;
-    }
-    public void setModuleId(long moduleId) {
-      this.moduleId = moduleId;
-    }
-    public String getTokenName() {
-      return tokenName;
-    }
-    public void setTokenName(String tokenName) {
-      this.tokenName = tokenName;
-    }
-    public String getServiceName() {
-      return serviceName;
-    }
-    public void setServiceName(String serviceName) {
-      this.serviceName = serviceName;
-    }
-
-    @Override
-    public int hashCode() {
-      final int prime = 31;
-      int result = 1;
-      result =
-          prime * result + ((gadgetUri == null) ? 0 : gadgetUri.hashCode());
-      result = prime * result + (int) (moduleId ^ (moduleId >>> 32));
-      result =
-          prime * result + ((serviceName == null) ? 0 : serviceName.hashCode());
-      result =
-          prime * result + ((tokenName == null) ? 0 : tokenName.hashCode());
-      result = prime * result + ((userId == null) ? 0 : userId.hashCode());
-      return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-      if (this == obj) return true;
-      if (obj == null) return false;
-      if (getClass() != obj.getClass()) return false;
-      final TokenKey other = (TokenKey) obj;
-      if (gadgetUri == null) {
-        if (other.gadgetUri != null) return false;
-      } else if (!gadgetUri.equals(other.gadgetUri)) return false;
-      if (moduleId != other.moduleId) return false;
-      if (serviceName == null) {
-        if (other.serviceName != null) return false;
-      } else if (!serviceName.equals(other.serviceName)) return false;
-      if (tokenName == null) {
-        if (other.tokenName != null) return false;
-      } else if (!tokenName.equals(other.tokenName)) return false;
-      if (userId == null) {
-        if (other.userId != null) return false;
-      } else if (!userId.equals(other.userId)) return false;
-      return true;
-    }
-  }
-
   public static class TokenInfo {
-    private String accessToken;
-    private String tokenSecret;
+    private final String accessToken;
+    private final String tokenSecret;
     public TokenInfo(String token, String secret) {
       accessToken = token;
       tokenSecret = secret;
@@ -355,4 +89,41 @@
       return tokenSecret;
     }
   }
+
+  /**
+   * Retrieve OAuth consumer to use for requests.  The returned consumer is ready to use for signed
+   * fetch requests.
+   * 
+   * @param securityToken token for user/gadget making request.
+   * @param serviceName gadget's nickname for the service being accessed.
+   * @param provider OAuth service provider info to be inserted into the returned consumer.
+   * 
+   * @throws GadgetException if no OAuth consumer can be found (e.g. no consumer key can be used.)
+   */
+  public ConsumerInfo getConsumerKeyAndSecret(SecurityToken securityToken, String serviceName,
+      OAuthServiceProvider provider) throws GadgetException;
+
+  /**
+   * Retrieve OAuth access token to use for the request.
+   * @param securityToken token for user/gadget making request.
+   * @param consumerInfo OAuth consumer that will be used for the request.
+   * @param serviceName gadget's nickname for the service being accessed.
+   * @param tokenName gadget's nickname for the token to use.
+   * @return the token and secret, or null if none exist
+   * @throws GadgetException if an error occurs during lookup
+   */
+  public TokenInfo getTokenInfo(SecurityToken securityToken, ConsumerInfo consumerInfo,
+      String serviceName, String tokenName) throws GadgetException;
+
+  /**
+   * Set the access token for the given user/gadget/service/token
+   */
+  public void setTokenInfo(SecurityToken securityToken, ConsumerInfo consumerInfo, String serviceName,
+      String tokenName, TokenInfo tokenInfo) throws GadgetException;
+
+  /**
+   * Remove the access token for the given user/gadget/service/token
+   */
+  public void removeToken(SecurityToken securityToken, ConsumerInfo consumerInfo,
+      String serviceName, String tokenName) throws GadgetException;
 }

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/HttpPreloader.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/HttpPreloader.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/HttpPreloader.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/HttpPreloader.java Tue Sep  9 18:50:41 2008
@@ -71,8 +71,7 @@
       // TODO: This should be extracted into a common helper that takes any
       // org.apache.shindig.gadgets.spec.RequestAuthenticationInfo.
       HttpRequest request = new HttpRequest(Uri.fromJavaUri(preload.getHref()))
-            .setSignOwner(preload.isSignOwner())
-            .setSignViewer(preload.isSignViewer())
+            .setOAuthArguments(new OAuthArguments(preload))
             .setContainer(context.getContainer())
             .setSecurityToken(context.getToken())
             .setGadget(Uri.fromJavaUri(context.getUrl()));
@@ -82,11 +81,8 @@
           response = fetcher.get().fetch(request);
           break;
         case SIGNED:
-          response = fetcher.getSigningFetcher(context.getToken()).fetch(request);
-          break;
         case OAUTH:
-          response = fetcher.getOAuthFetcher(context.getToken(), new OAuthArguments(preload))
-              .fetch(request);
+          response = fetcher.getOAuthFetcher(request).fetch(request);
           break;
       }
       return new HttpPreloadData(response);

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HttpGuiceModule.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HttpGuiceModule.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HttpGuiceModule.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HttpGuiceModule.java Tue Sep  9 18:50:41 2008
@@ -33,8 +33,8 @@
       super.configure();
   }
 
-  public HttpGuiceModule(Properties properties) {
-    super(properties);
+  public HttpGuiceModule(Properties properties, String oauthConfigJson) {
+    super(properties, oauthConfigJson);
   }
 
   public HttpGuiceModule() {

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/MakeRequestHandler.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/MakeRequestHandler.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/MakeRequestHandler.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/MakeRequestHandler.java Tue Sep  9 18:50:41 2008
@@ -56,8 +56,6 @@
   public static final String METHOD_PARAM = "httpMethod";
   public static final String HEADERS_PARAM = "headers";
   public static final String NOCACHE_PARAM = "nocache";
-  public static final String SIGN_VIEWER = "signViewer";
-  public static final String SIGN_OWNER = "signOwner";
   public static final String CONTENT_TYPE_PARAM = "contentType";
   public static final String NUM_ENTRIES_PARAM = "numEntries";
   public static final String DEFAULT_NUM_ENTRIES = "3";
@@ -82,14 +80,17 @@
     // Figure out whether authentication is required
     Auth auth = Auth.parse(getParameter(request, AUTHZ_PARAM, ""));
     SecurityToken authToken = null;
+    OAuthArguments oauthArguments = null;
     if (auth != Auth.NONE) {
       authToken = extractAndValidateToken(request);
+      oauthArguments = new OAuthArguments(auth, request);
     }
 
     rcr.setSecurityToken(authToken);
+    rcr.setOAuthArguments(oauthArguments);
 
     // Build the chain of fetchers that will handle the request
-    HttpFetcher fetcher = getHttpFetcher(auth, authToken, request);
+    HttpFetcher fetcher = getHttpFetcher(auth, rcr);
 
     // Serialize the response
     HttpResponse results = fetcher.fetch(rcr);
@@ -140,12 +141,6 @@
 
     req.setIgnoreCache("1".equals(request.getParameter(NOCACHE_PARAM)));
 
-    if (request.getParameter(SIGN_VIEWER) != null) {
-      req.setSignViewer(Boolean.parseBoolean(request.getParameter(SIGN_VIEWER)));
-    }
-    if (request.getParameter(SIGN_OWNER) != null) {
-      req.setSignOwner(Boolean.parseBoolean(request.getParameter(SIGN_OWNER)));
-    }
     if (request.getParameter(GADGET_PARAM) != null) {
       req.setGadget(Uri.parse(request.getParameter(GADGET_PARAM)));
     }
@@ -179,17 +174,13 @@
    * Whatever we do needs to return a reference to the OAuthFetcher, if it is
    * present, so we can pull data out as needed.
    */
-  private HttpFetcher getHttpFetcher(Auth auth, SecurityToken token, HttpServletRequest request)
-      throws GadgetException {
+  private HttpFetcher getHttpFetcher(Auth auth, HttpRequest request) throws GadgetException {
     switch (auth) {
       case NONE:
         return contentFetcherFactory.get();
       case SIGNED:
-        // TODO: Remove token from signature and use what's on the request object instead.
-        return contentFetcherFactory.getSigningFetcher(token);
       case OAUTH:
-        // TODO: Remove token from signature, return what's on the request object.
-        return contentFetcherFactory.getOAuthFetcher(token, new OAuthArguments(request));
+        return contentFetcherFactory.getOAuthFetcher(request);
       default:
         return contentFetcherFactory.get();
     }

Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java Tue Sep  9 18:50:41 2008
@@ -305,7 +305,8 @@
         "</Module>";
     expect(fetcher.fetch(SPEC_REQUEST))
         .andReturn(new HttpResponse(gadgetXml));
-    expect(fetcherFactory.getSigningFetcher(BASIC_CONTEXT.getToken()))
+    expect(fetcherFactory.getOAuthFetcher(
+        isA(HttpRequest.class)))
         .andReturn(fetcher);
     expect(fetcher.fetch(preloadRequest))
         .andReturn(new HttpResponse(preloadData));
@@ -332,7 +333,7 @@
     expect(fetcher.fetch(SPEC_REQUEST))
         .andReturn(new HttpResponse(gadgetXml));
     expect(fetcherFactory.getOAuthFetcher(
-        isA(SecurityToken.class), isA(OAuthArguments.class)))
+        isA(HttpRequest.class)))
         .andReturn(fetcher);
     expect(fetcher.fetch(preloadRequest))
         .andReturn(new HttpResponse(preloadData));

Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetTestFixture.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetTestFixture.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetTestFixture.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetTestFixture.java Tue Sep  9 18:50:41 2008
@@ -39,7 +39,6 @@
   public final GadgetServer gadgetServer;
   public final ContentFetcherFactory fetcherFactory = mock(ContentFetcherFactory.class);
   public final HttpFetcher fetcher = mock(HttpFetcher.class);
-  public final SigningFetcher signingFetcher = mock(SigningFetcher.class);
   public final OAuthFetcher oauthFetcher = mock(OAuthFetcher.class);
   public final ContentFetcherFactory contentFetcherFactory = mock(ContentFetcherFactory.class);
   public final GadgetBlacklist blacklist = mock(GadgetBlacklist.class);

Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpRequestTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpRequestTest.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpRequestTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpRequestTest.java Tue Sep  9 18:50:41 2008
@@ -23,6 +23,7 @@
 
 import org.apache.shindig.auth.AnonymousSecurityToken;
 import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.gadgets.oauth.OAuthArguments;
 
 import org.apache.commons.io.IOUtils;
 import org.junit.Test;
@@ -85,6 +86,9 @@
 
   @Test
   public void copyCtorCopiesAllFields() {
+    OAuthArguments oauthArguments = new OAuthArguments();
+    oauthArguments.setSignOwner(false);
+    oauthArguments.setSignViewer(true);
     HttpRequest request = new HttpRequest(DEFAULT_URI)
         .setCacheTtl(100)
         .addHeader(TEST_HEADER_KEY, TEST_HEADER_VALUE)
@@ -94,8 +98,7 @@
         .setPostBody(POST_BODY.getBytes())
         .setRewriteMimeType("text/fake")
         .setSecurityToken(new AnonymousSecurityToken())
-        .setSignOwner(false)
-        .setSignViewer(false);
+        .setOAuthArguments(oauthArguments);
 
     HttpRequest request2 = new HttpRequest(request).setUri(Uri.parse("http://example.org/foo"));
 
@@ -107,7 +110,9 @@
     assertEquals(request.getPostBodyAsString(), request2.getPostBodyAsString());
     assertEquals(request.getRewriteMimeType(), request2.getRewriteMimeType());
     assertEquals(request.getSecurityToken(), request2.getSecurityToken());
-    assertEquals(request.getSignOwner(), request2.getSignOwner());
-    assertEquals(request.getSignViewer(), request2.getSignViewer());
+    assertEquals(request.getOAuthArguments().getSignOwner(),
+        request2.getOAuthArguments().getSignOwner());
+    assertEquals(request.getOAuthArguments().getSignViewer(),
+        request2.getOAuthArguments().getSignViewer());
   }
 }

Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreTest.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreTest.java Tue Sep  9 18:50:41 2008
@@ -18,330 +18,122 @@
  */
 package org.apache.shindig.gadgets.oauth;
 
-import static org.easymock.EasyMock.eq;
-import static org.easymock.EasyMock.expect;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
 
-import org.apache.shindig.auth.SecurityTokenDecoder;
-
-import junit.framework.TestCase;
-
-import net.oauth.OAuthAccessor;
+import net.oauth.OAuthConsumer;
 import net.oauth.OAuthServiceProvider;
 import net.oauth.signature.RSA_SHA1;
 
-import org.easymock.classextension.EasyMock;
-import org.easymock.classextension.IMocksControl;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class BasicOAuthStoreTest extends TestCase {
-
-  private IMocksControl control;
-  private Map<OAuthStore.ProviderKey, OAuthStore.ConsumerKeyAndSecret>
-      mockConsumerInfos;
-  private Map<OAuthStore.TokenKey, OAuthStore.TokenInfo> mockTokens;
-  private BasicOAuthStore noDefaultStore;
-  private BasicOAuthStore withDefaultStore;
-  private String defaultKey = "defaultkey";
-  private String defaultSecret = "defaultsecret";  // not quite a PKCS8-encoded
-                                                   // RSA key, but that's ok
-
-  @Override
-  @SuppressWarnings("unchecked")
-  protected void setUp() throws Exception {
-    super.setUp();
-    control = EasyMock.createStrictControl();
-    mockConsumerInfos = control.createMock(
-        new HashMap<OAuthStore.ProviderKey,
-                    OAuthStore.ConsumerKeyAndSecret>().getClass());
-    mockTokens = control.createMock(
-        new HashMap<OAuthStore.TokenKey, OAuthStore.TokenInfo>().getClass());
-
-    noDefaultStore = new BasicOAuthStore();
-    noDefaultStore.setHashMapsForTesting(mockConsumerInfos, mockTokens);
-
-    withDefaultStore = new BasicOAuthStore(defaultKey, defaultSecret);
-    withDefaultStore.setHashMapsForTesting(mockConsumerInfos, mockTokens);
+import org.apache.shindig.common.testing.FakeGadgetToken;
+import org.apache.shindig.gadgets.GadgetException;
+import org.apache.shindig.gadgets.oauth.BasicOAuthStoreConsumerKeyAndSecret.KeyType;
+import org.apache.shindig.gadgets.oauth.OAuthStore.ConsumerInfo;
+import org.apache.shindig.gadgets.oauth.OAuthStore.TokenInfo;
+import org.junit.Before;
+import org.junit.Test;
+
+public class BasicOAuthStoreTest {
+  
+  private static final String SAMPLE_FILE =
+    "{" +
+    "'http://localhost:8080/gadgets/files/samplecontainer/examples/oauth.xml' : {" +
+    "'' : {" + 
+    "'consumer_key' : 'gadgetConsumer'," + 
+    "'consumer_secret' : 'gadgetSecret'," + 
+    "'key_type' : 'HMAC_SYMMETRIC'" +
+    "}" +
+    "}," +
+    "'http://rsagadget/test.xml' : {" +
+    "'' : {" + 
+    "'consumer_key' : 'rsaconsumer'," + 
+    "'consumer_secret' : 'rsaprivate'," + 
+    "'key_type' : 'RSA_PRIVATE'" +
+    "}" +
+    "}" +
+
+    "}";
+
+  private BasicOAuthStore store;
+  
+  @Before
+  public void setUp() throws Exception {
+    store = new BasicOAuthStore();
+    store.initFromConfigString(SAMPLE_FILE);
   }
-
-  public void testGetOAuthAccessor() throws Exception {
-    OAuthStore.TokenKey tokenKey = new OAuthStore.TokenKey();
-    tokenKey.setGadgetUri("http://foo.bar.com/gadget.xml");
-    tokenKey.setModuleId(2348709L);
-    tokenKey.setUserId("testuser");
-    tokenKey.setServiceName("testservice");
-    tokenKey.setTokenName("testtoken");
-
-    OAuthStore.TokenInfo tokenInfo = new OAuthStore.TokenInfo("accesstoken",
-                                                              "tokensecret");
-
-    OAuthStore.ProviderKey provKey = new OAuthStore.ProviderKey();
-    provKey.setGadgetUri(tokenKey.getGadgetUri());
-    provKey.setServiceName(tokenKey.getServiceName());
-
-    OAuthServiceProvider provider = new OAuthServiceProvider(
-        "request", "authorize", "access");
-
-    OAuthStore.ProviderInfo info = new BasicOAuthStore.ProviderInfo();
-
-    info.setHttpMethod(OAuthStore.HttpMethod.GET);
-    info.setSignatureType(OAuthStore.SignatureType.HMAC_SHA1);
-    info.setProvider(provider);
-    info.setParamLocation(OAuthStore.OAuthParamLocation.AUTH_HEADER);
-
-    ////////////////////////////////////////////////////////////////////////////
-    // first, the case where we don't have a consumer key/secret
-
-    control.checkOrder(false);
-
-    expect(mockConsumerInfos.get(eq(provKey))).andReturn(null).once();
-    expect(mockTokens.get(tokenKey)).andReturn(tokenInfo);
-
-    control.replay();
-
-    OAuthStore.AccessorInfo accessorInfo =
-        withDefaultStore.getOAuthAccessor(tokenKey, info);
-
-    control.verify();
-
-    OAuthAccessor accessor = accessorInfo.getAccessor();
-
-    assertSame(info.getHttpMethod(), accessorInfo.getHttpMethod());
-    assertSame(OAuthStore.OAuthParamLocation.AUTH_HEADER,
-               accessorInfo.getParamLocation());
-
-    assertEquals("accesstoken", accessor.accessToken);
-    assertEquals("tokensecret", accessor.tokenSecret);
-    assertEquals(defaultKey, accessor.consumer.consumerKey);
-    assertNull(accessor.consumer.consumerSecret);
-    assertEquals(defaultSecret, accessor.consumer
-        .getProperty(RSA_SHA1.PRIVATE_KEY));
-    assertEquals("access", accessor.consumer.serviceProvider.accessTokenURL);
-    assertEquals("request", accessor.consumer.serviceProvider.requestTokenURL);
-    assertEquals("authorize",
-                 accessor.consumer.serviceProvider.userAuthorizationURL);
-
-    // now for the one that doesn't have default keys set
-    control.reset();
-    control.checkOrder(false);
-
-    expect(mockConsumerInfos.get(eq(provKey))).andReturn(null).once();
-    expect(mockTokens.get(tokenKey)).andStubReturn(tokenInfo);
-
-    control.replay();
-
-    try {
-      accessorInfo = noDefaultStore.getOAuthAccessor(tokenKey, info);
-      fail("expected exception, but didn't get it");
-    } catch (OAuthNoDataException e) {
-      // this is expected
-    }
-
-    control.verify();
-
-    ////////////////////////////////////////////////////////////////////////////
-    // now the case where we have negotiated an HMAC consumer secret
-
-    OAuthStore.ConsumerKeyAndSecret kas =
-        new OAuthStore.ConsumerKeyAndSecret("negotiatedkey",
-                                            "negotiatedsecret",
-                                            OAuthStore.KeyType.HMAC_SYMMETRIC);
-
-    info.setParamLocation(OAuthStore.OAuthParamLocation.POST_BODY);
-
-    control.reset();
-    control.checkOrder(false);
-
-    expect(mockConsumerInfos.get(eq(provKey))).andReturn(kas).once();
-    expect(mockTokens.get(tokenKey)).andReturn(tokenInfo);
-
-    control.replay();
-
-    accessorInfo = noDefaultStore.getOAuthAccessor(tokenKey, info);
-
-    control.verify();
-
-    assertSame(OAuthStore.OAuthParamLocation.POST_BODY,
-               accessorInfo.getParamLocation());
-
-    accessor = accessorInfo.getAccessor();
-
-    assertEquals("accesstoken", accessor.accessToken);
-    assertEquals("tokensecret", accessor.tokenSecret);
-    assertEquals("negotiatedkey", accessor.consumer.consumerKey);
-    assertEquals("negotiatedsecret", accessor.consumer.consumerSecret);
-    assertEquals("access", accessor.consumer.serviceProvider.accessTokenURL);
-    assertEquals("request", accessor.consumer.serviceProvider.requestTokenURL);
-    assertEquals("authorize",
-                 accessor.consumer.serviceProvider.userAuthorizationURL);
-
-    // the store with fallback keys should do the same thing
-
-    control.reset();
-    control.checkOrder(false);
-
-    expect(mockConsumerInfos.get(eq(provKey))).andReturn(kas).once();
-    expect(mockTokens.get(tokenKey)).andReturn(tokenInfo);
-
-    control.replay();
-
-    accessorInfo = withDefaultStore.getOAuthAccessor(tokenKey, info);
-
-    control.verify();
-
-    accessor = accessorInfo.getAccessor();
-
-    assertEquals("accesstoken", accessor.accessToken);
-    assertEquals("tokensecret", accessor.tokenSecret);
-    assertEquals("negotiatedkey", accessor.consumer.consumerKey);
-    assertEquals("negotiatedsecret", accessor.consumer.consumerSecret);
-    assertEquals("access", accessor.consumer.serviceProvider.accessTokenURL);
-    assertEquals("request", accessor.consumer.serviceProvider.requestTokenURL);
-    assertEquals("authorize",
-                 accessor.consumer.serviceProvider.userAuthorizationURL);
-
-    ////////////////////////////////////////////////////////////////////////////
-    // now the case where we have negotiated an RSA consumer key
-
-    kas = new OAuthStore.ConsumerKeyAndSecret("negotiatedkey",
-                                              "negotiatedsecret",
-                                              OAuthStore.KeyType.RSA_PRIVATE);
-
-    control.reset();
-    control.checkOrder(false);
-
-    expect(mockConsumerInfos.get(eq(provKey))).andReturn(kas).once();
-    expect(mockTokens.get(tokenKey)).andReturn(tokenInfo);
-
-    control.replay();
-
-    accessorInfo = noDefaultStore.getOAuthAccessor(tokenKey, info);
-
-    control.verify();
-
-    accessor = accessorInfo.getAccessor();
-
-    assertEquals("accesstoken", accessor.accessToken);
-    assertEquals("tokensecret", accessor.tokenSecret);
-    assertEquals("negotiatedkey", accessor.consumer.consumerKey);
-    assertNull(accessor.consumer.consumerSecret);
-    assertEquals("negotiatedsecret",
-                 accessor.consumer.getProperty(RSA_SHA1.PRIVATE_KEY));
-    assertEquals("access", accessor.consumer.serviceProvider.accessTokenURL);
-    assertEquals("request", accessor.consumer.serviceProvider.requestTokenURL);
-    assertEquals("authorize",
-                 accessor.consumer.serviceProvider.userAuthorizationURL);
-
-    // store with fallback keys should do the same
-
-    control.reset();
-    control.checkOrder(false);
-
-    expect(mockConsumerInfos.get(eq(provKey))).andReturn(kas).once();
-    expect(mockTokens.get(tokenKey)).andReturn(tokenInfo);
-
-    control.replay();
-
-    accessorInfo = noDefaultStore.getOAuthAccessor(tokenKey, info);
-
-    control.verify();
-
-    accessor = accessorInfo.getAccessor();
-
-    assertEquals("accesstoken", accessor.accessToken);
-    assertEquals("tokensecret", accessor.tokenSecret);
-    assertEquals("negotiatedkey", accessor.consumer.consumerKey);
-    assertNull(accessor.consumer.consumerSecret);
-    assertEquals("negotiatedsecret",
-                 accessor.consumer.getProperty(RSA_SHA1.PRIVATE_KEY));
-    assertEquals("access", accessor.consumer.serviceProvider.accessTokenURL);
-    assertEquals("request", accessor.consumer.serviceProvider.requestTokenURL);
-    assertEquals("authorize",
-                 accessor.consumer.serviceProvider.userAuthorizationURL);
-
-    ////////////////////////////////////////////////////////////////////////////
-    // now, test some error conditions: no token found
-
-    control.reset();
-    control.checkOrder(false);
-
-    expect(mockConsumerInfos.get(eq(provKey))).andStubReturn(kas);
-    expect(mockTokens.get(tokenKey)).andReturn(null);
-
-    control.replay();
-
-    accessorInfo = noDefaultStore.getOAuthAccessor(tokenKey, info);
-
-    control.verify();
-
-    assertNull(accessorInfo.getAccessor().accessToken);
-    assertNull(accessorInfo.getAccessor().requestToken);
-
-    // same with the store with fallback keys
-
-    control.reset();
-    control.checkOrder(false);
-
-    expect(mockConsumerInfos.get(eq(provKey))).andStubReturn(kas);
-    expect(mockTokens.get(tokenKey)).andReturn(null);
-
-    control.replay();
-
-    accessorInfo = withDefaultStore.getOAuthAccessor(tokenKey, info);
-    assertNull(accessorInfo.getAccessor().accessToken);
-    assertNull(accessorInfo.getAccessor().requestToken);
-
-    control.verify();
-
+  
+  @Test
+  public void testInit() throws Exception {
+    FakeGadgetToken t = new FakeGadgetToken();
+    t.setAppUrl("http://localhost:8080/gadgets/files/samplecontainer/examples/oauth.xml");
+    OAuthServiceProvider provider = new OAuthServiceProvider("req", "authorize", "access");
+    ConsumerInfo consumerInfo = store.getConsumerKeyAndSecret(t, "", provider);
+    OAuthConsumer consumer = consumerInfo.getConsumer();
+    assertEquals("gadgetConsumer", consumer.consumerKey);
+    assertEquals("gadgetSecret", consumer.consumerSecret);
+    assertEquals("HMAC-SHA1", consumer.getProperty("oauth_signature_method"));
+    assertEquals(provider, consumer.serviceProvider);
+    assertNull(consumerInfo.getKeyName());
+
+    t.setAppUrl("http://rsagadget/test.xml");
+    consumerInfo = store.getConsumerKeyAndSecret(t, "", provider);
+    consumer = consumerInfo.getConsumer();
+    assertEquals("rsaconsumer", consumer.consumerKey);
+    assertNull(consumer.consumerSecret);
+    assertEquals("RSA-SHA1", consumer.getProperty("oauth_signature_method"));
+    assertEquals(provider, consumer.serviceProvider);
+    assertEquals("rsaprivate", consumer.getProperty(RSA_SHA1.PRIVATE_KEY));
+    assertNull(consumerInfo.getKeyName());
   }
-
-  public void testSetOAuthConsumerKeyAndSecret() throws Exception {
-    OAuthStore.ProviderKey provKey = new OAuthStore.ProviderKey();
-    provKey.setGadgetUri("http://foo.bar.com/gadget.xml");
-    provKey.setServiceName("testservice");
-
-    OAuthStore.ConsumerKeyAndSecret kas =
-        new OAuthStore.ConsumerKeyAndSecret("consumerkey",
-                                            "consumersecret",
-                                            OAuthStore.KeyType.HMAC_SYMMETRIC);
-
-    OAuthServiceProvider provider = new OAuthServiceProvider(
-        "request", "authorize", "access");
-
-    OAuthStore.ProviderInfo info = new OAuthStore.ProviderInfo();
-    info.setHttpMethod(OAuthStore.HttpMethod.GET);
-    info.setSignatureType(OAuthStore.SignatureType.HMAC_SHA1);
-    info.setProvider(provider);
-
-    expect(mockConsumerInfos.put(provKey, kas)).andReturn(kas).once();
-
-    control.replay();
-
-    noDefaultStore.setOAuthConsumerKeyAndSecret(provKey, kas);
-
-    control.verify();
-
+  
+  @Test
+  public void testGetAndSetAndRemoveToken() {
+    FakeGadgetToken t = new FakeGadgetToken();
+    ConsumerInfo consumer = new ConsumerInfo(null, null);
+    t.setAppUrl("http://localhost:8080/gadgets/files/samplecontainer/examples/oauth.xml");
+    t.setViewerId("viewer-one");
+    assertNull(store.getTokenInfo(t, consumer, "", ""));
+    
+    TokenInfo info = new TokenInfo("token", "secret");
+    store.setTokenInfo(t, consumer, "service", "token", info);
+    
+    info = store.getTokenInfo(t, consumer, "service", "token");
+    assertEquals("token", info.getAccessToken());
+    assertEquals("secret", info.getTokenSecret());
+    
+    FakeGadgetToken t2 = new FakeGadgetToken();
+    t2.setAppUrl("http://localhost:8080/gadgets/files/samplecontainer/examples/oauth.xml");
+    t2.setViewerId("viewer-two");
+    assertNull(store.getTokenInfo(t2, consumer, "service", "token"));
+    
+    store.removeToken(t, consumer, "service", "token");
+    assertNull(store.getTokenInfo(t, consumer, "service", "token"));
   }
+  
+  @Test
+  public void testDefaultKey() throws Exception {
+    FakeGadgetToken t = new FakeGadgetToken();
+    t.setAppUrl("http://localhost:8080/not-in-store.xml");
+    OAuthServiceProvider provider = new OAuthServiceProvider("req", "authorize", "access");
 
-  public void testSetTokenAndSecret() throws Exception {
-    OAuthStore.TokenKey tokenKey = new OAuthStore.TokenKey();
-    tokenKey.setGadgetUri("http://foo.bar.com/gadget.xml");
-    tokenKey.setServiceName("testservice");
-    tokenKey.setModuleId(9843243278L);
-    tokenKey.setTokenName("testtoken");
-    tokenKey.setUserId("test user");
-
-    OAuthStore.TokenInfo tokenInfo =
-        new OAuthStore.TokenInfo(SecurityTokenDecoder.SECURITY_TOKEN_NAME, "secret");
-
-
-    expect(mockTokens.put(tokenKey, tokenInfo)).andReturn(null);
-
-    control.replay();
-
-    noDefaultStore.setTokenAndSecret(tokenKey, tokenInfo);
-
-    control.verify();
+    try {
+      store.getConsumerKeyAndSecret(t, "", provider);
+      fail();
+    } catch (GadgetException e) {
+      // good
+    }
+    
+    BasicOAuthStoreConsumerKeyAndSecret cks = new BasicOAuthStoreConsumerKeyAndSecret(
+        "somekey", "default", KeyType.RSA_PRIVATE, "keyname");
+    store.setDefaultKey(cks);
+    
+    ConsumerInfo consumer = store.getConsumerKeyAndSecret(t, "", provider);
+    assertEquals("somekey", consumer.getConsumer().consumerKey);
+    assertNull(consumer.getConsumer().consumerSecret);
+    assertEquals("RSA-SHA1", consumer.getConsumer().getProperty("oauth_signature_method"));
+    assertEquals("default", consumer.getConsumer().getProperty(RSA_SHA1.PRIVATE_KEY));
+    assertEquals(provider, consumer.getConsumer().serviceProvider);
+    assertEquals("keyname", consumer.getKeyName());
   }
 }

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=693675&r1=693674&r2=693675&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 Tue Sep  9 18:50:41 2008
@@ -24,6 +24,7 @@
 import net.oauth.OAuthServiceProvider;
 import net.oauth.OAuthValidator;
 import net.oauth.SimpleOAuthValidator;
+import net.oauth.signature.RSA_SHA1;
 
 import org.apache.shindig.common.crypto.Crypto;
 import org.apache.shindig.gadgets.GadgetException;
@@ -31,7 +32,7 @@
 import org.apache.shindig.gadgets.http.HttpRequest;
 import org.apache.shindig.gadgets.http.HttpResponse;
 import org.apache.shindig.gadgets.http.HttpResponseBuilder;
-import org.apache.shindig.gadgets.oauth.OAuthStore.OAuthParamLocation;
+import org.apache.shindig.gadgets.oauth.AccessorInfo.OAuthParamLocation;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -59,6 +60,9 @@
 
   public final static String CONSUMER_KEY = "consumer";
   public final static String CONSUMER_SECRET = "secret";
+  
+  public final static String SIGNED_FETCH_CONSUMER_KEY = "signedfetch";
+
 
   private static class TokenState {
     String tokenSecret;
@@ -112,7 +116,8 @@
    */
   private final HashMap<String, TokenState> tokenState;
   private final OAuthValidator validator;
-  private final OAuthConsumer consumer;
+  private final OAuthConsumer signedFetchConsumer;
+  private final OAuthConsumer oauthConsumer;
 
   private boolean throttled;
   private boolean vagueErrors;
@@ -128,14 +133,26 @@
   public FakeOAuthServiceProvider() {
     OAuthServiceProvider provider = new OAuthServiceProvider(
         REQUEST_TOKEN_URL, APPROVAL_URL, ACCESS_TOKEN_URL);
-    consumer = new OAuthConsumer(
-        null, CONSUMER_KEY, CONSUMER_SECRET, provider);
+    
+    signedFetchConsumer = new OAuthConsumer(null, null, null, null);
+    signedFetchConsumer.setProperty(RSA_SHA1.X509_CERTIFICATE, OAuthFetcherTest.CERTIFICATE_TEXT);
+
+    oauthConsumer = new OAuthConsumer(null, CONSUMER_KEY, CONSUMER_SECRET, provider);
+    
     tokenState = new HashMap<String, TokenState>();
     validator = new SimpleOAuthValidator();
     vagueErrors = false;
     validParamLocations = new HashSet<OAuthParamLocation>();
     validParamLocations.add(OAuthParamLocation.URI_QUERY);
   }
+  
+  public OAuthConsumer getConsumer(String consumerKey) {
+    if (consumerKey.equals("signedfetch")) {
+      return signedFetchConsumer;
+    } else {
+      return oauthConsumer;
+    }
+  }
 
   public void setVagueErrors(boolean vagueErrors) {
     this.vagueErrors = vagueErrors;
@@ -183,7 +200,12 @@
       throws Exception {
     OAuthMessage message = parseMessage(request).message;
     String requestConsumer = message.getParameter(OAuth.OAUTH_CONSUMER_KEY);
-    if (!CONSUMER_KEY.equals(requestConsumer)) {
+    OAuthConsumer consumer;
+    if (CONSUMER_KEY.equals(requestConsumer)) {
+      consumer = oauthConsumer;
+    } else if (SIGNED_FETCH_CONSUMER_KEY.equals(requestConsumer)) {
+      consumer = signedFetchConsumer;
+    } else {
       return makeOAuthProblemReport(
           "consumer_key_unknown", "invalid consumer: " + requestConsumer);
     }
@@ -238,7 +260,7 @@
         }
       }
     }
-    
+        
     // Parse authorization header
     if (validParamLocations.contains(OAuthParamLocation.AUTH_HEADER)) {
       String aznHeader = request.getHeader("Authorization");
@@ -253,15 +275,21 @@
     }
     
     // Parse body
-    if (validParamLocations.contains(OAuthParamLocation.POST_BODY)) {
-      String body = request.getPostBodyAsString();
-      if (request.getMethod().equals("POST")) {
-        String type = request.getHeader("Content-Type");
-        if (!"application/x-www-form-urlencoded".equals(type)) {
-          throw new RuntimeException("Wrong content-type header: " + type);
-        }
-        info.body = body;
-        params.addAll(OAuth.decodeForm(request.getPostBodyAsString()));
+    String body = request.getPostBodyAsString();
+    if (request.getMethod().equals("POST")) {
+      String type = request.getHeader("Content-Type");
+      if (!"application/x-www-form-urlencoded".equals(type)) {
+        throw new RuntimeException("Wrong content-type header: " + type);
+      }
+      info.body = body;
+      params.addAll(OAuth.decodeForm(request.getPostBodyAsString()));
+    }
+    
+    // If we're not configured to pass oauth parameters in the post body, double check
+    // that they didn't end up there.
+    if (!validParamLocations.contains(OAuthParamLocation.POST_BODY)) {
+      if (body.contains("oauth_")) {
+        throw new RuntimeException("Found unexpected post body data" + body);
       }
     }
     
@@ -359,7 +387,7 @@
   public TokenPair getPreapprovedToken(String userData) {
     String requestToken = Crypto.getRandomString(16);
     String requestTokenSecret = Crypto.getRandomString(16);
-    TokenState state = new TokenState(requestTokenSecret, consumer);
+    TokenState state = new TokenState(requestTokenSecret, oauthConsumer);
     state.setState(TokenState.State.APPROVED);
     state.setUserData(userData);
     tokenState.put(requestToken, state);
@@ -391,7 +419,7 @@
     if (state.getState() != TokenState.State.APPROVED) {
       throw new Exception("Token not approved");
     }
-    OAuthAccessor accessor = new OAuthAccessor(consumer);
+    OAuthAccessor accessor = new OAuthAccessor(oauthConsumer);
     accessor.requestToken = requestToken;
     accessor.tokenSecret = state.tokenSecret;
     message.validateMessage(accessor, validator);
@@ -409,27 +437,50 @@
   private HttpResponse handleResourceUrl(HttpRequest request)
       throws Exception {
     MessageInfo info = parseMessage(request);
-    String accessToken = info.message.getParameter("oauth_token");
-    TokenState state = tokenState.get(accessToken);
-    if (throttled) {
-      return makeOAuthProblemReport(
-          "consumer_key_refused", "exceeded quota");
-    }
-    if (state == null) {
-      return makeOAuthProblemReport(
-          "token_rejected", "Access token unknown");
-    }
-    if (state.getState() != TokenState.State.APPROVED) {
-      return makeOAuthProblemReport(
-          "token_revoked", "User revoked permissions");
+    String consumerId = info.message.getParameter("oauth_consumer_key");
+    OAuthConsumer consumer;
+    if (CONSUMER_KEY.equals(consumerId)) {
+      consumer = oauthConsumer;
+    } else if ("signedfetch".equals(consumerId)) {
+      consumer = signedFetchConsumer;
+    } else if ("container.com".equals(consumerId)) {
+      consumer = signedFetchConsumer;
+    } else {
+      return makeOAuthProblemReport("parameter_missing", "oauth_consumer_key not found");
     }
     OAuthAccessor accessor = new OAuthAccessor(consumer);
-    accessor.accessToken = accessToken;
-    accessor.tokenSecret = state.getSecret();
+    String responseBody = null;
+    if (consumer == oauthConsumer) {
+      // for OAuth, check the access token.  We skip this for signed fetch
+      String accessToken = info.message.getParameter("oauth_token");
+      TokenState state = tokenState.get(accessToken);
+      if (throttled) {
+        return makeOAuthProblemReport(
+            "consumer_key_refused", "exceeded quota");
+      }
+      if (state == null) {
+        return makeOAuthProblemReport(
+            "token_rejected", "Access token unknown");
+      }
+      if (state.getState() != TokenState.State.APPROVED) {
+        return makeOAuthProblemReport(
+            "token_revoked", "User revoked permissions");
+      }
+      accessor.accessToken = accessToken;
+      accessor.tokenSecret = state.getSecret();
+      responseBody = "User data is " + state.getUserData();
+    } else {
+      // For signed fetch, just echo back the query parameters in the body
+      responseBody = request.getUri().getQuery();
+    }
+    
+    // Check the signature
     info.message.validateMessage(accessor, validator);
+    
+    // Send back a response
     HttpResponseBuilder resp = new HttpResponseBuilder()
         .setHttpStatusCode(HttpResponse.SC_OK)
-        .setResponseString("User data is " + state.getUserData());
+        .setResponseString(responseBody);
     if (info.aznHeader != null) {
       resp.setHeader(AUTHZ_ECHO_HEADER, info.aznHeader);
     }