You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by wo...@apache.org on 2011/10/12 22:10:42 UTC

svn commit: r1182565 [2/9] - in /shindig/trunk: config/ content/samplecontainer/examples/commoncontainer/ content/samplecontainer/examples/oauth2/ features/src/main/javascript/features/core.io/ features/src/main/javascript/features/shindig.xhrwrapper/ ...

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/BasicOAuth2Message.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/BasicOAuth2Message.java?rev=1182565&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/BasicOAuth2Message.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/BasicOAuth2Message.java Wed Oct 12 20:10:39 2011
@@ -0,0 +1,219 @@
+/*
+ * 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.oauth2;
+
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.gadgets.oauth2.logger.FilteredLogger;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import com.google.common.collect.Maps;
+
+/**
+ * See {@link OAuth2Message}
+ * 
+ */
+public class BasicOAuth2Message implements OAuth2Message {
+  private final static String LOG_CLASS = BasicOAuth2Message.class.getName();
+  private final static FilteredLogger LOG = FilteredLogger
+      .getFilteredLogger(BasicOAuth2Message.LOG_CLASS);
+
+  private OAuth2Error error;
+  private final Map<String, String> params;
+  private final Map<String, String> unparsedProperties;
+
+  public BasicOAuth2Message() {
+    this.params = Maps.newHashMapWithExpectedSize(5);
+    this.unparsedProperties = Maps.newHashMapWithExpectedSize(0);
+  }
+
+  public String getAccessToken() {
+    return this.params.get(OAuth2Message.ACCESS_TOKEN);
+  }
+
+  public String getAuthorization() {
+    return this.params.get(OAuth2Message.AUTHORIZATION);
+  }
+
+  public OAuth2Error getError() {
+    if (this.error == null) {
+      final String errorParam = this.params.get(OAuth2Message.ERROR);
+      if (errorParam != null) {
+        if (OAuth2Message.INVALID_REQUEST.equalsIgnoreCase(errorParam)) {
+          this.error = OAuth2Error.SPEC_INVALID_REQUEST;
+        } else if (OAuth2Message.UNAUTHORIZED_CLIENT.equalsIgnoreCase(errorParam)) {
+          this.error = OAuth2Error.SPEC_UNAUTHORIZED_CLIENT;
+        } else if (OAuth2Message.ACCESS_DENIED.equalsIgnoreCase(errorParam)) {
+          this.error = OAuth2Error.SPEC_ACCESS_DENIED;
+        } else if (OAuth2Message.UNSUPPORTED_RESPONSE_TYPE.equalsIgnoreCase(errorParam)) {
+          this.error = OAuth2Error.SPEC_UNSUPPORTED_RESPONSE_TYPE;
+        } else if (OAuth2Message.INVALID_SCOPE.equalsIgnoreCase(errorParam)) {
+          this.error = OAuth2Error.SPEC_INVALID_SCOPE;
+        } else if (OAuth2Message.SERVER_ERROR.equalsIgnoreCase(errorParam)) {
+          this.error = OAuth2Error.SPEC_SERVER_ERROR;
+        } else if (OAuth2Message.TEMPORARILY_UNAVAILABLE.equalsIgnoreCase(errorParam)) {
+          this.error = OAuth2Error.SPEC_TEMPORARILY_UNAVAILABLE;
+        } else if (OAuth2Message.INVALID_CLIENT.equalsIgnoreCase(errorParam)) {
+          this.error = OAuth2Error.SPEC_INVALID_CLIENT;
+        } else if (OAuth2Message.INVALID_GRANT.equalsIgnoreCase(errorParam)) {
+          this.error = OAuth2Error.SPEC_INVALID_GRANT;
+        } else if (OAuth2Message.UNSUPPORTED_GRANT_TYPE.equalsIgnoreCase(errorParam)) {
+          this.error = OAuth2Error.SPEC_UNSUPPORTED_GRANT_TYPE;
+        } else {
+          this.error = OAuth2Error.UNKNOWN_PROBLEM;
+        }
+      }
+    }
+
+    return this.error;
+  }
+
+  public String getErrorDescription() {
+    return this.params.get(OAuth2Message.ERROR_DESCRIPTION);
+  }
+
+  public String getErrorUri() {
+    return this.params.get(OAuth2Message.ERROR_URI);
+  }
+
+  public String getExpiresIn() {
+    return this.params.get(OAuth2Message.EXPIRES_IN);
+  }
+
+  public String getMacAlgorithm() {
+    return this.params.get(OAuth2Message.MAC_ALGORITHM);
+  }
+
+  public String getMacSecret() {
+    return this.params.get(OAuth2Message.MAC_SECRET);
+  }
+
+  public Map<String, String> getParameters() {
+    return this.params;
+  }
+
+  public String getRefreshToken() {
+    return this.params.get(OAuth2Message.REFRESH_TOKEN);
+  }
+
+  public String getState() {
+    return this.params.get(OAuth2Message.STATE);
+  }
+
+  public String getTokenType() {
+    return this.params.get(OAuth2Message.TOKEN_TYPE);
+  }
+
+  public Map<String, String> getUnparsedProperties() {
+    // TODO ARC
+    return this.unparsedProperties;
+  }
+
+  public void parseFragment(final String fragment) {
+    final Uri uri = Uri.parse(fragment);
+    final Map<String, List<String>> _params = uri.getFragmentParameters();
+    for (final Entry<String, List<String>> entry : _params.entrySet()) {
+      this.params.put(entry.getKey(), entry.getValue().get(0));
+    }
+  }
+
+  public void parseJSON(final String response) {
+    try {
+      final JSONObject jsonObject = new JSONObject(response);
+      final String accessToken = jsonObject.optString(OAuth2Message.ACCESS_TOKEN, null);
+      if (accessToken != null) {
+        this.params.put(OAuth2Message.ACCESS_TOKEN, accessToken);
+      }
+
+      final String tokenType = jsonObject.optString(OAuth2Message.TOKEN_TYPE, null);
+      if (tokenType != null) {
+        this.params.put(OAuth2Message.TOKEN_TYPE, tokenType);
+      }
+
+      final String expiresIn = jsonObject.optString(OAuth2Message.EXPIRES_IN, null);
+      if (expiresIn != null) {
+        this.params.put(OAuth2Message.EXPIRES_IN, expiresIn);
+      }
+
+      final String refreshToken = jsonObject.optString(OAuth2Message.REFRESH_TOKEN, null);
+      if (refreshToken != null) {
+        this.params.put(OAuth2Message.REFRESH_TOKEN, refreshToken);
+      }
+
+      final String _error = jsonObject.optString(OAuth2Message.ERROR, null);
+      if (_error != null) {
+        this.params.put(OAuth2Message.ERROR, _error);
+      }
+
+      final String errorDescription = jsonObject.optString(OAuth2Message.ERROR_DESCRIPTION, null);
+      if (errorDescription != null) {
+        this.params.put(OAuth2Message.ERROR_DESCRIPTION, errorDescription);
+      }
+
+      final String errorUri = jsonObject.optString(OAuth2Message.ERROR_URI, null);
+      if (errorUri != null) {
+        this.params.put(OAuth2Message.ERROR_URI, errorUri);
+      }
+    } catch (final JSONException e) {
+      if (BasicOAuth2Message.LOG.isLoggable()) {
+        BasicOAuth2Message.LOG.log("JSONException parsing response", e);
+      }
+      this.params.put(OAuth2Message.ERROR, "JSONException parsing response");
+    }
+  }
+
+  public void parseQuery(final String query) {
+    final Uri uri = Uri.parse(query);
+    final Map<String, List<String>> _params = uri.getQueryParameters();
+    for (final Entry<String, List<String>> entry : _params.entrySet()) {
+      this.params.put(entry.getKey(), entry.getValue().get(0));
+    }
+    if ((!this.params.containsKey(OAuth2Message.EXPIRES_IN))
+        && (this.params.containsKey("expires"))) {
+      this.params.put(OAuth2Message.EXPIRES_IN, this.params.get("expires"));
+    }
+  }
+
+  public void parseRequest(final HttpServletRequest request) {
+    @SuppressWarnings("unchecked")
+    final Enumeration<String> paramNames = request.getParameterNames();
+    while (paramNames.hasMoreElements()) {
+      final String paramName = paramNames.nextElement();
+      final String param = request.getParameter(paramName);
+      this.params.put(paramName, param);
+    }
+  }
+
+  public void setError(OAuth2Error error) {
+    this.params.put(OAuth2Message.ERROR, error.getErrorCode());
+  }
+
+  public void setErrorDescription(String errorDescription) {
+    this.params.put(OAuth2Message.ERROR_DESCRIPTION, errorDescription);
+  }
+
+  public void setErrorUri(String errorUri) {
+    this.params.put(OAuth2Message.ERROR_URI, errorUri);
+  }
+}

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/BasicOAuth2Request.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/BasicOAuth2Request.java?rev=1182565&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/BasicOAuth2Request.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/BasicOAuth2Request.java Wed Oct 12 20:10:39 2011
@@ -0,0 +1,863 @@
+/*
+ * 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.oauth2;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.shindig.auth.SecurityToken;
+import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.gadgets.GadgetException;
+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.oauth2.handler.AuthorizationEndpointResponseHandler;
+import org.apache.shindig.gadgets.oauth2.handler.ClientAuthenticationHandler;
+import org.apache.shindig.gadgets.oauth2.handler.GrantRequestHandler;
+import org.apache.shindig.gadgets.oauth2.handler.OAuth2HandlerError;
+import org.apache.shindig.gadgets.oauth2.handler.ResourceRequestHandler;
+import org.apache.shindig.gadgets.oauth2.handler.TokenEndpointResponseHandler;
+import org.apache.shindig.gadgets.oauth2.logger.FilteredLogger;
+
+import com.google.common.collect.Maps;
+import com.google.inject.Inject;
+
+/**
+ * see {@link OAuth2Request}
+ * 
+ */
+public class BasicOAuth2Request implements OAuth2Request {
+  private final static String LOG_CLASS = BasicOAuth2Request.class.getName();
+  private final static FilteredLogger LOG = FilteredLogger
+      .getFilteredLogger(BasicOAuth2Request.LOG_CLASS);
+
+  private OAuth2Accessor _accessor;
+
+  private OAuth2Arguments arguments;
+
+  private final List<AuthorizationEndpointResponseHandler> authorizationEndpointResponseHandlers;
+
+  private final List<ClientAuthenticationHandler> clientAuthenticationHandlers;
+
+  private final HttpFetcher fetcher;
+
+  private final OAuth2FetcherConfig fetcherConfig;
+
+  private final List<GrantRequestHandler> grantRequestHandlers;
+
+  private HttpRequest realRequest;
+
+  private final List<ResourceRequestHandler> resourceRequestHandlers;
+
+  private OAuth2ResponseParams responseParams;
+
+  private SecurityToken securityToken;
+
+  private final OAuth2Store store;
+
+  private final List<TokenEndpointResponseHandler> tokenEndpointResponseHandlers;
+
+  private final boolean sendTraceToClient;
+
+  /**
+   * @param fetcherConfig
+   *          configuration options for the fetcher
+   * @param fetcher
+   *          fetcher to use for actually making requests
+   */
+  @Inject
+  public BasicOAuth2Request(final OAuth2FetcherConfig fetcherConfig, final HttpFetcher fetcher,
+      final List<AuthorizationEndpointResponseHandler> authorizationEndpointResponseHandlers,
+      final List<ClientAuthenticationHandler> clientAuthenticationHandlers,
+      final List<GrantRequestHandler> grantRequestHandlers,
+      final List<ResourceRequestHandler> resourceRequestHandlers,
+      final List<TokenEndpointResponseHandler> tokenEndpointResponseHandlers,
+      final boolean sendTraceToClient) {
+    this.fetcherConfig = fetcherConfig;
+    if (this.fetcherConfig != null) {
+      this.store = this.fetcherConfig.getOAuth2Store();
+    } else {
+      this.store = null;
+    }
+    this.fetcher = fetcher;
+    this.authorizationEndpointResponseHandlers = authorizationEndpointResponseHandlers;
+    this.clientAuthenticationHandlers = clientAuthenticationHandlers;
+    this.grantRequestHandlers = grantRequestHandlers;
+    this.resourceRequestHandlers = resourceRequestHandlers;
+    this.tokenEndpointResponseHandlers = tokenEndpointResponseHandlers;
+    this.sendTraceToClient = sendTraceToClient;
+
+    if (BasicOAuth2Request.LOG.isLoggable()) {
+      BasicOAuth2Request.LOG.log("this.fetcherConfig = {0}", this.fetcherConfig);
+      BasicOAuth2Request.LOG.log("this.store = {0}", this.store);
+      BasicOAuth2Request.LOG.log("this.fetcher = {0}", this.fetcher);
+      BasicOAuth2Request.LOG.log("this.authorizationEndpointResponseHandlers = {0}",
+          this.authorizationEndpointResponseHandlers);
+      BasicOAuth2Request.LOG.log("this.clientAuthenticationHandlers = {0}",
+          this.clientAuthenticationHandlers);
+      BasicOAuth2Request.LOG.log("this.grantRequestHandlers = {0}", this.grantRequestHandlers);
+      BasicOAuth2Request.LOG
+          .log("this.resourceRequestHandlers = {0}", this.resourceRequestHandlers);
+      BasicOAuth2Request.LOG.log("this.tokenEndpointResponseHandlers = {0}",
+          this.tokenEndpointResponseHandlers);
+      BasicOAuth2Request.LOG.log("this.sendTraceToClient = {0}", this.sendTraceToClient);
+    }
+  }
+
+  public HttpResponse fetch(final HttpRequest request) {
+    final boolean isLogging = BasicOAuth2Request.LOG.isLoggable();
+    if (isLogging) {
+      BasicOAuth2Request.LOG.entering(BasicOAuth2Request.LOG_CLASS, "fetch", request);
+    }
+
+    OAuth2Accessor accessor = null;
+
+    HttpResponse response = null;
+
+    try {
+      // First step is to get an OAuth2Accessor for this request
+      if ((request == null) || (request.getSecurityToken() == null)) {
+        // Any errors before we have an accessor are special cases
+        response = this.sendErrorResponse(null, OAuth2Error.MISSING_FETCH_PARAMS,
+            "no request or security token", "");
+      } else {
+        this.realRequest = request;
+        this.securityToken = request.getSecurityToken();
+        this.responseParams = new OAuth2ResponseParams();
+        this.arguments = this.realRequest.getOAuth2Arguments();
+
+        if (BasicOAuth2Request.LOG.isLoggable()) {
+          BasicOAuth2Request.LOG.log("this.realRequest = {0}", this.realRequest);
+          BasicOAuth2Request.LOG.log("this.securityToken = {0}", this.securityToken);
+          BasicOAuth2Request.LOG.log("this.responseParams = {0}", this.responseParams);
+          BasicOAuth2Request.LOG.log("this.arguments = {0}", this.arguments);
+        }
+
+        if ((this.responseParams == null) || (this.arguments == null)) {
+          // Any errors before we have an accessor are special cases
+          return this.sendErrorResponse(null, OAuth2Error.FETCH_INIT_PROBLEM,
+              "no responseParams or arguments", "");
+        }
+
+        accessor = this.getAccessor();
+
+        if (BasicOAuth2Request.LOG.isLoggable()) {
+          BasicOAuth2Request.LOG.log("accessor", accessor);
+        }
+
+        if (accessor == null) {
+          // Any errors before we have an accessor are special cases
+          response = this.sendErrorResponse(null, OAuth2Error.FETCH_INIT_PROBLEM,
+              "accessor is null", "");
+        } else {
+          accessor.setRedirecting(false);
+
+          HttpResponseBuilder responseBuilder = null;
+          if (!accessor.isErrorResponse()) {
+            responseBuilder = this.attemptFetch(accessor, false);
+          }
+
+          response = this.processResponse(accessor, responseBuilder);
+        }
+      }
+    } catch (final Throwable t) {
+      if (BasicOAuth2Request.LOG.isLoggable()) {
+        BasicOAuth2Request.LOG.log("exception occurred during fetch", t);
+      }
+      if (accessor == null) {
+        accessor = new BasicOAuth2Accessor(t, OAuth2Error.FETCH_PROBLEM,
+            "exception occurred during fetch", "");
+      } else {
+        accessor.setErrorResponse(t, OAuth2Error.FETCH_PROBLEM, "exception occurred during fetch",
+            "");
+      }
+      response = this.processResponse(accessor, this.getErrorResponseBuilder(t,
+          OAuth2Error.FETCH_PROBLEM, "exception occurred during fetch", ""));
+    } finally {
+      if (accessor != null) {
+        if (!accessor.isRedirecting()) {
+          accessor.invalidate();
+          this.store.removeOAuth2Accessor(accessor);
+          this._accessor = null;
+        }
+      }
+    }
+
+    if (isLogging) {
+      BasicOAuth2Request.LOG.exiting(BasicOAuth2Request.LOG_CLASS, "fetch", response);
+    }
+
+    return response;
+  }
+
+  private HttpResponseBuilder attemptFetch(final OAuth2Accessor accessor, final boolean tryAgain) {
+    final boolean isLogging = BasicOAuth2Request.LOG.isLoggable();
+    if (isLogging) {
+      BasicOAuth2Request.LOG.entering(BasicOAuth2Request.LOG_CLASS, "attemptFetch", new Object[] {
+          accessor, tryAgain });
+    }
+
+    HttpResponseBuilder ret = null;
+
+    // If there's an error in the accessor don't continue.
+    if (!accessor.isErrorResponse()) {
+      if (BasicOAuth2Request.haveAccessToken(accessor) != null) {
+        // We have an access_token, use it and stop!
+        ret = this.fetchData(accessor);
+      } else {
+        // We don't have an access token, we need to try and get one.
+        // First step see if we have a refresh token
+        if (BasicOAuth2Request.haveRefreshToken(accessor) != null) {
+          if (BasicOAuth2Request.checkCanRefresh()) {
+            final OAuth2HandlerError handlerError = this.refreshToken(accessor);
+            if (handlerError == null) {
+              // No errors refreshing, attempt the fetch again.
+              ret = this.attemptFetch(accessor, true);
+            } else {
+              // There was an error refreshing, stop.
+              final OAuth2Error error = handlerError.getError();
+              ret = this.getErrorResponseBuilder(handlerError.getCause(), error,
+                  handlerError.getContextMessage(), "");
+            }
+          } else {
+            // User cannot refresh, they'll have to try to authorize again.
+            accessor.setRefreshToken(null);
+            ret = this.attemptFetch(accessor, true);
+          }
+        } else {
+          // We have no access token and no refresh token.
+          // User needs to authorize again.
+          if (!accessor.isRedirecting() && this.checkCanAuthorize(accessor)) {
+            final String completeAuthUrl = this.authorize(accessor);
+            if (completeAuthUrl != null) {
+              // Send a response to redirect to the authorization url
+              this.responseParams.setAuthorizationUrl(completeAuthUrl);
+              accessor.setRedirecting(true);
+            } else {
+              // This wasn't a redirect type of authorization. try again
+              ret = this.attemptFetch(accessor, true);
+            }
+          }
+        }
+      }
+
+      if ((ret == null) && (!accessor.isRedirecting())) {
+        // We don't have a response, just issue the request and
+        // see what happens
+        ret = this.fetchData(accessor);
+      }
+
+      if ((ret == null) && (accessor.isRedirecting())) {
+        ret = new HttpResponseBuilder().setHttpStatusCode(HttpResponse.SC_OK).setStrictNoCache();
+      }
+    } else {
+      return null;
+    }
+
+    if (isLogging) {
+      BasicOAuth2Request.LOG.exiting(BasicOAuth2Request.LOG_CLASS, "attemptFetch", ret);
+    }
+
+    return ret;
+  }
+
+  private String authorize(final OAuth2Accessor accessor) {
+    final boolean isLogging = BasicOAuth2Request.LOG.isLoggable();
+    if (isLogging) {
+      BasicOAuth2Request.LOG.entering(BasicOAuth2Request.LOG_CLASS, "authorize", accessor);
+    }
+
+    String ret = null;
+
+    final String grantType = accessor.getGrantType();
+
+    GrantRequestHandler grantRequestHandlerUsed = null;
+    for (final GrantRequestHandler grantRequestHandler : this.grantRequestHandlers) {
+      if (grantRequestHandler.getGrantType().equalsIgnoreCase(grantType)) {
+        grantRequestHandlerUsed = grantRequestHandler;
+        break;
+      }
+    }
+
+    if (grantRequestHandlerUsed == null) {
+      accessor.setErrorResponse(null, OAuth2Error.AUTHENTICATION_PROBLEM,
+          "no grantRequestHandler found for " + grantType, "");
+    } else {
+      String completeAuthUrl = null;
+      try {
+        completeAuthUrl = grantRequestHandlerUsed.getCompleteUrl(accessor);
+      } catch (final OAuth2RequestException e) {
+        if (isLogging) {
+          BasicOAuth2Request.LOG.log("error getting complete url", e);
+        }
+      }
+      if (grantRequestHandlerUsed.isRedirectRequired()) {
+        ret = completeAuthUrl;
+      } else {
+        final OAuth2HandlerError error = this.authorize(accessor, grantRequestHandlerUsed,
+            completeAuthUrl);
+        if (error != null) {
+          accessor.setErrorResponse(error.getCause(), OAuth2Error.AUTHENTICATION_PROBLEM,
+              error.getContextMessage(), "");
+        }
+      }
+    }
+
+    if (isLogging) {
+      BasicOAuth2Request.LOG.exiting(BasicOAuth2Request.LOG_CLASS, "authorize", ret);
+    }
+
+    return ret;
+  }
+
+  private OAuth2HandlerError authorize(final OAuth2Accessor accessor,
+      final GrantRequestHandler grantRequestHandler, final String completeAuthUrl) {
+
+    final boolean isLogging = BasicOAuth2Request.LOG.isLoggable();
+    if (isLogging) {
+      BasicOAuth2Request.LOG.entering(BasicOAuth2Request.LOG_CLASS, "authorize", new Object[] {
+          accessor, grantRequestHandler, completeAuthUrl });
+    }
+
+    OAuth2HandlerError ret = null;
+
+    HttpRequest authorizationRequest;
+    try {
+      authorizationRequest = grantRequestHandler.getAuthorizationRequest(accessor, completeAuthUrl);
+    } catch (final OAuth2RequestException e) {
+      authorizationRequest = null;
+      ret = new OAuth2HandlerError(e.getError(), e.getErrorText(), e);
+    }
+
+    if (isLogging) {
+      BasicOAuth2Request.LOG.log("authorizationRequest = {0}", authorizationRequest);
+    }
+
+    if (authorizationRequest != null) {
+      HttpResponse authorizationResponse;
+      try {
+        authorizationResponse = this.fetcher.fetch(authorizationRequest);
+      } catch (final GadgetException e) {
+        if (isLogging) {
+          BasicOAuth2Request.LOG.log("authorize()", e);
+        }
+        authorizationResponse = null;
+        ret = new OAuth2HandlerError(OAuth2Error.AUTHORIZE_PROBLEM,
+            "exception thrown fetching authorization", e);
+      }
+
+      if (isLogging) {
+        BasicOAuth2Request.LOG.log("authorizationResponse = {0}", authorizationResponse);
+      }
+
+      if (authorizationResponse != null) {
+        if (grantRequestHandler.isAuthorizationEndpointResponse()) {
+          for (final AuthorizationEndpointResponseHandler authorizationEndpointResponseHandler : this.authorizationEndpointResponseHandlers) {
+            if (authorizationEndpointResponseHandler.handlesResponse(accessor,
+                authorizationResponse)) {
+              if (isLogging) {
+                BasicOAuth2Request.LOG.log("using AuthorizationEndpointResponseHandler = {0}",
+                    authorizationEndpointResponseHandler);
+              }
+              ret = authorizationEndpointResponseHandler.handleResponse(accessor,
+                  authorizationResponse);
+              if (ret != null) {
+                // error occurred stop processing
+                break;
+              }
+            }
+          }
+        }
+
+        if (ret == null) {
+          if (grantRequestHandler.isTokenEndpointResponse()) {
+            for (final TokenEndpointResponseHandler tokenEndpointResponseHandler : this.tokenEndpointResponseHandlers) {
+              if (tokenEndpointResponseHandler.handlesResponse(accessor, authorizationResponse)) {
+                if (isLogging) {
+                  BasicOAuth2Request.LOG.log("using TokenEndpointResponseHandler = {0}",
+                      tokenEndpointResponseHandler);
+                }
+                ret = tokenEndpointResponseHandler.handleResponse(accessor, authorizationResponse);
+                if (ret != null) {
+                  // error occurred stop processing
+                  break;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+
+    if (isLogging) {
+      BasicOAuth2Request.LOG.exiting(BasicOAuth2Request.LOG_CLASS, "authorize", ret);
+    }
+
+    return ret;
+  }
+
+  private static String buildRefreshTokenUrl(final OAuth2Accessor accessor) {
+    final boolean isLogging = BasicOAuth2Request.LOG.isLoggable();
+    if (isLogging) {
+      BasicOAuth2Request.LOG.entering(BasicOAuth2Request.LOG_CLASS, "buildRefreshTokenUrl",
+          accessor);
+    }
+
+    String ret = null;
+
+    final String refreshUrl = accessor.getTokenUrl();
+    if (refreshUrl != null) {
+      ret = BasicOAuth2Request.getCompleteRefreshUrl(refreshUrl);
+    }
+
+    if (isLogging) {
+      BasicOAuth2Request.LOG.exiting(BasicOAuth2Request.LOG_CLASS, "buildRefreshTokenUrl", ret);
+    }
+
+    return ret;
+  }
+
+  private boolean checkCanAuthorize(final OAuth2Accessor accessor) {
+    final boolean isLogging = BasicOAuth2Request.LOG.isLoggable();
+    if (isLogging) {
+      BasicOAuth2Request.LOG.entering(BasicOAuth2Request.LOG_CLASS, "checkCanAuthorize", accessor);
+    }
+
+    boolean ret = true;
+
+    if (BasicOAuth2Request.LOG.isLoggable()) {
+      BasicOAuth2Request.LOG.log("securityToken = {0}", this.securityToken);
+    }
+
+    final String pageOwner = this.securityToken.getOwnerId();
+    final String pageViewer = this.securityToken.getViewerId();
+
+    if (BasicOAuth2Request.LOG.isLoggable()) {
+      BasicOAuth2Request.LOG.log("pageOwner = {0}", pageOwner);
+      BasicOAuth2Request.LOG.log("pageViewer = {0}", pageViewer);
+    }
+
+    if ((pageOwner == null) || (pageViewer == null)) {
+      accessor.setErrorResponse(null, OAuth2Error.AUTHORIZE_PROBLEM,
+          "pageOwner or pageViewer is null", "");
+      ret = false;
+    } else if (!this.fetcherConfig.isViewerAccessTokensEnabled() && !pageOwner.equals(pageViewer)) {
+      accessor.setErrorResponse(null, OAuth2Error.AUTHORIZE_PROBLEM, "pageViewer is not pageOwner",
+          "");
+      ret = false;
+    }
+
+    if (isLogging) {
+      BasicOAuth2Request.LOG.exiting(BasicOAuth2Request.LOG_CLASS, "checkCanAuthorize", ret);
+    }
+
+    return ret;
+  }
+
+  private static boolean checkCanRefresh() {
+    // Everyone can try to refresh???
+    return true;
+  }
+
+  private HttpResponseBuilder fetchData(final OAuth2Accessor accessor) {
+    final boolean isLogging = BasicOAuth2Request.LOG.isLoggable();
+    if (isLogging) {
+      BasicOAuth2Request.LOG.entering(BasicOAuth2Request.LOG_CLASS, "fetchData", accessor);
+    }
+
+    HttpResponseBuilder ret = null;
+
+    try {
+      final HttpResponse response = this.fetchFromServer(accessor, this.realRequest);
+      ret = new HttpResponseBuilder(response);
+
+      if ((response.getHttpStatusCode() != HttpResponse.SC_OK) && (this.sendTraceToClient)) {
+        this.responseParams.addRequestTrace(this.realRequest, response);
+      }
+    } catch (final OAuth2RequestException e) {
+      ret = this.getErrorResponseBuilder(e, e.getError(), e.getErrorText(), "");
+    }
+
+    if (isLogging) {
+      BasicOAuth2Request.LOG.exiting(BasicOAuth2Request.LOG_CLASS, "fetchData", ret);
+    }
+
+    return ret;
+  }
+
+  private HttpResponse fetchFromServer(final OAuth2Accessor accessor, final HttpRequest request)
+      throws OAuth2RequestException {
+    final boolean isLogging = BasicOAuth2Request.LOG.isLoggable();
+    if (isLogging) {
+      BasicOAuth2Request.LOG.entering(BasicOAuth2Request.LOG_CLASS, "fetchFromServer",
+          new Object[] { accessor, "only log request once" });
+    }
+
+    HttpResponse ret = null;
+
+    final OAuth2Token accessToken = accessor.getAccessToken();
+    final OAuth2Token refreshToken = accessor.getRefreshToken();
+
+    if (BasicOAuth2Request.LOG.isLoggable()) {
+      BasicOAuth2Request.LOG.log("accessToken = {0}", accessToken);
+      BasicOAuth2Request.LOG.log("refreshToken = {0}", refreshToken);
+    }
+
+    if (accessToken != null) {
+      String tokenType = accessToken.getTokenType();
+      if ((tokenType == null) || (tokenType.length() == 0)) {
+        tokenType = OAuth2Message.BEARER_TOKEN_TYPE;
+      }
+
+      for (final ResourceRequestHandler resourceRequestHandler : this.resourceRequestHandlers) {
+        if (tokenType.equalsIgnoreCase(resourceRequestHandler.getTokenType())) {
+          resourceRequestHandler.addOAuth2Params(accessor, request);
+        }
+      }
+    }
+
+    try {
+      ret = this.fetcher.fetch(request);
+    } catch (final GadgetException e) {
+      throw new OAuth2RequestException(OAuth2Error.MISSING_SERVER_RESPONSE,
+          "GadgetException fetchFromServer", e);
+    }
+
+    if (ret == null) {
+      throw new OAuth2RequestException(OAuth2Error.MISSING_SERVER_RESPONSE, "response is null",
+          null);
+    }
+
+    final int responseCode = ret.getHttpStatusCode();
+
+    if (isLogging) {
+      BasicOAuth2Request.LOG.log("responseCode = {0}", responseCode);
+    }
+
+    if ((responseCode >= HttpResponse.SC_BAD_REQUEST)
+        && (responseCode < HttpResponse.SC_INTERNAL_SERVER_ERROR)) {
+      if (accessToken != null) {
+        try {
+          this.store.removeToken(accessToken);
+        } catch (final GadgetException e) {
+          throw new OAuth2RequestException(OAuth2Error.MISSING_SERVER_RESPONSE,
+              "error removing access_token", null);
+        }
+        accessor.setAccessToken(null);
+      }
+
+      if (refreshToken != null) {
+        try {
+          this.store.removeToken(refreshToken);
+        } catch (final GadgetException e) {
+          throw new OAuth2RequestException(OAuth2Error.MISSING_SERVER_RESPONSE,
+              "error removing refresh_token", null);
+        }
+        accessor.setRefreshToken(null);
+      }
+    }
+
+    if (isLogging) {
+      BasicOAuth2Request.LOG.exiting(BasicOAuth2Request.LOG_CLASS, "fetchFromServer", ret);
+    }
+
+    return ret;
+  }
+
+  private OAuth2Accessor getAccessor() {
+    if ((this._accessor == null) || (!this._accessor.isValid())) {
+      if (this.fetcherConfig != null) {
+        final GadgetOAuth2TokenStore tokenStore = this.fetcherConfig.getTokenStore();
+        if (tokenStore != null) {
+          this._accessor = tokenStore.getOAuth2Accessor(this.securityToken, this.arguments,
+              this.realRequest.getGadget());
+        }
+      }
+    }
+
+    return this._accessor;
+  }
+
+  private static String getCompleteRefreshUrl(final String refreshUrl) {
+    final String ret = OAuth2Utils.buildUrl(refreshUrl, null, null);
+
+    return ret;
+  }
+
+  private HttpResponseBuilder getErrorResponseBuilder(final Throwable t, final OAuth2Error error,
+      final String contextMessage, final String errorUri) {
+
+    final boolean isLogging = BasicOAuth2Request.LOG.isLoggable();
+    if (isLogging) {
+      BasicOAuth2Request.LOG.entering(BasicOAuth2Request.LOG_CLASS, "getErrorResponseBuilder",
+          new Object[] { t, error, contextMessage, errorUri });
+    }
+
+    final HttpResponseBuilder ret = new HttpResponseBuilder().setHttpStatusCode(
+        HttpResponse.SC_FORBIDDEN).setStrictNoCache();
+
+    if ((t != null) && (this.sendTraceToClient)) {
+      final StringWriter sw = new StringWriter();
+      t.printStackTrace(new PrintWriter(sw));
+      final String message = sw.toString();
+      this.responseParams.addDebug(message);
+    }
+
+    this.responseParams.addToResponse(ret, error.getErrorCode(),
+        error.getErrorDescription(contextMessage), errorUri, error.getErrorExplanation());
+
+    if (isLogging) {
+      BasicOAuth2Request.LOG.exiting(BasicOAuth2Request.LOG_CLASS, "getErrorResponseBuilder", ret);
+    }
+
+    return ret;
+  }
+
+  private static String getRefreshBody(final OAuth2Accessor accessor) {
+    final boolean isLogging = BasicOAuth2Request.LOG.isLoggable();
+    if (isLogging) {
+      BasicOAuth2Request.LOG.entering(BasicOAuth2Request.LOG_CLASS, "getRefreshBody", accessor);
+    }
+
+    String ret = "";
+
+    Map<String, String> queryParams;
+    try {
+      queryParams = Maps.newHashMap();
+      queryParams.put(OAuth2Message.GRANT_TYPE, OAuth2Message.REFRESH_TOKEN);
+      queryParams.put(OAuth2Message.REFRESH_TOKEN, new String(accessor.getRefreshToken()
+          .getSecret(), "UTF-8"));
+      if ((accessor.getScope() != null) && (accessor.getScope().length() > 0)) {
+        queryParams.put(OAuth2Message.SCOPE, accessor.getScope());
+      }
+
+      final String clientId = accessor.getClientId();
+      final byte[] secret = accessor.getClientSecret();
+      queryParams.put(OAuth2Message.CLIENT_ID, clientId);
+      queryParams.put(OAuth2Message.CLIENT_SECRET, new String(secret, "UTF-8"));
+
+      ret = OAuth2Utils.buildUrl(ret, queryParams, null);
+
+      final char firstChar = ret.charAt(0);
+      if ((firstChar == '?') || (firstChar == '&')) {
+        ret = ret.substring(1);
+      }
+
+      if (isLogging) {
+        BasicOAuth2Request.LOG.exiting(BasicOAuth2Request.LOG_CLASS, "getRefreshBody", ret);
+      }
+    } catch (final UnsupportedEncodingException e) {
+      if (isLogging) {
+        BasicOAuth2Request.LOG.log("error generating refresh body", e);
+        ret = null;
+      }
+    }
+
+    return ret;
+  }
+
+  private HttpResponse processResponse(final OAuth2Accessor accessor,
+      final HttpResponseBuilder responseBuilder) {
+
+    final boolean isLogging = BasicOAuth2Request.LOG.isLoggable();
+    if (isLogging) {
+      BasicOAuth2Request.LOG.entering(BasicOAuth2Request.LOG_CLASS, "processResponse",
+          new Object[] { accessor, (responseBuilder == null) });
+    }
+
+    if (accessor.isErrorResponse() || (responseBuilder == null)) {
+      return this.sendErrorResponse(accessor.getErrorException(), accessor.getError(),
+          accessor.getErrorContextMessage(), accessor.getErrorUri());
+    }
+
+    if (this.responseParams.getAuthorizationUrl() != null) {
+      responseBuilder.setMetadata(OAuth2ResponseParams.APPROVAL_URL,
+          this.responseParams.getAuthorizationUrl());
+      accessor.setRedirecting(true);
+    } else {
+      accessor.setRedirecting(false);
+    }
+
+    final HttpResponse ret = responseBuilder.create();
+    if (isLogging) {
+      BasicOAuth2Request.LOG.exiting(BasicOAuth2Request.LOG_CLASS, "processResponse",
+          "response logged in fetch()");
+    }
+
+    return ret;
+  }
+
+  private OAuth2HandlerError refreshToken(final OAuth2Accessor accessor) {
+    final boolean isLogging = BasicOAuth2Request.LOG.isLoggable();
+    if (isLogging) {
+      BasicOAuth2Request.LOG.entering(BasicOAuth2Request.LOG_CLASS, "refreshToken",
+          new Object[] { accessor });
+    }
+
+    OAuth2HandlerError ret = null;
+
+    String refershTokenUrl = null;
+
+    refershTokenUrl = BasicOAuth2Request.buildRefreshTokenUrl(accessor);
+
+    if (isLogging) {
+      BasicOAuth2Request.LOG.log("refershTokenUrl = {0}", refershTokenUrl);
+    }
+
+    if (refershTokenUrl != null) {
+      HttpResponse response = null;
+      final HttpRequest request = new HttpRequest(Uri.parse(refershTokenUrl));
+      request.setMethod("POST");
+      request.setHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
+
+      for (final ClientAuthenticationHandler clientAuthenticationHandler : this.clientAuthenticationHandlers) {
+        if (clientAuthenticationHandler.geClientAuthenticationType().equalsIgnoreCase(
+            accessor.getClientAuthenticationType())) {
+          clientAuthenticationHandler.addOAuth2Authentication(request, accessor);
+        }
+      }
+
+      try {
+        final byte[] body = BasicOAuth2Request.getRefreshBody(accessor).getBytes("UTF-8");
+        request.setPostBody(body);
+      } catch (final Exception e) {
+        if (isLogging) {
+          BasicOAuth2Request.LOG.log("refreshToken()", e);
+        }
+        ret = new OAuth2HandlerError(OAuth2Error.REFRESH_TOKEN_PROBLEM,
+            "error generating refresh body", e);
+      }
+
+      if (ret == null) {
+        try {
+          response = this.fetcher.fetch(request);
+        } catch (final GadgetException e) {
+          if (isLogging) {
+            BasicOAuth2Request.LOG.log("refreshToken()", e);
+          }
+          ret = new OAuth2HandlerError(OAuth2Error.REFRESH_TOKEN_PROBLEM,
+              "error fetching refresh token", e);
+        }
+
+        if (isLogging) {
+          BasicOAuth2Request.LOG.log("response = {0}", response);
+        }
+
+        if (response == null) {
+          ret = new OAuth2HandlerError(OAuth2Error.REFRESH_TOKEN_PROBLEM, "response is null", null);
+        }
+
+        if (ret == null) {
+          if (response != null) {
+            final int statusCode = response.getHttpStatusCode();
+            if (statusCode != HttpResponse.SC_OK) {
+              ret = new OAuth2HandlerError(OAuth2Error.REFRESH_TOKEN_PROBLEM,
+                  "bad response from server : " + statusCode, null);
+            }
+          }
+
+          if (ret == null) {
+            for (final TokenEndpointResponseHandler tokenEndpointResponseHandler : this.tokenEndpointResponseHandlers) {
+              if (tokenEndpointResponseHandler.handlesResponse(accessor, response)) {
+                final OAuth2HandlerError error = tokenEndpointResponseHandler.handleResponse(
+                    accessor, response);
+                if (error != null) {
+                  return error;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+
+    if (isLogging) {
+      BasicOAuth2Request.LOG.exiting(BasicOAuth2Request.LOG_CLASS, "refreshToken", ret);
+    }
+
+    return ret;
+  }
+
+  private HttpResponse sendErrorResponse(final Throwable t, final OAuth2Error error,
+      final String contextMessage, final String errorUri) {
+    final HttpResponseBuilder responseBuilder = this.getErrorResponseBuilder(t, error,
+        contextMessage, errorUri);
+    return responseBuilder.create();
+  }
+
+  private static OAuth2Token haveAccessToken(final OAuth2Accessor accessor) {
+    final boolean isLogging = BasicOAuth2Request.LOG.isLoggable();
+    if (isLogging) {
+      BasicOAuth2Request.LOG.entering(BasicOAuth2Request.LOG_CLASS, "haveAccessToken",
+          new Object[] { accessor });
+    }
+
+    OAuth2Token ret = accessor.getAccessToken();
+    if ((ret != null)) {
+      if (!BasicOAuth2Request.validateAccessToken(ret)) {
+        ret = null;
+      }
+    }
+
+    if (isLogging) {
+      BasicOAuth2Request.LOG.exiting(BasicOAuth2Request.LOG_CLASS, "haveAccessToken", ret);
+    }
+
+    return ret;
+  }
+
+  private static OAuth2Token haveRefreshToken(final OAuth2Accessor accessor) {
+    final boolean isLogging = BasicOAuth2Request.LOG.isLoggable();
+    if (isLogging) {
+      BasicOAuth2Request.LOG.entering(BasicOAuth2Request.LOG_CLASS, "haveRefreshToken",
+          new Object[] { accessor });
+    }
+
+    OAuth2Token ret = accessor.getRefreshToken();
+    if ((ret != null)) {
+      if (!BasicOAuth2Request.validateRefreshToken(ret)) {
+        ret = null;
+      }
+    }
+
+    if (isLogging) {
+      BasicOAuth2Request.LOG.exiting(BasicOAuth2Request.LOG_CLASS, "haveRefreshToken", ret);
+    }
+
+    return ret;
+  }
+
+  private static boolean validateAccessToken(final OAuth2Token accessToken) {
+    if (accessToken != null) {
+      return true;
+    }
+
+    return false;
+  }
+
+  private static boolean validateRefreshToken(final OAuth2Token refreshToken) {
+    if (refreshToken != null) {
+      return true;
+    }
+
+    return false;
+  }
+}
\ No newline at end of file

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/BasicOAuth2Store.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/BasicOAuth2Store.java?rev=1182565&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/BasicOAuth2Store.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/BasicOAuth2Store.java Wed Oct 12 20:10:39 2011
@@ -0,0 +1,412 @@
+/*
+ * 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.oauth2;
+
+import java.util.Set;
+
+import org.apache.shindig.gadgets.GadgetException;
+import org.apache.shindig.gadgets.GadgetException.Code;
+import org.apache.shindig.gadgets.oauth2.logger.FilteredLogger;
+import org.apache.shindig.gadgets.oauth2.persistence.OAuth2Cache;
+import org.apache.shindig.gadgets.oauth2.persistence.OAuth2CacheException;
+import org.apache.shindig.gadgets.oauth2.persistence.OAuth2Client;
+import org.apache.shindig.gadgets.oauth2.persistence.OAuth2Encrypter;
+import org.apache.shindig.gadgets.oauth2.persistence.OAuth2PersistenceException;
+import org.apache.shindig.gadgets.oauth2.persistence.OAuth2Persister;
+
+import com.google.inject.Inject;
+
+/**
+ * see {@link OAuth2Store}
+ * 
+ * Default OAuth2Store.
+ * 
+ * Uses 3 Guice bindings to achieve storage implementation.
+ * 
+ * 1) {@link OAuth2Persister} 2) {@link OAuth2Cache} 3) {@link OAuth2Encrypter}
+ * 
+ */
+public class BasicOAuth2Store implements OAuth2Store {
+  private final static String LOG_CLASS = BasicOAuth2Store.class.getName();
+  private static final FilteredLogger LOG = FilteredLogger
+      .getFilteredLogger(BasicOAuth2Store.LOG_CLASS);
+
+  private final OAuth2Cache cache;
+  private final String globalRedirectUri;
+  private final OAuth2Persister persister;
+
+  @Inject
+  public BasicOAuth2Store(final OAuth2Cache cache, final OAuth2Persister persister,
+      final String globalRedirectUri) {
+    this.cache = cache;
+    this.persister = persister;
+    this.globalRedirectUri = globalRedirectUri;
+    if (BasicOAuth2Store.LOG.isLoggable()) {
+      BasicOAuth2Store.LOG.log("this.cache = {0}", this.cache);
+      BasicOAuth2Store.LOG.log("this.persister = {0}", this.persister);
+      BasicOAuth2Store.LOG.log("this.globalRedirectUri = {0}", this.globalRedirectUri);
+    }
+  }
+
+  public boolean clearCache() throws GadgetException {
+    final boolean isLogging = BasicOAuth2Store.LOG.isLoggable();
+    if (isLogging) {
+      BasicOAuth2Store.LOG.entering(BasicOAuth2Store.LOG_CLASS, "clearCache");
+    }
+
+    try {
+      this.cache.clearClients();
+      this.cache.clearTokens();
+    } catch (final OAuth2PersistenceException e) {
+      if (isLogging) {
+        BasicOAuth2Store.LOG.log("Error clearing OAuth2 cache", e);
+      }
+      throw new GadgetException(Code.OAUTH_STORAGE_ERROR, "Error clearing OAuth2 cache", e);
+    }
+
+    if (isLogging) {
+      BasicOAuth2Store.LOG.exiting(BasicOAuth2Store.LOG_CLASS, "clearCache", true);
+    }
+
+    return true;
+  }
+
+  public OAuth2Token createToken() {
+    final boolean isLogging = BasicOAuth2Store.LOG.isLoggable();
+    if (isLogging) {
+      BasicOAuth2Store.LOG.entering(BasicOAuth2Store.LOG_CLASS, "createToken");
+    }
+
+    final OAuth2Token ret = this.persister.createToken();
+
+    if (isLogging) {
+      BasicOAuth2Store.LOG.exiting(BasicOAuth2Store.LOG_CLASS, "clearCache", ret);
+    }
+
+    return ret;
+  }
+
+  public OAuth2Client getClient(final String gadgetUri, final String serviceName)
+      throws GadgetException {
+    final boolean isLogging = BasicOAuth2Store.LOG.isLoggable();
+    if (isLogging) {
+      BasicOAuth2Store.LOG.entering(BasicOAuth2Store.LOG_CLASS, "getClient", new Object[] {
+          gadgetUri, serviceName });
+    }
+
+    final Integer index = this.cache.getClientIndex(gadgetUri, serviceName);
+
+    if (isLogging) {
+      BasicOAuth2Store.LOG.log("index = {0}", index);
+    }
+
+    OAuth2Client client = this.cache.getClient(index);
+
+    if (isLogging) {
+      BasicOAuth2Store.LOG.log("client from cache = {0}", client);
+    }
+
+    if (client == null) {
+      try {
+        client = this.persister.findClient(gadgetUri, serviceName);
+        if (client != null) {
+          this.cache.storeClient(client);
+        }
+      } catch (final OAuth2PersistenceException e) {
+        if (isLogging) {
+          BasicOAuth2Store.LOG.log("Error loading OAuth2 client ", e);
+        }
+        throw new GadgetException(Code.OAUTH_STORAGE_ERROR, "Error loading OAuth2 client "
+            + serviceName, e);
+      }
+    }
+
+    if (isLogging) {
+      BasicOAuth2Store.LOG.exiting(BasicOAuth2Store.LOG_CLASS, "getClient", client);
+    }
+
+    return client;
+  }
+
+  public OAuth2Accessor getOAuth2Accessor(final Integer index) {
+    final boolean isLogging = BasicOAuth2Store.LOG.isLoggable();
+    if (isLogging) {
+      BasicOAuth2Store.LOG.entering(BasicOAuth2Store.LOG_CLASS, "getOAuth2Accessor", index);
+    }
+
+    final OAuth2Accessor ret = this.cache.getOAuth2Accessor(index);
+
+    if (isLogging) {
+      BasicOAuth2Store.LOG.exiting(BasicOAuth2Store.LOG_CLASS, "getOAuth2Accessor", ret);
+    }
+
+    return ret;
+  }
+
+  public OAuth2Accessor getOAuth2Accessor(final String gadgetUri, final String serviceName,
+      final String user, final String scope) throws GadgetException {
+    final boolean isLogging = BasicOAuth2Store.LOG.isLoggable();
+    if (isLogging) {
+      BasicOAuth2Store.LOG.entering(BasicOAuth2Store.LOG_CLASS, "getOAuth2Accessor", new Object[] {
+          gadgetUri, serviceName, user, scope });
+    }
+
+    final Integer index = this.cache.getOAuth2AccessorIndex(gadgetUri, serviceName, user, scope);
+
+    OAuth2Accessor ret = this.cache.getOAuth2Accessor(index);
+
+    if ((ret == null) || (!ret.isValid())) {
+      final OAuth2Client client = this.getClient(gadgetUri, serviceName);
+
+      if (client != null) {
+        final OAuth2Token accessToken = this.getToken(gadgetUri, serviceName, user, scope,
+            OAuth2Token.Type.ACCESS);
+        final OAuth2Token refreshToken = this.getToken(gadgetUri, serviceName, user, scope,
+            OAuth2Token.Type.REFRESH);
+
+        final BasicOAuth2Accessor newAccessor = new BasicOAuth2Accessor(gadgetUri, serviceName,
+            user, scope, client.isAllowModuleOverride(), this, this.globalRedirectUri);
+        newAccessor.setAccessToken(accessToken);
+        newAccessor.setAuthorizationUrl(client.getAuthorizationUrl());
+        newAccessor.setClientAuthenticationType(client.getClientAuthenticationType());
+        newAccessor.setAuthorizationHeader(client.isAuthorizationHeader());
+        newAccessor.setUrlParameter(client.isUrlParameter());
+        newAccessor.setClientId(client.getClientId());
+        newAccessor.setClientSecret(client.getClientSecret());
+        newAccessor.setGrantType(client.getGrantType());
+        newAccessor.setRedirectUri(client.getRedirectUri());
+        newAccessor.setRefreshToken(refreshToken);
+        newAccessor.setTokenUrl(client.getTokenUrl());
+        newAccessor.setType(client.getType());
+        ret = newAccessor;
+
+        this.storeOAuth2Accessor(ret);
+      }
+    }
+
+    if (isLogging) {
+      BasicOAuth2Store.LOG.exiting(BasicOAuth2Store.LOG_CLASS, "getOAuth2Accessor", ret);
+    }
+
+    return ret;
+  }
+
+  public Integer getOAuth2AccessorIndex(final String gadgetUri, final String serviceName,
+      final String user, final String scope) {
+    return this.cache.getOAuth2AccessorIndex(gadgetUri, serviceName, user, scope);
+  }
+
+  public OAuth2Token getToken(final String gadgetUri, final String serviceName, final String user,
+      final String scope, final OAuth2Token.Type type) throws GadgetException {
+
+    final boolean isLogging = BasicOAuth2Store.LOG.isLoggable();
+    if (isLogging) {
+      BasicOAuth2Store.LOG.entering(BasicOAuth2Store.LOG_CLASS, "getToken", new Object[] {
+          gadgetUri, serviceName, user, scope, type });
+    }
+
+    final Integer index = this.cache.getTokenIndex(gadgetUri, serviceName, user, scope, type);
+    OAuth2Token token = this.cache.getToken(index);
+    if (token == null) {
+      try {
+        token = this.persister.findToken(gadgetUri, serviceName, user, scope, type);
+        if (token != null) {
+          this.cache.storeToken(token);
+        }
+      } catch (final OAuth2PersistenceException e) {
+        throw new GadgetException(Code.OAUTH_STORAGE_ERROR, "Error loading OAuth2 token " + index,
+            e);
+      }
+    }
+
+    if (isLogging) {
+      BasicOAuth2Store.LOG.exiting(BasicOAuth2Store.LOG_CLASS, "getToken", token);
+    }
+
+    return token;
+  }
+
+  public boolean init() throws GadgetException {
+    final boolean isLogging = BasicOAuth2Store.LOG.isLoggable();
+    if (isLogging) {
+      BasicOAuth2Store.LOG.entering(BasicOAuth2Store.LOG_CLASS, "init");
+    }
+
+    this.clearCache();
+
+    try {
+      final Set<OAuth2Client> clients = this.persister.loadClients();
+      if (isLogging) {
+        BasicOAuth2Store.LOG.log("clients = {0}", clients);
+      }
+      this.cache.storeClients(clients);
+    } catch (final OAuth2PersistenceException e) {
+      throw new GadgetException(Code.OAUTH_STORAGE_ERROR, "Error loading OAuth2 clients", e);
+    }
+
+    try {
+      final Set<OAuth2Token> tokens = this.persister.loadTokens();
+      if (isLogging) {
+        BasicOAuth2Store.LOG.log("tokens = {0}", tokens);
+      }
+      this.cache.storeTokens(tokens);
+    } catch (final OAuth2PersistenceException e) {
+      throw new GadgetException(Code.OAUTH_STORAGE_ERROR, "Error loading OAuth2 tokens", e);
+    }
+
+    if (isLogging) {
+      BasicOAuth2Store.LOG.exiting(BasicOAuth2Store.LOG_CLASS, "init", true);
+    }
+
+    return true;
+  }
+
+  public OAuth2Accessor removeOAuth2Accessor(final OAuth2Accessor accessor) {
+    final boolean isLogging = BasicOAuth2Store.LOG.isLoggable();
+    if (isLogging) {
+      BasicOAuth2Store.LOG.entering(BasicOAuth2Store.LOG_CLASS, "removeOAuth2Accessor", accessor);
+    }
+
+    final OAuth2Accessor ret = null;
+
+    if (accessor != null) {
+      final Integer index = this.cache.getOAuth2AccessorIndex(accessor.getGadgetUri(),
+          accessor.getServiceName(), accessor.getUser(), accessor.getScope());
+      return this.cache.removeOAuth2Accessor(index);
+    }
+
+    if (isLogging) {
+      BasicOAuth2Store.LOG.exiting(BasicOAuth2Store.LOG_CLASS, "removeOAuth2Accessor", ret);
+    }
+
+    return ret;
+  }
+
+  public OAuth2Token removeToken(final OAuth2Token token) throws GadgetException {
+    final boolean isLogging = BasicOAuth2Store.LOG.isLoggable();
+    if (isLogging) {
+      BasicOAuth2Store.LOG.entering(BasicOAuth2Store.LOG_CLASS, "removeToken", token);
+    }
+
+    if (token != null) {
+      if (isLogging) {
+        BasicOAuth2Store.LOG.exiting(BasicOAuth2Store.LOG_CLASS, "removeToken", token);
+      }
+
+      return this.removeToken(token.getGadgetUri(), token.getServiceName(), token.getUser(),
+          token.getScope(), token.getType());
+    }
+
+    if (isLogging) {
+      BasicOAuth2Store.LOG.exiting(BasicOAuth2Store.LOG_CLASS, "removeOAuth2Accessor", null);
+    }
+
+    return null;
+  }
+
+  public OAuth2Token removeToken(final String gadgetUri, final String serviceName,
+      final String user, final String scope, final OAuth2Token.Type type) throws GadgetException {
+
+    final boolean isLogging = BasicOAuth2Store.LOG.isLoggable();
+    if (isLogging) {
+      BasicOAuth2Store.LOG.entering(BasicOAuth2Store.LOG_CLASS, "removeToken", new Object[] {
+          gadgetUri, serviceName, user, scope, type });
+    }
+
+    final Integer index = this.cache.getTokenIndex(gadgetUri, serviceName, user, scope, type);
+    try {
+      final OAuth2Token token = this.cache.removeToken(index);
+      if (token != null) {
+        this.persister.removeToken(gadgetUri, serviceName, user, scope, type);
+      }
+
+      if (isLogging) {
+        BasicOAuth2Store.LOG.exiting(BasicOAuth2Store.LOG_CLASS, "removeToken", token);
+      }
+
+      return token;
+    } catch (final OAuth2PersistenceException e) {
+      if (isLogging) {
+        BasicOAuth2Store.LOG.log("Error loading OAuth2 token ", e);
+      }
+      throw new GadgetException(Code.OAUTH_STORAGE_ERROR, "Error loading OAuth2 token "
+          + serviceName, e);
+    }
+  }
+
+  public static boolean runImport(final OAuth2Persister source, final OAuth2Persister target,
+      final boolean clean) {
+    if (BasicOAuth2Store.LOG.isLoggable()) {
+      BasicOAuth2Store.LOG.entering(BasicOAuth2Store.LOG_CLASS, "runImport", new Object[] { source,
+          target, clean });
+    }
+
+    // No import for default persistence
+    return false;
+  }
+
+  public void setToken(final OAuth2Token token) throws GadgetException {
+    final boolean isLogging = BasicOAuth2Store.LOG.isLoggable();
+    if (isLogging) {
+      BasicOAuth2Store.LOG.entering(BasicOAuth2Store.LOG_CLASS, "setToken", token);
+    }
+
+    if (token != null) {
+      final Integer index = this.cache.getTokenIndex(token);
+      final OAuth2Token existingToken = this.getToken(token.getGadgetUri(), token.getServiceName(),
+          token.getUser(), token.getScope(), token.getType());
+      try {
+        if (existingToken == null) {
+          this.persister.insertToken(token);
+        } else {
+          this.cache.removeToken(index);
+          this.persister.updateToken(token);
+        }
+        this.cache.storeToken(token);
+      } catch (final OAuth2CacheException e) {
+        if (isLogging) {
+          BasicOAuth2Store.LOG.log("Error storing OAuth2 token " + index, e);
+        }
+        throw new GadgetException(Code.OAUTH_STORAGE_ERROR, "Error storing OAuth2 token " + index,
+            e);
+      } catch (final OAuth2PersistenceException e) {
+        if (isLogging) {
+          BasicOAuth2Store.LOG.log("Error storing OAuth2 token " + index, e);
+        }
+        throw new GadgetException(Code.OAUTH_STORAGE_ERROR, "Error storing OAuth2 token " + index,
+            e);
+      }
+    }
+
+    if (isLogging) {
+      BasicOAuth2Store.LOG.exiting(BasicOAuth2Store.LOG_CLASS, "setToken");
+    }
+  }
+
+  public void storeOAuth2Accessor(final OAuth2Accessor accessor) {
+    final boolean isLogging = BasicOAuth2Store.LOG.isLoggable();
+    if (isLogging) {
+      BasicOAuth2Store.LOG.entering(BasicOAuth2Store.LOG_CLASS, "storeOAuth2Accessor", accessor);
+    }
+
+    this.cache.storeOAuth2Accessor(accessor);
+
+    if (isLogging) {
+      BasicOAuth2Store.LOG.exiting(BasicOAuth2Store.LOG_CLASS, "storeOAuth2Accessor");
+    }
+  }
+}

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/GadgetOAuth2TokenStore.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/GadgetOAuth2TokenStore.java?rev=1182565&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/GadgetOAuth2TokenStore.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/GadgetOAuth2TokenStore.java Wed Oct 12 20:10:39 2011
@@ -0,0 +1,276 @@
+/*
+ * 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.oauth2;
+
+import org.apache.shindig.auth.SecurityToken;
+import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.gadgets.GadgetContext;
+import org.apache.shindig.gadgets.GadgetException;
+import org.apache.shindig.gadgets.GadgetSpecFactory;
+import org.apache.shindig.gadgets.oauth2.logger.FilteredLogger;
+import org.apache.shindig.gadgets.spec.BaseOAuthService.EndPoint;
+import org.apache.shindig.gadgets.spec.GadgetSpec;
+import org.apache.shindig.gadgets.spec.OAuth2Service;
+import org.apache.shindig.gadgets.spec.OAuth2Spec;
+
+import com.google.common.base.Joiner;
+import com.google.inject.Inject;
+
+/**
+ * Higher-level interface that allows callers to store and retrieve
+ * OAuth2-related data directly from {@code GadgetSpec}s, {@code GadgetContext}
+ * s, etc. See {@link OAuth2Store} for a more detailed explanation of the OAuth
+ * 2.0 Data Store.
+ */
+public class GadgetOAuth2TokenStore {
+
+  private final static String LOG_CLASS = GadgetOAuth2TokenStore.class.getName();
+  private static final FilteredLogger LOG = FilteredLogger
+      .getFilteredLogger(GadgetOAuth2TokenStore.LOG_CLASS);
+
+  private static class OAuth2SpecInfo {
+    private final String authorizationUrl;
+    private final String scope;
+    private final String tokenUrl;
+
+    public OAuth2SpecInfo(final String authorizationUrl, final String tokenUrl, final String scope) {
+      this.authorizationUrl = authorizationUrl;
+      this.tokenUrl = tokenUrl;
+      this.scope = scope;
+    }
+
+    public String getAuthorizationUrl() {
+      return this.authorizationUrl;
+    }
+
+    public String getScope() {
+      return this.scope;
+    }
+
+    public String getTokenUrl() {
+      return this.tokenUrl;
+    }
+  }
+
+  private final GadgetSpecFactory specFactory;
+
+  private final OAuth2Store store;
+
+  @Inject
+  public GadgetOAuth2TokenStore(final OAuth2Store store, final GadgetSpecFactory specFactory) {
+    this.store = store;
+    this.specFactory = specFactory;
+    if (GadgetOAuth2TokenStore.LOG.isLoggable()) {
+      GadgetOAuth2TokenStore.LOG.log("this.store = {0}", this.store);
+      GadgetOAuth2TokenStore.LOG.log("this.specFactory = {0}", this.specFactory);
+    }
+  }
+
+  private GadgetSpec findSpec(final SecurityToken securityToken, final OAuth2Arguments arguments,
+      final Uri gadgetUri) throws OAuth2RequestException {
+    final boolean isLogging = GadgetOAuth2TokenStore.LOG.isLoggable();
+    if (isLogging) {
+      GadgetOAuth2TokenStore.LOG.entering(GadgetOAuth2TokenStore.LOG_CLASS, "findSpec",
+          new Object[] { arguments, gadgetUri });
+    }
+
+    GadgetSpec ret = null;
+
+    try {
+      final GadgetContext context = new OAuth2GadgetContext(securityToken, arguments, gadgetUri);
+      ret = this.specFactory.getGadgetSpec(context);
+    } catch (final IllegalArgumentException e) {
+      if (isLogging) {
+        GadgetOAuth2TokenStore.LOG.log("Error finding GadgetContext " + gadgetUri.toString(), e);
+      }
+      throw new OAuth2RequestException(OAuth2Error.GADGET_SPEC_PROBLEM, gadgetUri.toString(), e);
+    } catch (final GadgetException e) {
+      if (isLogging) {
+        GadgetOAuth2TokenStore.LOG.log("Error finding GadgetContext " + gadgetUri.toString(), e);
+      }
+      throw new OAuth2RequestException(OAuth2Error.GADGET_SPEC_PROBLEM, gadgetUri.toString(), e);
+    }
+
+    if (isLogging) {
+      // this is cumbersome in the logs, just return whether or not it's null
+      if (ret == null) {
+        GadgetOAuth2TokenStore.LOG.exiting(GadgetOAuth2TokenStore.LOG_CLASS, "findSpec", null);
+      } else {
+        GadgetOAuth2TokenStore.LOG.exiting(GadgetOAuth2TokenStore.LOG_CLASS, "findSpec",
+            "non-null spec omitted from logs");
+      }
+    }
+
+    return ret;
+  }
+
+  /**
+   * Retrieves and merges the data from the {@link OAuth2Store}, the gadget spec
+   * and the request itself to populate the OAuth2 data for this requets.
+   * 
+   * @param securityToken
+   *          {@link SecurityToken} from the request
+   * @param arguments
+   *          {@link OAuth2Arguments} from the request
+   * @param gadgetUri
+   *          gadget uri from the request
+   * @return the {@link OAuth2Accessor} for the request
+   * @throws OAuth2RequestException
+   */
+  public OAuth2Accessor getOAuth2Accessor(final SecurityToken securityToken,
+      final OAuth2Arguments arguments, final Uri gadgetUri) {
+
+    final boolean isLogging = GadgetOAuth2TokenStore.LOG.isLoggable();
+    if (isLogging) {
+      GadgetOAuth2TokenStore.LOG.entering(GadgetOAuth2TokenStore.LOG_CLASS, "getOAuth2Accessor",
+          new Object[] { securityToken, arguments, gadgetUri });
+    }
+
+    OAuth2Accessor ret = null;
+
+    if ((this.store == null) || (gadgetUri == null) || (securityToken == null)) {
+      ret = new BasicOAuth2Accessor(null, OAuth2Error.GET_OAUTH2_ACCESSOR_PROBLEM,
+          "OAuth2Accessor missing a param --- store = " + this.store + " , gadgetUri = "
+              + gadgetUri + " , securityToken = " + securityToken, "");
+    } else {
+      final String serviceName = arguments != null ? arguments.getServiceName() : "";
+
+      OAuth2SpecInfo specInfo = null;
+      try {
+        specInfo = this.lookupSpecInfo(securityToken, arguments, gadgetUri);
+      } catch (final OAuth2RequestException e1) {
+        if (isLogging) {
+          GadgetOAuth2TokenStore.LOG.log("No gadget spec", e1);
+        }
+        ret = new BasicOAuth2Accessor(e1, OAuth2Error.NO_GADGET_SPEC, "gadgetUri = " + gadgetUri
+            + " , serviceName = " + serviceName, "");
+      }
+
+      if (specInfo == null) {
+        ret = new BasicOAuth2Accessor(null, OAuth2Error.NO_GADGET_SPEC, "gadgetUri = " + gadgetUri
+            + " , serviceName = " + serviceName, "");
+      }
+
+      if ((ret == null) && (arguments != null) && (specInfo != null)) {
+        String scope = arguments.getScope();
+        if ((scope == null) || (scope.length() == 0)) {
+          // no scope on request, default to module prefs scope
+          scope = specInfo.getScope();
+        }
+
+        if ((scope == null) || (scope.length() == 0)) {
+          scope = "";
+        }
+
+        OAuth2Accessor persistedAccessor;
+        try {
+          persistedAccessor = this.store.getOAuth2Accessor(gadgetUri.toString(), serviceName,
+              securityToken.getViewerId(), scope);
+        } catch (final GadgetException e) {
+          if (isLogging) {
+            GadgetOAuth2TokenStore.LOG.log("Exception in getOAuth2Accessor", e);
+          }
+          persistedAccessor = null;
+        }
+
+        if (persistedAccessor == null) {
+          ret = new BasicOAuth2Accessor(null, OAuth2Error.GET_OAUTH2_ACCESSOR_PROBLEM,
+              "gadgetUri = " + gadgetUri + " , serviceName = " + serviceName, "");
+        } else {
+          final OAuth2Accessor mergedAccessor = new BasicOAuth2Accessor(persistedAccessor);
+
+          if (persistedAccessor.isAllowModuleOverrides()) {
+            final String specAuthorizationUrl = specInfo.getAuthorizationUrl();
+            final String specTokenUrl = specInfo.getTokenUrl();
+
+            if ((specAuthorizationUrl != null) && (specAuthorizationUrl.length() > 0)) {
+              mergedAccessor.setAuthorizationUrl(specAuthorizationUrl);
+            }
+            if ((specTokenUrl != null) && (specTokenUrl.length() > 0)) {
+              mergedAccessor.setTokenUrl(specTokenUrl);
+            }
+          }
+
+          this.store.storeOAuth2Accessor(mergedAccessor);
+
+          ret = mergedAccessor;
+        }
+      }
+    }
+
+    if (isLogging) {
+      GadgetOAuth2TokenStore.LOG
+          .exiting(GadgetOAuth2TokenStore.LOG_CLASS, "getOAuth2Accessor", ret);
+    }
+
+    return ret;
+  }
+
+  /**
+   * 
+   * @return the {@link OAuth2Store}, never <code>null</code>
+   */
+  public OAuth2Store getOAuth2Store() {
+    return this.store;
+  }
+
+  private OAuth2SpecInfo lookupSpecInfo(final SecurityToken securityToken,
+      final OAuth2Arguments arguments, final Uri gadgetUri) throws OAuth2RequestException {
+
+    final boolean isLogging = GadgetOAuth2TokenStore.LOG.isLoggable();
+    if (isLogging) {
+      GadgetOAuth2TokenStore.LOG.entering(GadgetOAuth2TokenStore.LOG_CLASS, "lookupSpecInfo",
+          new Object[] { securityToken, arguments, gadgetUri });
+    }
+
+    final GadgetSpec spec = this.findSpec(securityToken, arguments, gadgetUri);
+    final OAuth2Spec oauthSpec = spec.getModulePrefs().getOAuth2Spec();
+    if (oauthSpec == null) {
+      throw new OAuth2RequestException(OAuth2Error.LOOKUP_SPEC_PROBLEM,
+          "Failed to retrieve OAuth URLs, spec for gadget " + securityToken.getAppUrl()
+              + " does not contain OAuth element.", null);
+    }
+    final OAuth2Service service = oauthSpec.getServices().get(arguments.getServiceName());
+    if (service == null) {
+      throw new OAuth2RequestException(OAuth2Error.LOOKUP_SPEC_PROBLEM,
+          "Failed to retrieve OAuth URLs, spec for gadget does not contain OAuth service "
+              + arguments.getServiceName() + ".  Known services: "
+              + Joiner.on(',').join(oauthSpec.getServices().keySet()) + '.', null);
+    }
+
+    String authorizationUrl = null;
+    final EndPoint authorizationUrlEndpoint = service.getAuthorizationUrl();
+    if (authorizationUrlEndpoint != null) {
+      authorizationUrl = authorizationUrlEndpoint.url.toString();
+    }
+
+    String tokenUrl = null;
+    final EndPoint tokenUrlEndpoint = service.getTokenUrl();
+    if (tokenUrlEndpoint != null) {
+      tokenUrl = tokenUrlEndpoint.url.toString();
+    }
+
+    final OAuth2SpecInfo ret = new OAuth2SpecInfo(authorizationUrl, tokenUrl, service.getScope());
+
+    if (isLogging) {
+      GadgetOAuth2TokenStore.LOG.exiting(GadgetOAuth2TokenStore.LOG_CLASS, "lookupSpecInfo", ret);
+    }
+
+    return ret;
+  }
+}

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/OAuth2Accessor.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/OAuth2Accessor.java?rev=1182565&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/OAuth2Accessor.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/OAuth2Accessor.java Wed Oct 12 20:10:39 2011
@@ -0,0 +1,254 @@
+/*
+ * 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.oauth2;
+
+import java.io.Serializable;
+
+import org.apache.shindig.gadgets.oauth2.handler.ClientAuthenticationHandler;
+
+/**
+ * OAuth2 related data accessor.
+ * 
+ * Every {@link OAuth2Request} will create an accessor and store it in the
+ * OAuth2Store while the request is being issued. It will be removed when the
+ * request is done (success or failure.)
+ * 
+ * OAuth2Accessor implementations should be {@link Serializable} to facilitate
+ * cluster storage and caching across the various phases of OAuth 2.0 flows.
+ */
+
+public interface OAuth2Accessor extends Serializable {
+  /**
+   * 
+   * Enumeration of possible accessor types
+   * 
+   */
+  public enum Type {
+    CONFIDENTIAL, PUBLIC, UNKNOWN
+  }
+
+  /**
+   * 
+   * @return the access {@link OAuth2Token} or <code>null</code>
+   */
+  public OAuth2Token getAccessToken();
+
+  /**
+   * 
+   * @return the authorization endpoint for this accessor.
+   */
+  public String getAuthorizationUrl();
+
+  /**
+   * see {@link ClientAuthenticationHandler}
+   * 
+   * @return the type of client authentication the service provider expects
+   */
+  public String getClientAuthenticationType();
+
+  /**
+   * 
+   * @return the "client_id" for this accessor
+   */
+  public String getClientId();
+
+  /**
+   * 
+   * @return the "client_secret" for this accessor
+   */
+  public byte[] getClientSecret();
+
+  /**
+   * 
+   * 
+   */
+  public OAuth2Error getError();
+
+  /**
+   * 
+   */
+  public String getErrorContextMessage();
+
+  /**
+   * 
+   * @return the error exception, if this is an error, otherwise
+   *         <code>null</code>
+   */
+  public Throwable getErrorException();
+
+  /**
+   * 
+   * @return the error uri, if this is an error, otherwise <code>null</code>
+   */
+  public String getErrorUri();
+
+  /**
+   * 
+   * @return the URI of the gadget issuing the request
+   */
+  public String getGadgetUri();
+
+  /**
+   * 
+   * @return grant_type of this client, e.g. "code" or "client_credentials"
+   */
+  public String getGrantType();
+
+  /**
+   * 
+   * @return redirect_uri of the client for this accessor
+   */
+  public String getRedirectUri();
+
+  /**
+   * 
+   * @return the refresh {@link OAuth2Token} or <code>null</code>
+   */
+  public OAuth2Token getRefreshToken();
+
+  /**
+   * if the gadget request or gadget spec specifies a scope it will be set here
+   * 
+   * See {@link http://tools.ietf.org/html/draft-ietf-oauth-v2-21#section-3.3}
+   * 
+   * @return scope of the request, or "" if none was specified
+   */
+  public String getScope();
+
+  /**
+   * 
+   * @return the service name from the gadget spec, defaults to ""
+   */
+  public String getServiceName();
+
+  /**
+   * 
+   * @return the state to include on authorization requests
+   */
+  public String getState();
+
+  /**
+   * 
+   * @return the token endpoint for this accessor.
+   */
+  public String getTokenUrl();
+
+  /**
+   * 
+   * @return the {@link Type} of client for this accessor
+   */
+  public Type getType();
+
+  /**
+   * 
+   * @return of the page viewer
+   */
+  public String getUser();
+
+  /**
+   * invalidates the accessor once the request is done.
+   * 
+   */
+  public void invalidate();
+
+  /**
+   * 
+   * @return <code>true</code> if the gadget's <ModulePrefs> can override
+   *         accessor settings
+   */
+  public boolean isAllowModuleOverrides();
+
+  /**
+   * Indicates the service provider wants the access token in an
+   * "Authorization:" header, per the spec.
+   * 
+   * @return
+   */
+  public boolean isAuthorizationHeader();
+
+  /**
+   * 
+   * @return if an error response needs to be sent to the client
+   */
+  public boolean isErrorResponse();
+
+  /**
+   * is this accessor in the middle of a authorize redirect?
+   * 
+   * @return
+   */
+  public boolean isRedirecting();
+
+  /**
+   * Indicates the service provider wants the access token in an URL Parameter.
+   * This goes against the spec but Google, Facebook and Microsoft all expect
+   * it.
+   * 
+   * @return
+   */
+  public boolean isUrlParameter();
+
+  public boolean isValid();
+
+  /**
+   * updates the access token for the request (does not add it to
+   * {@link OAuth2Store})
+   * 
+   * @param accessToken
+   */
+  public void setAccessToken(OAuth2Token accessToken);
+
+  /**
+   * updates the authorization endpoint url
+   * 
+   * @param authorizationUrl
+   */
+  public void setAuthorizationUrl(String authorizationUrl);
+
+  /**
+   * 
+   * @param exception
+   * @param error
+   * @param contextMessage
+   * @param errorUri
+   */
+  public void setErrorResponse(Throwable exception, OAuth2Error error, String contextMessage,
+      String errorUri);
+
+  /**
+   * Used to communicate that we are in a redirect authorization flow and the
+   * accessor should be preserved.
+   * 
+   * @param redirecting
+   */
+  public void setRedirecting(boolean redirecting);
+
+  /**
+   * updates the refresh token for the request (does not add it to
+   * {@link OAuth2Store})
+   * 
+   * @param accessToken
+   */
+  public void setRefreshToken(OAuth2Token refreshToken);
+
+  /**
+   * updates the token endpoint url
+   * 
+   * @param tokenUrl
+   */
+  public void setTokenUrl(String tokenUrl);
+}

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/OAuth2Arguments.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/OAuth2Arguments.java?rev=1182565&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/OAuth2Arguments.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/OAuth2Arguments.java Wed Oct 12 20:10:39 2011
@@ -0,0 +1,156 @@
+/*
+ * 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.oauth2;
+
+import java.util.Enumeration;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.shindig.gadgets.AuthType;
+import org.apache.shindig.gadgets.GadgetException;
+import org.apache.shindig.gadgets.spec.RequestAuthenticationInfo;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.Maps;
+
+/**
+ * Arguments to an OAuth2 fetch sent by the client.
+ */
+public class OAuth2Arguments {
+  private static final String BYPASS_SPEC_CACHE_PARAM = "bypassSpecCache";
+  private static final String SCOPE_PARAM = "OAUTH_SCOPE";
+  private static final String SERVICE_PARAM = "OAUTH_SERVICE_NAME";
+
+  private final boolean bypassSpecCache;
+  private final Map<String, String> requestOptions = Maps.newTreeMap();
+  private final String scope;
+  private final String serviceName;
+
+  public OAuth2Arguments(final AuthType auth, final Map<String, String> map) {
+    if (AuthType.OAUTH2.equals(auth)) {
+      this.requestOptions.putAll(map);
+      this.serviceName = OAuth2Arguments.getAuthInfoParam(this.requestOptions,
+          OAuth2Arguments.SERVICE_PARAM, "");
+      this.scope = OAuth2Arguments.getAuthInfoParam(this.requestOptions,
+          OAuth2Arguments.SCOPE_PARAM, "");
+      this.bypassSpecCache = "1".equals(OAuth2Arguments.getAuthInfoParam(this.requestOptions,
+          OAuth2Arguments.BYPASS_SPEC_CACHE_PARAM, null));
+    } else {
+      this.serviceName = null;
+      this.scope = null;
+      this.bypassSpecCache = false;
+    }
+  }
+
+  /**
+   * Public constructor to parse OAuth2Arguments from a
+   * {@link HttpServletRequest}
+   * 
+   * @param request
+   *          {@link HttpServletRequest} that came into the server
+   * @throws GadgetException
+   */
+  public OAuth2Arguments(final HttpServletRequest request) throws GadgetException {
+    this.serviceName = OAuth2Arguments.getRequestParam(request, OAuth2Arguments.SERVICE_PARAM, "");
+    this.scope = OAuth2Arguments.getRequestParam(request, OAuth2Arguments.SCOPE_PARAM, "");
+    this.bypassSpecCache = "1".equals(OAuth2Arguments.getRequestParam(request,
+        OAuth2Arguments.BYPASS_SPEC_CACHE_PARAM, null));
+    final Enumeration<String> params = OAuth2Arguments.getParameterNames(request);
+    while (params.hasMoreElements()) {
+      final String name = params.nextElement();
+      this.requestOptions.put(name, request.getParameter(name));
+    }
+  }
+
+  public OAuth2Arguments(final OAuth2Arguments orig) {
+    this.serviceName = orig.serviceName;
+    this.scope = orig.scope;
+    this.bypassSpecCache = orig.bypassSpecCache;
+    this.requestOptions.putAll(orig.requestOptions);
+  }
+
+  public OAuth2Arguments(final RequestAuthenticationInfo info) {
+    this(info.getAuthType(), info.getAttributes());
+  }
+
+  @Override
+  public boolean equals(final Object obj) {
+    if (this == obj) {
+      return true;
+    }
+
+    if (!(obj instanceof OAuth2Arguments)) {
+      return false;
+    }
+
+    final OAuth2Arguments other = (OAuth2Arguments) obj;
+    return (this.bypassSpecCache == other.getBypassSpecCache())
+        && this.serviceName.equals(other.getServiceName());
+  }
+
+  public boolean getBypassSpecCache() {
+    return this.bypassSpecCache;
+  }
+
+  @SuppressWarnings("unchecked")
+  private static Enumeration<String> getParameterNames(final HttpServletRequest request) {
+    return request.getParameterNames();
+  }
+
+  public String getRequestOption(String name) {
+    return this.requestOptions.get(name);
+  }
+
+  public String getRequestOption(String name, String def) {
+    final String val = this.requestOptions.get(name);
+    return (val != null ? val : def);
+  }
+
+  public String getScope() {
+    return this.scope;
+  }
+
+  public String getServiceName() {
+    return this.serviceName;
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hashCode(this.bypassSpecCache, this.serviceName);
+  }
+
+  private static String getAuthInfoParam(final Map<String, String> attrs, final String name,
+      final String def) {
+    String val = attrs.get(name);
+    if (val == null) {
+      val = def;
+    }
+    return val;
+  }
+
+  private static String getRequestParam(final HttpServletRequest request, final String name,
+      final String def) {
+    String val = request.getParameter(name);
+    if (val == null) {
+      val = def;
+    }
+    return val;
+  }
+}
\ No newline at end of file

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/OAuth2Error.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/OAuth2Error.java?rev=1182565&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/OAuth2Error.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/OAuth2Error.java Wed Oct 12 20:10:39 2011
@@ -0,0 +1,129 @@
+/*
+ * 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.oauth2;
+
+import java.text.MessageFormat;
+import java.util.ResourceBundle;
+
+import org.apache.shindig.gadgets.oauth2.logger.FilteredLogger;
+
+/**
+ * Any time there's an error in the OAuth2 layer it's reported with an
+ * OAuth2Error.
+ * 
+ * errorCode - should correspond to an OAuth2Message errorCode when appropriate.
+ * 
+ */
+public enum OAuth2Error {
+  AUTHORIZATION_CODE_PROBLEM("authorization_code_problem"),
+  AUTHORIZE_PROBLEM("authorize_problem"),
+  AUTHENTICATION_PROBLEM( "authentication_problem"),
+  BEARER_TOKEN_PROBLEM("bearer_token_problem"), 
+  CALLBACK_PROBLEM("callback_problem"),
+  CLIENT_CREDENTIALS_PROBLEM("client_credentials_problem"),
+  CODE_GRANT_PROBLEM("code_grant_problem"),
+  FETCH_INIT_PROBLEM("fetch_init_problem"),
+  FETCH_PROBLEM("fetch_problem"),
+  GADGET_SPEC_PROBLEM("gadget_spec_problem"),
+  GET_OAUTH2_ACCESSOR_PROBLEM("get_oauth2_accessor_problem"),
+  LOOKUP_SPEC_PROBLEM("lookup_spec_problem"),
+  MAC_TOKEN_PROBLEM("mac_token_problem"),
+  MISSING_FETCH_PARAMS("missing_fetch_params"),
+  MISSING_SERVER_RESPONSE("missing_server_response"),
+  NO_RESPONSE_HANDLER("no_response_handler"),
+  NO_GADGET_SPEC("no_gadget_spec"),
+  REFRESH_TOKEN_PROBLEM("refresh_token_problem"),
+  SECRET_ENCRYPTION_PROBLEM("secret_encryption_problem"),
+  SPEC_ACCESS_DENIED("access_denied"),
+  SPEC_INVALID_CLIENT("invalid_client"),
+  SPEC_INVALID_GRANT("invalid_grant"),
+  SPEC_INVALID_REQUEST("invalid_request"),
+  SPEC_INVALID_SCOPE("invalid_scope"),
+  SPEC_SERVER_ERROR("server_error"),
+  SPEC_TEMPORARILY_UNAVAILABLE("temporarily_unavailable"),
+  SPEC_UNAUTHORIZED_CLIENT("unauthorized_client"),
+  SPEC_UNSUPPORTED_GRANT_TYPE("unsupported_grant_type"),
+  SPEC_UNSUPPORTED_RESPONSE_TYPE("unsupported_response_type"),
+  SERVER_REJECTED_REQUEST("server_rejected_request"),
+  TOKEN_RESPONSE_PROBLEM("token_response_problem"),
+  UNKNOWN_PROBLEM("unknown_problem");
+
+  public static final String MESSAGES = "org.apache.shindig.gadgets.oauth2.resource";
+
+  private static final String MESSAGE_HEADER = "message_header";
+
+  private final String errorCode;
+  private final String errorDescription;
+  private final String errorExplanation;
+
+  private OAuth2Error(final String errorCode) {
+    this.errorCode = errorCode;
+    String header = OAuth2Request.class.getName() + " encountered a problem: ";
+    String _errorDescription = errorCode;
+    String _errorExplanation = errorCode;
+
+    FilteredLogger LOG = null;
+    try {
+      LOG = FilteredLogger.getFilteredLogger(OAuth2Error.class.getName());
+      final ResourceBundle resourceBundle = LOG.getResourceBundle();
+      if (resourceBundle != null) {
+        final String bundleHeader = resourceBundle.getString(OAuth2Error.MESSAGE_HEADER);
+        if (bundleHeader != null) {
+          header = MessageFormat.format(bundleHeader, OAuth2Request.class.getName());
+        }
+
+        final String bundleErrorDescription = resourceBundle.getString(this.errorCode);
+        if ((bundleErrorDescription == null) || (bundleErrorDescription.length() == 0)) {
+          _errorDescription = header + this.errorCode;
+        } else {
+          _errorDescription = header + bundleErrorDescription;
+        }
+
+        final String bundleErrorExplanation = resourceBundle.getString(this.errorCode
+            + ".explanation");
+        if ((bundleErrorExplanation == null) || (bundleErrorExplanation.length() == 0)) {
+          _errorExplanation = _errorDescription;
+        } else {
+          _errorExplanation = bundleErrorExplanation;
+        }
+      }
+    } catch (final Exception e) {
+      if (LOG != null) {
+        if (LOG.isLoggable()) {
+          LOG.log("error loading OAuth2Error messages", e);
+        }
+      } else {
+        e.printStackTrace();
+      }
+    }
+
+    this.errorDescription = _errorDescription;
+    this.errorExplanation = _errorExplanation;
+  }
+
+  public String getErrorCode() {
+    return this.errorCode;
+  }
+
+  public String getErrorDescription(final Object... objects) {
+    return MessageFormat.format(this.errorDescription, objects);
+  }
+
+  public String getErrorExplanation() {
+    return this.errorExplanation;
+  }
+}
\ No newline at end of file

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/OAuth2FetcherConfig.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/OAuth2FetcherConfig.java?rev=1182565&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/OAuth2FetcherConfig.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/OAuth2FetcherConfig.java Wed Oct 12 20:10:39 2011
@@ -0,0 +1,56 @@
+/*
+ * 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.oauth2;
+
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+
+/**
+ * Configuration parameters for an OAuth2Request
+ */
+public class OAuth2FetcherConfig {
+  private final GadgetOAuth2TokenStore tokenStore;
+  private final boolean viewerAccessTokensEnabled;
+
+  @Inject
+  public OAuth2FetcherConfig(final GadgetOAuth2TokenStore tokenStore,
+      @Named("shindig.oauth2.viewer-access-tokens-enabled") final boolean viewerAccessTokensEnabled) {
+    this.tokenStore = tokenStore;
+    this.viewerAccessTokensEnabled = viewerAccessTokensEnabled;
+  }
+
+  /**
+   * @return the store with persisted client and token information
+   */
+  public OAuth2Store getOAuth2Store() {
+    return this.tokenStore.getOAuth2Store();
+  }
+
+  /**
+   * @return the store with gadget spec information
+   */
+  public GadgetOAuth2TokenStore getTokenStore() {
+    return this.tokenStore;
+  }
+
+  /**
+   * @return true if the owner pages do not allow user controlled javascript
+   */
+  public boolean isViewerAccessTokensEnabled() {
+    return this.viewerAccessTokensEnabled;
+  }
+}