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 [4/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/handler/CodeGrantTypeHandler.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/CodeGrantTypeHandler.java?rev=1182565&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/CodeGrantTypeHandler.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/CodeGrantTypeHandler.java Wed Oct 12 20:10:39 2011
@@ -0,0 +1,105 @@
+/*
+ * 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.handler;
+
+import java.util.Map;
+
+import org.apache.shindig.gadgets.http.HttpRequest;
+import org.apache.shindig.gadgets.oauth2.OAuth2Accessor;
+import org.apache.shindig.gadgets.oauth2.OAuth2Error;
+import org.apache.shindig.gadgets.oauth2.OAuth2Message;
+import org.apache.shindig.gadgets.oauth2.OAuth2RequestException;
+import org.apache.shindig.gadgets.oauth2.OAuth2Utils;
+
+import com.google.common.collect.Maps;
+import com.google.inject.Inject;
+
+/**
+ * 
+ * See {@link GrantRequestHandler}
+ * 
+ * Handles the "authorization_code" flow
+ */
+public class CodeGrantTypeHandler implements GrantRequestHandler {
+  private static final OAuth2Error ERROR = OAuth2Error.CODE_GRANT_PROBLEM;
+
+  @Inject
+  public CodeGrantTypeHandler() {
+  }
+
+  public HttpRequest getAuthorizationRequest(final OAuth2Accessor accessor,
+      final String completeAuthorizationUrl) throws OAuth2RequestException {
+    throw new OAuth2RequestException(CodeGrantTypeHandler.ERROR,
+        "inappropriate call to CodeGrantTypeHandler.getAuthorizationRequest()", null);
+  }
+
+  public String getCompleteUrl(final OAuth2Accessor accessor) throws OAuth2RequestException {
+    if (accessor == null) {
+      throw new OAuth2RequestException(CodeGrantTypeHandler.ERROR, "accessor is null", null);
+    }
+
+    if (!accessor.isValid() || accessor.isErrorResponse() || accessor.isRedirecting()) {
+      throw new OAuth2RequestException(CodeGrantTypeHandler.ERROR, "accessor is invalid", null);
+    }
+
+    if (!accessor.getGrantType().equalsIgnoreCase(OAuth2Message.AUTHORIZATION)) {
+      throw new OAuth2RequestException(CodeGrantTypeHandler.ERROR, "grant type is not code", null);
+    }
+
+    final Map<String, String> queryParams = Maps.newHashMapWithExpectedSize(4);
+    queryParams.put(OAuth2Message.RESPONSE_TYPE, this.getGrantType());
+    queryParams.put(OAuth2Message.CLIENT_ID, accessor.getClientId());
+    final String redirectUri = accessor.getRedirectUri();
+    if ((redirectUri != null) && (redirectUri.length() > 0)) {
+      queryParams.put(OAuth2Message.REDIRECT_URI, redirectUri);
+    }
+
+    final String state = accessor.getState();
+    if ((state != null) && (state.length() > 0)) {
+      queryParams.put(OAuth2Message.STATE, state);
+    }
+
+    final String scope = accessor.getScope();
+    if ((scope != null) && (scope.length() > 0)) {
+      queryParams.put(OAuth2Message.SCOPE, scope);
+    }
+
+    final String ret = OAuth2Utils.buildUrl(accessor.getAuthorizationUrl(), queryParams, null);
+
+    return ret;
+  }
+
+  public String getGrantType() {
+    return OAuth2Message.AUTHORIZATION;
+  }
+
+  public static String getResponseType() {
+    return OAuth2Message.AUTHORIZATION_CODE;
+  }
+
+  public boolean isAuthorizationEndpointResponse() {
+    return true;
+  }
+
+  public boolean isRedirectRequired() {
+    return true;
+  }
+
+  public boolean isTokenEndpointResponse() {
+    return false;
+  }
+}
\ No newline at end of file

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/GrantRequestHandler.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/GrantRequestHandler.java?rev=1182565&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/GrantRequestHandler.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/GrantRequestHandler.java Wed Oct 12 20:10:39 2011
@@ -0,0 +1,82 @@
+/*
+ * 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.handler;
+
+import org.apache.shindig.gadgets.http.HttpRequest;
+import org.apache.shindig.gadgets.oauth2.OAuth2Accessor;
+import org.apache.shindig.gadgets.oauth2.OAuth2RequestException;
+
+/**
+ * Enables injection of new Grant Type schemes into the system.
+ * 
+ * If a {@link GrantRequestHandler#getGrantType()} matches a
+ * {@link OAuth2Accessor#getGrantType()} it will be invoked to initiate the
+ * grant request.
+ * 
+ * By default "code" and "client_credentials" are supported.
+ * 
+ * Only one GrantRequestHandler will be executed (first to match.)
+ * 
+ */
+public interface GrantRequestHandler {
+  /**
+   * If {@link #isRedirectRequired()} is false the system will executes this
+   * request.
+   * 
+   * @param accessor
+   * @param completeAuthorizationUrl
+   * @return HttpRequest
+   * @throws OAuth2RequestException
+   */
+  public HttpRequest getAuthorizationRequest(OAuth2Accessor accessor,
+      String completeAuthorizationUrl) throws OAuth2RequestException;
+
+  /**
+   * Url to send redirects to.
+   * 
+   * @param accessor
+   * @return String complete url
+   * @throws OAuth2RequestException
+   */
+  public String getCompleteUrl(OAuth2Accessor accessor) throws OAuth2RequestException;
+
+  /**
+   * 
+   * @return the grant_type this handler initiates
+   */
+  public String getGrantType();
+
+  /**
+   * 
+   * @return true if the response is from the authorization endpoint, i.e. code
+   */
+  public boolean isAuthorizationEndpointResponse();
+
+  /**
+   * 
+   * @return true to redirect the client to the
+   *         {@link #getCompleteUrl(OAuth2Accessor)}
+   */
+  public boolean isRedirectRequired();
+
+  /**
+   * 
+   * @return true if the response is from the token endpoint i.e.
+   *         client_credentials
+   */
+  public boolean isTokenEndpointResponse();
+}

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/MacTokenHandler.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/MacTokenHandler.java?rev=1182565&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/MacTokenHandler.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/MacTokenHandler.java Wed Oct 12 20:10:39 2011
@@ -0,0 +1,266 @@
+/*
+ * 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.handler;
+
+import java.io.UnsupportedEncodingException;
+import java.security.GeneralSecurityException;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.shindig.common.crypto.Crypto;
+import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.gadgets.http.HttpRequest;
+import org.apache.shindig.gadgets.oauth2.OAuth2Accessor;
+import org.apache.shindig.gadgets.oauth2.OAuth2Error;
+import org.apache.shindig.gadgets.oauth2.OAuth2Message;
+import org.apache.shindig.gadgets.oauth2.OAuth2Token;
+
+/**
+ * 
+ * See {@link ResourceRequestHandler}
+ * 
+ * Handles the mac token type
+ */
+public class MacTokenHandler implements ResourceRequestHandler {
+  public static final String TOKEN_TYPE = OAuth2Message.MAC_TOKEN_TYPE;
+  private static final OAuth2Error ERROR = OAuth2Error.MAC_TOKEN_PROBLEM;
+
+  public MacTokenHandler() {
+  }
+
+  public OAuth2HandlerError addOAuth2Params(final OAuth2Accessor accessor, final HttpRequest request) {
+    try {
+      final OAuth2HandlerError handlerError = MacTokenHandler.validateOAuth2Params(accessor, request);
+      if (handlerError != null) {
+        return handlerError;
+      }
+
+      final OAuth2Token accessToken = accessor.getAccessToken();
+
+      String ext = accessToken.getMacExt();
+      if ((ext == null) || (ext.length() == 0)) {
+        ext = "";
+      }
+
+      // REQUIRED. The MAC key identifier.
+      final String id = new String(accessToken.getSecret(), "UTF-8");
+
+      // REQUIRED. A unique string generated by the client to allow the
+      // server to verify that a request has never been made before and
+      // helps prevent replay attacks when requests are made over an
+      // insecure channel. The nonce value MUST be unique across all
+      // requests with the same MAC key identifier.
+      // The nonce value MUST consist of the age of the MAC credentials
+      // expressed as the number of seconds since the credentials were
+      // issued to the client, a colon character (%x25), and a unique
+      // string (typically random). The age value MUST be a positive
+      // integer and MUST NOT include leading zeros (e.g.
+      // "000137131200"). For example: "273156:di3hvdf8".
+      // To avoid the need to retain an infinite number of nonce values
+      // for future checks, the server MAY choose to restrict the time
+      // period after which a request with an old age is rejected. If
+      // such a restriction is enforced, the server SHOULD allow for a
+      // sufficiently large window to accommodate network delays which
+      // will affect the credentials issue time used by the client to
+      // calculate the credentials' age.
+      final long currentTime = System.currentTimeMillis() / 1000;
+      final String nonce = Long.toString(currentTime - accessToken.getIssuedAt()) + ':'
+          + String.valueOf(Math.abs(Crypto.RAND.nextLong()));
+
+      // OPTIONAL. The HTTP request payload body hash as described in
+      // Section 3.2.
+
+      String bodyHash = MacTokenHandler.getBodyHash(request, accessToken.getMacSecret(),
+          accessToken.getMacAlgorithm());
+      if (bodyHash == null) {
+        bodyHash = "";
+      }
+
+      // mac
+      // REQUIRED. The HTTP request MAC as described in Section 3.3.
+      final Uri uri = request.getUri();
+
+      String uriString = uri.getPath();
+      if (uri.getQuery() != null) {
+        uriString = uriString + '?' + uri.getQuery();
+      }
+
+      String host = uri.getAuthority();
+      String port = "80";
+      final int index = host.indexOf(':');
+      if (index > 0) {
+        port = host.substring(index + 1);
+        host = host.substring(0, index);
+      } else {
+        final String scheme = uri.getScheme();
+        if ("https".equals(scheme)) {
+          port = "443";
+        }
+      }
+
+      final String mac = MacTokenHandler.getMac(nonce, request.getMethod(), uriString, host, port,
+          bodyHash, ext, accessToken.getMacSecret(), accessToken.getMacAlgorithm());
+
+      final String headerString = buildHeaderString(id, nonce, bodyHash, ext, mac);
+
+      request.setHeader(OAuth2Message.AUTHORIZATION_HEADER, headerString);
+      return null;
+    } catch (final Exception e) {
+      return MacTokenHandler.getError("Exception occurred " + e.getMessage(), e);
+    }
+  }
+
+  private static String buildHeaderString(String id, String nonce, String bodyHash, String ext, String mac) {
+    final StringBuilder headerString = new StringBuilder();
+
+    headerString.append(OAuth2Message.MAC_HEADER);
+    headerString.append(" id = \"");
+    headerString.append(id);
+    headerString.append("\",");
+    headerString.append(OAuth2Message.NONCE);
+    headerString.append("=\"");
+    headerString.append(nonce);
+    if (bodyHash.length() > 0) {
+      headerString.append("\",");
+      headerString.append(OAuth2Message.BODYHASH);
+      headerString.append("=\"");
+      headerString.append(bodyHash);
+    }
+    if (ext.length() > 0) {
+      headerString.append("\",");
+      headerString.append(OAuth2Message.MAC_EXT);
+      headerString.append("=\"");
+      headerString.append(ext);
+    }
+    headerString.append("\",");
+    headerString.append(OAuth2Message.MAC);
+    headerString.append("=\"");
+    headerString.append(mac);
+    headerString.append('\"');
+    return headerString.toString();
+  }
+
+  private static OAuth2HandlerError validateOAuth2Params(OAuth2Accessor accessor, HttpRequest request) {
+    if ((accessor == null) || (!accessor.isValid()) || (accessor.isErrorResponse())) {
+      return MacTokenHandler.getError("accessor is invalid " + accessor);
+    }
+
+    if (request == null) {
+      return MacTokenHandler.getError("request is null");
+    }
+
+    final OAuth2Token accessToken = accessor.getAccessToken();
+
+    if ((accessToken == null) || (accessToken.getTokenType().length() == 0)) {
+      return MacTokenHandler.getError("accessToken is invalid " + accessToken);
+    }
+
+    if (!MacTokenHandler.TOKEN_TYPE.equalsIgnoreCase(accessToken.getTokenType())) {
+      return MacTokenHandler.getError("token type mismatch expected " + MacTokenHandler.TOKEN_TYPE
+          + " but got " + accessToken.getTokenType());
+    }
+
+    final String algorithm = accessToken.getMacAlgorithm();
+    if ((algorithm == null) || (algorithm.length() == 0)) {
+      return MacTokenHandler.getError("invalid mac algorithm " + algorithm);
+    }
+
+    if (!OAuth2Message.HMAC_SHA_1.equalsIgnoreCase(algorithm)) {
+      return MacTokenHandler.getError("unsupported algorithm " + algorithm);
+    }
+
+    final byte[] macSecret = accessToken.getMacSecret();
+    if (macSecret == null) {
+      return MacTokenHandler.getError("mac secret is null");
+    }
+
+    if (macSecret.length == 0) {
+      return MacTokenHandler.getError("invalid mac secret");
+    }
+
+    return null;
+  }
+
+  public String getTokenType() {
+    return MacTokenHandler.TOKEN_TYPE;
+  }
+
+  private static String getBodyHash(final HttpRequest request, final byte[] key,
+      final String algorithm) throws UnsupportedEncodingException, GeneralSecurityException {
+    if (request.getPostBodyLength() > 0) {
+      final byte[] text = MacTokenHandler.getBody(request);
+      final byte[] hashed = MacTokenHandler.hash(text, key, algorithm);
+      return new String(hashed, "UTF-8");
+    }
+
+    return "";
+  }
+
+  private static byte[] getBody(final HttpRequest request) throws UnsupportedEncodingException {
+    return request.getPostBodyAsString().getBytes("UTF-8");
+  }
+
+  private static String getMac(final String nonce, final String method, final String uri,
+      final String host, final String port, final String bodyHash, final String ext,
+      final byte[] key, final String algorithm) throws UnsupportedEncodingException,
+      GeneralSecurityException {
+    final StringBuilder normalizedRequestString = MacTokenHandler.getNormalizedRequestString(nonce,
+        method, uri, host, port, bodyHash, ext);
+    final byte[] normalizedRequestBytes = normalizedRequestString.toString().getBytes("UTF-8");
+    final byte[] mac = MacTokenHandler.hash(normalizedRequestBytes, key, algorithm);
+    final byte[] encodedBytes = Base64.encodeBase64(mac);
+    return new String(encodedBytes, "UTF-8");
+  }
+
+  private static byte[] hash(final byte[] text, byte[] key, final String algorithm)
+      throws GeneralSecurityException {
+    if (OAuth2Message.HMAC_SHA_1.equalsIgnoreCase(algorithm)) {
+      return Crypto.hmacSha1(key, text);
+    }
+
+    return new byte[] {};
+  }
+
+  private static StringBuilder getNormalizedRequestString(final String nonce, final String method,
+      final String uri, final String host, final String port, final String bodyHash,
+      final String ext) {
+    final StringBuilder ret = new StringBuilder();
+    ret.append(nonce);
+    ret.append('\n');
+    ret.append(method);
+    ret.append('\n');
+    ret.append(uri);
+    ret.append('\n');
+    ret.append(host);
+    ret.append('\n');
+    ret.append(port);
+    ret.append('\n');
+    ret.append(bodyHash);
+    ret.append('\n');
+    ret.append(ext);
+    ret.append('\n');
+
+    return ret;
+  }
+
+  private static OAuth2HandlerError getError(final String contextMessage) {
+    return MacTokenHandler.getError(contextMessage, null);
+  }
+
+  private static OAuth2HandlerError getError(final String contextMessage, final Exception e) {
+    return new OAuth2HandlerError(MacTokenHandler.ERROR, contextMessage, e);
+  }
+}

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/OAuth2HandlerError.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/OAuth2HandlerError.java?rev=1182565&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/OAuth2HandlerError.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/OAuth2HandlerError.java Wed Oct 12 20:10:39 2011
@@ -0,0 +1,72 @@
+/*
+ * 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.handler;
+
+import java.io.Serializable;
+
+import org.apache.shindig.gadgets.oauth2.OAuth2Error;
+
+/**
+ * Stores an error in the handler layer.
+ * 
+ * 
+ */
+public class OAuth2HandlerError implements Serializable {
+  private static final long serialVersionUID = 6533884367169476207L;
+
+  private final OAuth2Error error;
+  private final Exception cause;
+  private final String contextMessage;
+
+  public OAuth2HandlerError(final OAuth2Error error, final String contextMessage,
+      final Exception cause) {
+    this.error = error;
+    this.contextMessage = contextMessage;
+    this.cause = cause;
+  }
+
+  /**
+   * 
+   * @return the {@link OAuth2Error} associated with this error
+   */
+  public OAuth2Error getError() {
+    return this.error;
+  }
+
+  /**
+   * 
+   * @return underlying exception that caused is error or <code>null</code>
+   */
+  public Exception getCause() {
+    return this.cause;
+  }
+
+  /**
+   * 
+   * @return non-translated message about the context of this error for
+   *         debugging purposes
+   */
+  public String getContextMessage() {
+    return this.contextMessage;
+  }
+
+  @Override
+  public String toString() {
+    return OAuth2HandlerError.class.getName() + " : " + this.error + " : "
+        + this.getContextMessage() + " : " + this.cause;
+  }
+}

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/OAuth2HandlerModule.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/OAuth2HandlerModule.java?rev=1182565&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/OAuth2HandlerModule.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/OAuth2HandlerModule.java Wed Oct 12 20:10:39 2011
@@ -0,0 +1,80 @@
+/*
+ * 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.handler;
+
+import java.util.List;
+
+import org.apache.shindig.gadgets.oauth2.logger.FilteredLogger;
+
+import com.google.common.collect.ImmutableList;
+import com.google.inject.AbstractModule;
+import com.google.inject.Provides;
+import com.google.inject.Singleton;
+
+/**
+ * Injects the default handlers.
+ * 
+ */
+public class OAuth2HandlerModule extends AbstractModule {
+  private static final FilteredLogger LOG = FilteredLogger
+      .getFilteredLogger(OAuth2HandlerModule.class.getName());
+
+  @Override
+  protected void configure() {
+    if (OAuth2HandlerModule.LOG.isLoggable()) {
+      OAuth2HandlerModule.LOG.entering(OAuth2HandlerModule.class.getName(), "configure");
+    }
+  }
+
+  @Provides
+  @Singleton
+  static List<AuthorizationEndpointResponseHandler> provideAuthorizationEndpointResponseHandlers(
+      final CodeAuthorizationResponseHandler codeAuthorizationResponseHandler) {
+    return ImmutableList
+        .of((AuthorizationEndpointResponseHandler) codeAuthorizationResponseHandler);
+  }
+
+  @Provides
+  @Singleton
+  static List<ClientAuthenticationHandler> provideClientAuthenticationHandlers(
+      final BasicAuthenticationHandler basicAuthenticationHandler,
+      final StandardAuthenticationHandler standardAuthenticationHandler) {
+    return ImmutableList.of(basicAuthenticationHandler, standardAuthenticationHandler);
+  }
+
+  @Provides
+  @Singleton
+  static List<GrantRequestHandler> provideGrantRequestHandlers(
+      final ClientCredentialsGrantTypeHandler clientCredentialsGrantTypeHandler,
+      final CodeGrantTypeHandler codeGrantTypeHandler) {
+    return ImmutableList.of(clientCredentialsGrantTypeHandler, codeGrantTypeHandler);
+  }
+
+  @Provides
+  @Singleton
+  static List<TokenEndpointResponseHandler> provideTokenEndpointResponseHandlers(
+      final TokenAuthorizationResponseHandler tokenAuthorizationResponseHandler) {
+    return ImmutableList.of((TokenEndpointResponseHandler) tokenAuthorizationResponseHandler);
+  }
+
+  @Provides
+  @Singleton
+  static List<ResourceRequestHandler> provideTokenHandlers(
+      final BearerTokenHandler bearerTokenHandler, final MacTokenHandler macTokenHandler) {
+    return ImmutableList.of(bearerTokenHandler, macTokenHandler);
+  }
+}
\ No newline at end of file

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/ResourceRequestHandler.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/ResourceRequestHandler.java?rev=1182565&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/ResourceRequestHandler.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/ResourceRequestHandler.java Wed Oct 12 20:10:39 2011
@@ -0,0 +1,50 @@
+/*
+ * 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.handler;
+
+import org.apache.shindig.gadgets.http.HttpRequest;
+import org.apache.shindig.gadgets.oauth2.OAuth2Accessor;
+import org.apache.shindig.gadgets.oauth2.OAuth2Token;
+
+/**
+ * 
+ * Enables inject of token type handlers to add OAuth2 auth data to resource
+ * requests.
+ * 
+ * By default shindig supports "Bearer" token types.
+ * 
+ * Matches on {@link OAuth2Token#getTokenType()}
+ * 
+ * All matching handlers are executed.
+ * 
+ */
+public interface ResourceRequestHandler {
+  /**
+   * Do the handler magic for the token type.
+   * 
+   * @param accessor
+   * @param request
+   * @return {@link OAuth2HandlerError} if one occurs
+   */
+  public OAuth2HandlerError addOAuth2Params(final OAuth2Accessor accessor, final HttpRequest request);
+
+  /**
+   * 
+   * @return the token type this handler handles
+   */
+  public String getTokenType();
+}

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/StandardAuthenticationHandler.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/StandardAuthenticationHandler.java?rev=1182565&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/StandardAuthenticationHandler.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/StandardAuthenticationHandler.java Wed Oct 12 20:10:39 2011
@@ -0,0 +1,88 @@
+/*
+ * 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.handler;
+
+import org.apache.shindig.gadgets.http.HttpRequest;
+import org.apache.shindig.gadgets.oauth2.OAuth2Accessor;
+import org.apache.shindig.gadgets.oauth2.OAuth2Error;
+import org.apache.shindig.gadgets.oauth2.OAuth2Message;
+
+/**
+ * 
+ * See {@link ClientAuthenticationHandler}
+ * 
+ * Handler for Basic Authentication
+ * 
+ */
+public class StandardAuthenticationHandler implements ClientAuthenticationHandler {
+  private static final OAuth2Error ERROR = OAuth2Error.AUTHENTICATION_PROBLEM;
+
+  public StandardAuthenticationHandler() {
+  }
+
+  public OAuth2HandlerError addOAuth2Authentication(final HttpRequest request,
+      final OAuth2Accessor accessor) {
+    try {
+      if (request == null) {
+        return StandardAuthenticationHandler.getError("request is null");
+      }
+
+      if (accessor == null) {
+        return StandardAuthenticationHandler.getError("accessor is null");
+      }
+
+      if (!accessor.isValid() || accessor.isErrorResponse()) {
+        return StandardAuthenticationHandler.getError("accessor is invalid");
+      }
+
+      final String clientId = accessor.getClientId();
+
+      if (clientId == null) {
+        return StandardAuthenticationHandler.getError("client_id is null");
+      }
+
+      final byte[] secretBytes = accessor.getClientSecret();
+
+      if (secretBytes == null) {
+        return StandardAuthenticationHandler.getError("client_secret is secret");
+      }
+
+      final String secret = new String(secretBytes, "UTF-8");
+
+      request.setHeader(OAuth2Message.CLIENT_ID, clientId);
+      request.setParam(OAuth2Message.CLIENT_ID, clientId);
+      request.setHeader(OAuth2Message.CLIENT_SECRET, secret);
+      request.setParam(OAuth2Message.CLIENT_SECRET, secret);
+
+      return null;
+    } catch (final Exception e) {
+      return StandardAuthenticationHandler.getError("Exception adding standard auth headers", e);
+    }
+  }
+
+  public String geClientAuthenticationType() {
+    return OAuth2Message.STANDARD_AUTH_TYPE;
+  }
+
+  private static OAuth2HandlerError getError(final String contextMessage) {
+    return StandardAuthenticationHandler.getError(contextMessage, null);
+  }
+
+  private static OAuth2HandlerError getError(final String contextMessage, final Exception e) {
+    return new OAuth2HandlerError(StandardAuthenticationHandler.ERROR, contextMessage, e);
+  }
+}
\ No newline at end of file

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/TokenAuthorizationResponseHandler.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/TokenAuthorizationResponseHandler.java?rev=1182565&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/TokenAuthorizationResponseHandler.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/TokenAuthorizationResponseHandler.java Wed Oct 12 20:10:39 2011
@@ -0,0 +1,211 @@
+/*
+ * 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.handler;
+
+import java.util.Map;
+
+import org.apache.shindig.gadgets.http.HttpResponse;
+import org.apache.shindig.gadgets.oauth2.OAuth2Accessor;
+import org.apache.shindig.gadgets.oauth2.OAuth2Error;
+import org.apache.shindig.gadgets.oauth2.OAuth2Message;
+import org.apache.shindig.gadgets.oauth2.OAuth2Store;
+import org.apache.shindig.gadgets.oauth2.OAuth2Token;
+import org.apache.shindig.gadgets.oauth2.logger.FilteredLogger;
+import org.json.JSONObject;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+/**
+ * 
+ * See {@link TokenEndpointResponseHandler}
+ * 
+ * Handles the "client_credentials" flow
+ */
+public class TokenAuthorizationResponseHandler implements TokenEndpointResponseHandler {
+  private final static String LOG_CLASS = CodeAuthorizationResponseHandler.class.getName();
+  private static final FilteredLogger LOG = FilteredLogger
+      .getFilteredLogger(TokenAuthorizationResponseHandler.LOG_CLASS);
+
+  private static final OAuth2Error ERROR = OAuth2Error.TOKEN_RESPONSE_PROBLEM;
+
+  private final Provider<OAuth2Message> oauth2MessageProvider;
+  private final OAuth2Store store;
+
+  @Inject
+  public TokenAuthorizationResponseHandler(final Provider<OAuth2Message> oauth2MessageProvider,
+      final OAuth2Store store) {
+    this.oauth2MessageProvider = oauth2MessageProvider;
+    this.store = store;
+
+    if (TokenAuthorizationResponseHandler.LOG.isLoggable()) {
+      TokenAuthorizationResponseHandler.LOG.log("this.oauth2MessageProvider = {0}",
+          this.oauth2MessageProvider);
+      TokenAuthorizationResponseHandler.LOG.log("this.store = {0}", this.store);
+    }
+  }
+
+  public OAuth2HandlerError handleResponse(final OAuth2Accessor accessor,
+      final HttpResponse response) {
+    final boolean isLogging = TokenAuthorizationResponseHandler.LOG.isLoggable();
+
+    if (isLogging) {
+      if (response != null) {
+        TokenAuthorizationResponseHandler.LOG.entering(TokenAuthorizationResponseHandler.LOG_CLASS,
+            "getAuthorizationBody", new Object[] { accessor, "non-null response" });
+      } else {
+        TokenAuthorizationResponseHandler.LOG.entering(TokenAuthorizationResponseHandler.LOG_CLASS,
+            "getAuthorizationBody", new Object[] { accessor, null });
+      }
+    }
+
+    OAuth2HandlerError ret = null;
+
+    try {
+      if (response == null) {
+        ret = TokenAuthorizationResponseHandler.getError("response is null");
+      }
+
+      if ((ret == null)
+          && ((accessor == null) || (!accessor.isValid()) || (accessor.isErrorResponse()))) {
+        ret = TokenAuthorizationResponseHandler.getError("accessor is invalid " + accessor);
+      }
+
+      if ((ret == null) && (response != null)) {
+        final int responseCode = response.getHttpStatusCode();
+        if (responseCode != HttpResponse.SC_OK) {
+          ret = TokenAuthorizationResponseHandler.getError("can't handle error response code "
+              + responseCode);
+        }
+
+        if (ret == null) {
+          final long issuedAt = System.currentTimeMillis() / 1000;
+
+          final String contentType = response.getHeader("Content-Type");
+          final String responseString = response.getResponseAsString();
+          final OAuth2Message msg = this.oauth2MessageProvider.get();
+
+          if (contentType.startsWith("text/plain")) {
+            // Facebook does this
+            msg.parseQuery("?" + responseString);
+          } else if (contentType.startsWith("application/json")) {
+            // Google does this
+            final JSONObject responseJson = new JSONObject(responseString);
+            msg.parseJSON(responseJson.toString());
+          } else {
+            if (isLogging) {
+              TokenAuthorizationResponseHandler.LOG.log("Unhandled Content-Type {0}", contentType);
+              TokenAuthorizationResponseHandler.LOG.exiting(
+                  TokenAuthorizationResponseHandler.LOG_CLASS, "handleResponse", null);
+            }
+            ret = TokenAuthorizationResponseHandler.getError("Unhandled Content-Type "
+                + contentType);
+          }
+
+          final OAuth2Error error = msg.getError();
+          if ((error == null) && (accessor != null)) {
+            final String accessToken = msg.getAccessToken();
+            final String refreshToken = msg.getRefreshToken();
+            final String expiresIn = msg.getExpiresIn();
+            final String tokenType = msg.getTokenType();
+            final String providerName = accessor.getServiceName();
+            final String gadgetUri = accessor.getGadgetUri();
+            final String scope = accessor.getScope();
+            final String user = accessor.getUser();
+            final String macAlgorithm = msg.getMacAlgorithm();
+            final String macSecret = msg.getMacSecret();
+            final Map<String, String> unparsedProperties = msg.getUnparsedProperties();
+
+            if (accessToken != null) {
+              final OAuth2Token storedAccessToken = this.store.createToken();
+              storedAccessToken.setIssuedAt(issuedAt);
+              if (expiresIn != null) {
+                storedAccessToken.setExpiresAt(issuedAt + Long.decode(expiresIn));
+              } else {
+                storedAccessToken.setExpiresAt(0);
+              }
+              storedAccessToken.setGadgetUri(gadgetUri);
+              storedAccessToken.setServiceName(providerName);
+              storedAccessToken.setScope(scope);
+              storedAccessToken.setSecret(accessToken.getBytes("UTF-8"));
+              storedAccessToken.setTokenType(tokenType);
+              storedAccessToken.setType(OAuth2Token.Type.ACCESS);
+              storedAccessToken.setUser(user);
+              if (macAlgorithm != null) {
+                storedAccessToken.setMacAlgorithm(macAlgorithm);
+              }
+              if (macSecret != null) {
+                storedAccessToken.setMacSecret(macSecret.getBytes("UTF-8"));
+              }
+              storedAccessToken.setProperties(unparsedProperties);
+              this.store.setToken(storedAccessToken);
+              accessor.setAccessToken(storedAccessToken);
+            }
+
+            if (refreshToken != null) {
+              final OAuth2Token storedRefreshToken = this.store.createToken();
+              storedRefreshToken.setExpiresAt(0);
+              storedRefreshToken.setGadgetUri(gadgetUri);
+              storedRefreshToken.setServiceName(providerName);
+              storedRefreshToken.setScope(scope);
+              storedRefreshToken.setSecret(refreshToken.getBytes("UTF-8"));
+              storedRefreshToken.setTokenType(tokenType);
+              storedRefreshToken.setType(OAuth2Token.Type.REFRESH);
+              storedRefreshToken.setUser(user);
+              this.store.setToken(storedRefreshToken);
+              accessor.setRefreshToken(storedRefreshToken);
+            }
+          }
+        }
+      }
+    } catch (final Exception e) {
+      if (isLogging) {
+        TokenAuthorizationResponseHandler.LOG.log(
+            "exception thrown handling authorization response", e);
+      }
+      return TokenAuthorizationResponseHandler.getError(
+          "exception thrown handling authorization response", e);
+    }
+
+    if (isLogging) {
+      TokenAuthorizationResponseHandler.LOG.exiting(TokenAuthorizationResponseHandler.LOG_CLASS,
+          "handleResponse", ret);
+    }
+
+    return ret;
+  }
+
+  public boolean handlesResponse(final OAuth2Accessor accessor, final HttpResponse response) {
+    if ((accessor == null) || (!accessor.isValid()) || (accessor.isErrorResponse())) {
+      return false;
+    }
+
+    if (response == null) {
+      return false;
+    }
+
+    return true;
+  }
+
+  private static OAuth2HandlerError getError(final String contextMessage) {
+    return TokenAuthorizationResponseHandler.getError(contextMessage, null);
+  }
+
+  private static OAuth2HandlerError getError(final String contextMessage, final Exception e) {
+    return new OAuth2HandlerError(TokenAuthorizationResponseHandler.ERROR, contextMessage, e);
+  }
+}

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/TokenEndpointResponseHandler.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/TokenEndpointResponseHandler.java?rev=1182565&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/TokenEndpointResponseHandler.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/handler/TokenEndpointResponseHandler.java Wed Oct 12 20:10:39 2011
@@ -0,0 +1,60 @@
+/*
+ * 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.handler;
+
+import org.apache.shindig.gadgets.http.HttpResponse;
+import org.apache.shindig.gadgets.oauth2.OAuth2Accessor;
+
+/**
+ * When an TokenEndpointResponseHandler is injected into the system it will be
+ * called on every response from the token server that it claims to handle.
+ * 
+ * See {@link http://tools.ietf.org/html/draft-ietf-oauth-v2-21#section-4}
+ * 
+ * By default shindig has handlers for the Authorization Code and Client
+ * Credential flows.
+ * 
+ */
+public interface TokenEndpointResponseHandler {
+  /**
+   * Let the handler do it's magic including any accessor/store updates.
+   * 
+   * If the handler is executed and encountered an error that should stop the
+   * authorization process it should return the appropriate
+   * {@link OAuth2HandlerError}.
+   * 
+   * 
+   * Applies in particular to the client_credentials flow.
+   * 
+   * See {@link http://tools.ietf.org/html/draft-ietf-oauth-v2-21#section-4.4.1}
+   * 
+   * @param accessor
+   * @param response
+   * @return see above
+   */
+  public OAuth2HandlerError handleResponse(OAuth2Accessor accessor, HttpResponse response);
+
+  /**
+   * Does the handler support this {@link OAuth2Accessor} / {@link HttpResponse}
+   * response?
+   * 
+   * @param accessor
+   * @param request
+   * @return <code>true</code> if handleRequest() should be invoked
+   */
+  public boolean handlesResponse(OAuth2Accessor accessor, HttpResponse response);
+}

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/logger/FilteredLogger.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/logger/FilteredLogger.java?rev=1182565&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/logger/FilteredLogger.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/logger/FilteredLogger.java Wed Oct 12 20:10:39 2011
@@ -0,0 +1,150 @@
+/*
+ * 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.logger;
+
+import java.util.ResourceBundle;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.shindig.gadgets.oauth2.OAuth2Error;
+
+/**
+ * Wraps a {@link Logger} with functions to remove OAuth2 secrets so they don't
+ * show up in trace logs.
+ * 
+ */
+public class FilteredLogger {
+  private static final Level DEFAULT_LOG_LEVEL = Level.FINEST;
+
+  private static final Pattern REMOVE_SECRETS1 = Pattern.compile("(?<=access_token=)[^=& \t\r\n]*");
+  private static final Pattern REMOVE_SECRETS2 = Pattern.compile("(Authorization:)[^\t\r\n]*");
+
+  private static String filteredMsg(final String msg) {
+    return FilteredLogger.filterSecrets(msg);
+  }
+
+  private static String filteredParam(final Object param) {
+    final String _param;
+    if (param != null) {
+      _param = FilteredLogger.filterSecrets(param.toString());
+    } else {
+      _param = "";
+    }
+
+    return _param;
+  }
+
+  private static String[] filteredParams(final Object[] params) {
+    final String[] _params;
+    if (params != null) {
+      _params = new String[params.length];
+      int i = 0;
+      for (final Object param : params) {
+        if (param != null) {
+          _params[i] = FilteredLogger.filteredMsg(param.toString());
+        } else {
+          _params[i] = "";
+        }
+        i++;
+      }
+    } else {
+      _params = new String[] {};
+    }
+
+    return _params;
+  }
+
+  public static String filterSecrets(String in) {
+    if ((in != null) && (in.length() > 0)) {
+      Matcher m = FilteredLogger.REMOVE_SECRETS1.matcher(in);
+      final String ret = m.replaceAll("REMOVED");
+      m = FilteredLogger.REMOVE_SECRETS2.matcher(ret);
+      return m.replaceAll("REMOVED");
+    }
+
+    return "";
+  }
+
+  public static FilteredLogger getFilteredLogger(final String className) {
+    return new FilteredLogger(className);
+  }
+
+  private final Logger logger;
+
+  protected FilteredLogger(final String className) {
+    this.logger = java.util.logging.Logger.getLogger(className, OAuth2Error.MESSAGES);
+  }
+
+  public void entering(String sourceClass, String sourceMethod) {
+    this.logger.entering(sourceClass, sourceMethod);
+  }
+
+  public void entering(String sourceClass, String sourceMethod, Object param) {
+    this.logger.entering(sourceClass, sourceMethod, FilteredLogger.filteredParam(param));
+  }
+
+  public void entering(String sourceClass, String sourceMethod, Object[] params) {
+    this.logger.entering(sourceClass, sourceMethod, FilteredLogger.filteredParams(params));
+  }
+
+  public ResourceBundle getResourceBundle() {
+    return this.logger.getResourceBundle();
+  }
+
+  public boolean isLoggable() {
+    return this.isLoggable(FilteredLogger.DEFAULT_LOG_LEVEL);
+  }
+
+  public boolean isLoggable(final Level logLevel) {
+    return this.logger.isLoggable(logLevel);
+  }
+
+  public void log(Level logLevel, String msg, Object param) {
+    this.logger.log(logLevel, FilteredLogger.filteredMsg(msg), FilteredLogger.filteredParam(param));
+  }
+
+  public void log(Level logLevel, String msg, Object[] params) {
+    this.logger.log(logLevel, FilteredLogger.filteredMsg(msg),
+        FilteredLogger.filteredParams(params));
+  }
+
+  public void log(Level logLevel, String msg, Throwable thrown) {
+    this.logger.log(logLevel, FilteredLogger.filterSecrets(msg), thrown);
+  }
+
+  public void log(String msg, Object param) {
+    this.log(FilteredLogger.DEFAULT_LOG_LEVEL, msg, param);
+  }
+
+  public void log(String msg, Object[] params) {
+    this.log(FilteredLogger.DEFAULT_LOG_LEVEL, msg, params);
+  }
+
+  public void log(String msg, Throwable thrown) {
+    this.logger.log(FilteredLogger.DEFAULT_LOG_LEVEL, msg, thrown);
+  }
+
+  public void exiting(String sourceClass, String sourceMethod) {
+    this.logger.exiting(sourceClass, sourceMethod);
+  }
+
+  public void exiting(String sourceClass, String sourceMethod, Object result) {
+    this.logger.exiting(sourceClass, sourceMethod, FilteredLogger.filteredParam(result));
+  }
+}
\ No newline at end of file

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2Cache.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2Cache.java?rev=1182565&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2Cache.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2Cache.java Wed Oct 12 20:10:39 2011
@@ -0,0 +1,175 @@
+/*
+ * 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.persistence;
+
+import java.util.Collection;
+
+import org.apache.shindig.gadgets.oauth2.OAuth2Accessor;
+import org.apache.shindig.gadgets.oauth2.OAuth2Store;
+import org.apache.shindig.gadgets.oauth2.OAuth2Token;
+
+/**
+ * Used by {@link OAuth2Store} to cache OAuth2 data.
+ * 
+ * Default implementation is in-memory HashMaps for shindig.
+ * 
+ */
+public interface OAuth2Cache {
+  /**
+   * Clears all cached {@link OAuth2Client}s.
+   * 
+   * @throws OAuth2CacheException
+   */
+  void clearClients() throws OAuth2CacheException;
+
+  /**
+   * Clears all cached {@link OAuth2Token}s.
+   * 
+   * @throws OAuth2CacheException
+   */
+  void clearTokens() throws OAuth2CacheException;
+
+  /**
+   * Find an {@link OAuth2Client} by {@link Integer} index.
+   * 
+   * @param index
+   * @return OAuth2Client
+   */
+  OAuth2Client getClient(Integer index);
+
+  /**
+   * Generate an {@link OAuth2Client} index for the given mapping.
+   * 
+   * @param gadgetUri
+   * @param serviceName
+   * @return client index
+   */
+  Integer getClientIndex(String gadgetUri, String serviceName);
+
+  /**
+   * Find an {@link OAuth2Accessor} by index.
+   * 
+   * @param index
+   * @return OAuth2Accessor
+   */
+  OAuth2Accessor getOAuth2Accessor(Integer index);
+
+  /**
+   * Generate in index for an {@link OAuth2Accessor} by the given parameters.
+   * 
+   * @param gadgetUri
+   * @param serviceName
+   * @param user
+   * @param scope
+   * @return index for the OAuth2Accessor
+   */
+  Integer getOAuth2AccessorIndex(String gadgetUri, String serviceName, String user, String scope);
+
+  /**
+   * Find an {@link OAuth2Token} based on index
+   * 
+   * @param index
+   * @return an OAuth2Token
+   */
+  OAuth2Token getToken(Integer index);
+
+  /**
+   * Returns the {@link Integer} index for the given {@link OAuth2Token}.
+   * 
+   * @param token
+   * @return index of the OAuth2Token
+   */
+  Integer getTokenIndex(OAuth2Token token);
+
+  /**
+   * Generate index for {@link OAuth2Token} based on parameters
+   * 
+   * @param gadgetUri
+   * @param serviceName
+   * @param user
+   * @param scope
+   * @param type
+   * @return index of OAuth2Token
+   */
+  Integer getTokenIndex(String gadgetUri, String serviceName, String user, String scope,
+      OAuth2Token.Type type);
+
+  /**
+   * Removes the {@link OAuth2Client} from the cache.
+   * 
+   * @param index
+   * @return the removed client, or <code>null</code> if none was found
+   * @throws OAuth2CacheException
+   */
+  OAuth2Client removeClient(Integer index) throws OAuth2CacheException;
+
+  /**
+   * Removes the given {@link OAuth2Accessor} from the cache.
+   * 
+   * @param index
+   * @return the removed {@link OAuth2Accessor} or <code>null</code> if none was
+   *         found
+   */
+  OAuth2Accessor removeOAuth2Accessor(Integer index);
+
+  /**
+   * Removes the given {@link OAuth2Token} from the cache.
+   * 
+   * @param index
+   * @return the removed {@link OAuth2Token} or <code>null</code> if none was
+   *         found
+   * @throws OAuth2CacheException
+   */
+  OAuth2Token removeToken(Integer index) throws OAuth2CacheException;
+
+  /**
+   * Stores the given client.
+   * 
+   * @param index
+   * @param client
+   * @throws OAuth2CacheException
+   */
+  Integer storeClient(OAuth2Client client) throws OAuth2CacheException;
+
+  /**
+   * Store all clients in the collection.
+   * 
+   * @param clients
+   * @throws OAuth2CacheException
+   */
+  void storeClients(Collection<OAuth2Client> clients) throws OAuth2CacheException;
+
+  /**
+   * Stores the given accessor.
+   * 
+   * @param accessor
+   */
+  Integer storeOAuth2Accessor(OAuth2Accessor accessor);
+
+  /**
+   * Stores the given token and returns it's index.
+   */
+  Integer storeToken(OAuth2Token token) throws OAuth2CacheException;
+
+  /**
+   * Stores all tokens in the collection.
+   * 
+   * @param tokens
+   * @throws OAuth2CacheException
+   */
+  void storeTokens(Collection<OAuth2Token> tokens) throws OAuth2CacheException;
+}

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2CacheException.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2CacheException.java?rev=1182565&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2CacheException.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2CacheException.java Wed Oct 12 20:10:39 2011
@@ -0,0 +1,29 @@
+/*
+ * 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.persistence;
+
+/**
+ * Subclass of {@link OAuth2PersistenceException} for caching issues.
+ * 
+ */
+public class OAuth2CacheException extends OAuth2PersistenceException {
+  private static final long serialVersionUID = -7722454386821962603L;
+
+  public OAuth2CacheException(final Exception cause) {
+    super(cause);
+  }
+}

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2Client.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2Client.java?rev=1182565&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2Client.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2Client.java Wed Oct 12 20:10:39 2011
@@ -0,0 +1,244 @@
+/*
+ * 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.persistence;
+
+import java.io.Serializable;
+
+import org.apache.shindig.gadgets.oauth2.OAuth2Accessor;
+import org.apache.shindig.gadgets.oauth2.OAuth2Message;
+
+import com.google.inject.Inject;
+
+/**
+ * Data class for client data stored in persistence.
+ * 
+ * Uses the injected {@link OAuth2Encrypter} protect the client_secret in the
+ * persistence store.
+ * 
+ */
+public class OAuth2Client implements Serializable {
+  private static final long serialVersionUID = -6090033505867216220L;
+
+  private boolean allowModuleOverride;
+  private boolean authorizationHeader;
+  private String authorizationUrl;
+  private String clientAuthenticationType;
+  private String clientId;
+  private byte[] clientSecret;
+  private byte[] encryptedSecret;
+  private transient final OAuth2Encrypter encrypter;
+  private String gadgetUri;
+  private String grantType = OAuth2Message.NO_GRANT_TYPE;
+  private String redirectUri;
+  private String serviceName;
+  private String tokenUrl;
+  private OAuth2Accessor.Type type = OAuth2Accessor.Type.UNKNOWN;
+  private boolean urlParameter;
+
+  @Inject
+  public OAuth2Client(final OAuth2Encrypter encrypter) {
+    this.encrypter = encrypter;
+  }
+
+  @Override
+  public boolean equals(final Object obj) {
+    if (obj == this) {
+      return true;
+    }
+    if (!(obj instanceof OAuth2Client)) {
+      return false;
+    }
+    final OAuth2Client other = (OAuth2Client) obj;
+    if (this.gadgetUri == null) {
+      if (other.gadgetUri != null) {
+        return false;
+      }
+    } else if (!this.gadgetUri.equals(other.gadgetUri)) {
+      return false;
+    }
+    if (this.serviceName == null) {
+      if (other.serviceName != null) {
+        return false;
+      }
+    } else if (!this.serviceName.equals(other.serviceName)) {
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * Returns authorization endpoint
+   * 
+   * @return authorization endpoint
+   */
+  public String getAuthorizationUrl() {
+    return this.authorizationUrl;
+  }
+
+  /**
+   * Returns client authentication type
+   * 
+   * @return client authentication type
+   */
+  public String getClientAuthenticationType() {
+    return this.clientAuthenticationType;
+  }
+
+  /**
+   * Returns client id.
+   * 
+   * @return client id
+   */
+  public String getClientId() {
+    return this.clientId;
+  }
+
+  /**
+   * Returns client secret
+   * 
+   * @return client secret
+   */
+  public byte[] getClientSecret() {
+    return this.clientSecret;
+  }
+
+  /**
+   * Returns encrypted secret
+   * 
+   * @return encrypted secret
+   */
+  public byte[] getEncryptedSecret() {
+    return this.encryptedSecret;
+  }
+
+  public OAuth2Encrypter getEncrypter() {
+    return this.encrypter;
+  }
+
+  public String getGadgetUri() {
+    return this.gadgetUri;
+  }
+
+  public String getGrantType() {
+    return this.grantType;
+  }
+
+  public String getRedirectUri() {
+    return this.redirectUri;
+  }
+
+  public String getServiceName() {
+    return this.serviceName;
+  }
+
+  public String getTokenUrl() {
+    return this.tokenUrl;
+  }
+
+  public OAuth2Accessor.Type getType() {
+    return this.type;
+  }
+
+  @Override
+  public int hashCode() {
+    if ((this.serviceName != null) && (this.gadgetUri != null)) {
+      return (this.serviceName + ":" + this.gadgetUri).hashCode();
+    }
+
+    return 0;
+  }
+
+  public boolean isAllowModuleOverride() {
+    return this.allowModuleOverride;
+  }
+
+  public boolean isAuthorizationHeader() {
+    return this.authorizationHeader;
+  }
+
+  public boolean isUrlParameter() {
+    return this.urlParameter;
+  }
+
+  public void setAllowModuleOverride(final boolean alllowModuleOverride) {
+    this.allowModuleOverride = alllowModuleOverride;
+  }
+
+  public void setAuthorizationHeader(boolean authorizationHeader) {
+    this.authorizationHeader = authorizationHeader;
+  }
+
+  public void setAuthorizationUrl(final String authorizationUrl) {
+    this.authorizationUrl = authorizationUrl;
+  }
+
+  public void setClientAuthenticationType(final String clientAuthenticationType) {
+    this.clientAuthenticationType = clientAuthenticationType;
+  }
+
+  public void setClientId(final String clientId) {
+    this.clientId = clientId;
+  }
+
+  public void setClientSecret(final byte[] secret) throws OAuth2EncryptionException {
+    this.clientSecret = secret;
+    this.encryptedSecret = this.encrypter.encrypt(secret);
+  }
+
+  public void setEncryptedSecret(final byte[] encryptedSecret) throws OAuth2EncryptionException {
+    this.encryptedSecret = encryptedSecret;
+    this.clientSecret = this.encrypter.decrypt(encryptedSecret);
+  }
+
+  public void setGadgetUri(final String gadgetUri) {
+    this.gadgetUri = gadgetUri;
+  }
+
+  public void setGrantType(final String grantType) {
+    this.grantType = grantType;
+  }
+
+  public void setRedirectUri(final String redirectUri) {
+    this.redirectUri = redirectUri;
+  }
+
+  public void setServiceName(final String serviceName) {
+    this.serviceName = serviceName;
+  }
+
+  public void setTokenUrl(final String tokenUrl) {
+    this.tokenUrl = tokenUrl;
+  }
+
+  public void setType(final OAuth2Accessor.Type type) {
+    this.type = type;
+  }
+
+  public void setUrlParameter(boolean urlParameter) {
+    this.urlParameter = urlParameter;
+  }
+
+  @Override
+  public String toString() {
+    return "org.apache.shindig.gadgets.oauth2.persistence.sample.OAuth2ClientImpl: serviceName = "
+        + this.serviceName + " , redirectUri = " + this.redirectUri + " , gadgetUri = "
+        + this.gadgetUri + " , clientId = " + this.clientId + " , grantType = " + this.grantType
+        + " , type = " + this.type.name() + " , grantType = " + this.grantType + " , tokenUrl = "
+        + this.tokenUrl + " , authorizationUrl = " + this.authorizationUrl
+        + " , this.clientAuthenticationType = " + this.clientAuthenticationType;
+  }
+}

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2Encrypter.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2Encrypter.java?rev=1182565&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2Encrypter.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2Encrypter.java Wed Oct 12 20:10:39 2011
@@ -0,0 +1,44 @@
+/*
+ * 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.persistence;
+
+
+/**
+ * Injected into the system to encrypt/decrypt client and token secrets in the
+ * persistence layer.
+ * 
+ * This does not apply to any broader concept of token signing or other signing
+ * from the OAuth 1.0 implementation.
+ * 
+ */
+public interface OAuth2Encrypter {
+  /**
+   * Decrypts client and token secret
+   * 
+   * @param encryptedSecret
+   * @return decryptedSecret
+   */
+  public byte[] decrypt(byte[] encryptedSecret) throws OAuth2EncryptionException;
+
+  /**
+   * Encrypts client and token secret
+   * 
+   * @param plainSecret
+   * @return encryptedSecret
+   */
+  public byte[] encrypt(byte[] plainSecret) throws OAuth2EncryptionException;
+}

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2EncryptionException.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2EncryptionException.java?rev=1182565&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2EncryptionException.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2EncryptionException.java Wed Oct 12 20:10:39 2011
@@ -0,0 +1,32 @@
+/*
+ * 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.persistence;
+
+import org.apache.shindig.gadgets.GadgetException;
+
+/**
+ * Subclass of {@link OAuth2PersistenceException} for secret
+ * encryption/decryption issues.
+ * 
+ */
+public class OAuth2EncryptionException extends GadgetException {
+  private static final long serialVersionUID = -3884237661767049433L;
+
+  public OAuth2EncryptionException(final Exception cause) {
+    super(Code.OAUTH_STORAGE_ERROR, cause);
+  }
+}

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2PersistenceException.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2PersistenceException.java?rev=1182565&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2PersistenceException.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2PersistenceException.java Wed Oct 12 20:10:39 2011
@@ -0,0 +1,28 @@
+/*
+ * 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.persistence;
+
+/**
+ * Exception class for errors that occur in the persistence layer.
+ */
+public class OAuth2PersistenceException extends Exception {
+  private static final long serialVersionUID = -8550943441259921635L;
+
+  public OAuth2PersistenceException(final Exception cause) {
+    super(cause);
+  }
+}

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2Persister.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2Persister.java?rev=1182565&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2Persister.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2Persister.java Wed Oct 12 20:10:39 2011
@@ -0,0 +1,119 @@
+/*
+ * 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.persistence;
+
+import java.util.Set;
+
+import org.apache.shindig.gadgets.oauth2.BasicOAuth2Store;
+import org.apache.shindig.gadgets.oauth2.OAuth2Accessor;
+import org.apache.shindig.gadgets.oauth2.OAuth2Store;
+import org.apache.shindig.gadgets.oauth2.OAuth2Token;
+import org.apache.shindig.gadgets.oauth2.persistence.sample.JSONOAuth2Persister;
+
+/**
+ * Interface, used primarily by {@link OAuth2Store}, to manage
+ * {@link OAuth2Accessor} and {@link OAuth2Token} storage.
+ * 
+ * An {@link OAuth2Accessor} has the same basic information as the
+ * {@link OAuth2Client}, merged with gadget spec and request prefs.
+ * 
+ * {@link OAuth2Accessor} is short lived, for the life of one request.
+ * 
+ * {@link OAuth2Clients} is intended to be persisted and cached.
+ * 
+ * The default persister for shindig is {@link JSONOAuth2Persister}
+ * 
+ */
+public interface OAuth2Persister {
+  /**
+   * 
+   * @return a new {@link OAuth2Token} suitable for initialization and storage.
+   */
+  OAuth2Token createToken();
+
+  /**
+   * 
+   * @param gadgetUri
+   * @param serviceName
+   * @return the client in the given mapping
+   * @throws OAuth2PersistenceException
+   */
+  OAuth2Client findClient(String gadgetUri, String serviceName) throws OAuth2PersistenceException;
+
+  /**
+   * 
+   * @param gadgetUri
+   * @param serviceName
+   * @param user
+   * @param scope
+   * @param type
+   * @return the token in the given mapping
+   * @throws OAuth2PersistenceException
+   */
+  OAuth2Token findToken(String gadgetUri, String serviceName, String user, String scope,
+      OAuth2Token.Type type) throws OAuth2PersistenceException;
+
+  /**
+   * Inserts a new {@link OAuth2Token} into the persistence layer.
+   * 
+   * @param token
+   * @throws OAuth2PersistenceException
+   */
+  void insertToken(OAuth2Token token) throws OAuth2PersistenceException;
+
+  /**
+   * Load all the clients from the persistence layer. The
+   * {@link BasicOAuth2Store#init()} method will call this to prepopulate the
+   * cache.
+   * 
+   * @return
+   * @throws OAuth2PersistenceException
+   */
+  Set<OAuth2Client> loadClients() throws OAuth2PersistenceException;
+
+  /**
+   * Load all the tokens from the persistence layer. The
+   * {@link BasicOAuth2Store#init()} method will call this to prepopulate the
+   * cache.
+   * 
+   * @return
+   * @throws OAuth2PersistenceException
+   */
+  Set<OAuth2Token> loadTokens() throws OAuth2PersistenceException;
+
+  /**
+   * Removes a token from the persistence layer.
+   * 
+   * @param gadgetUri
+   * @param serviceName
+   * @param user
+   * @param scope
+   * @param type
+   * @return
+   * @throws OAuth2PersistenceException
+   */
+  boolean removeToken(String gadgetUri, String serviceName, String user, String scope,
+      OAuth2Token.Type type) throws OAuth2PersistenceException;
+
+  /**
+   * Updates an existing {@link OAuth2Token} in the persistence layer.
+   * 
+   * @param token
+   * @throws OAuth2PersistenceException
+   */
+  void updateToken(OAuth2Token token) throws OAuth2PersistenceException;
+}

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2TokenPersistence.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2TokenPersistence.java?rev=1182565&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2TokenPersistence.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/OAuth2TokenPersistence.java Wed Oct 12 20:10:39 2011
@@ -0,0 +1,265 @@
+/*
+ * 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.persistence;
+
+import java.util.Map;
+
+import org.apache.shindig.gadgets.oauth2.OAuth2Error;
+import org.apache.shindig.gadgets.oauth2.OAuth2Message;
+import org.apache.shindig.gadgets.oauth2.OAuth2RequestException;
+import org.apache.shindig.gadgets.oauth2.OAuth2Token;
+
+import com.google.common.collect.Maps;
+import com.google.inject.Inject;
+
+/**
+ * see {@link OAuth2Token}
+ * 
+ */
+public class OAuth2TokenPersistence implements OAuth2Token {
+  private static final long serialVersionUID = 6853969404389015886L;
+
+  private byte[] encryptedMacSecret;
+  private byte[] encryptedSecret;
+  private transient final OAuth2Encrypter encrypter;
+  private long expiresAt;
+  private String gadgetUri;
+  private long issuedAt;
+  private String macAlgorithm;
+  private String macExt;
+  private byte[] macSecret;
+  private final Map<String, String> properties;
+  private String scope;
+  private byte[] secret;
+  private String serviceName;
+  private String tokenType;
+  private Type type;
+  private String user;
+
+  @Inject
+  public OAuth2TokenPersistence(final OAuth2Encrypter encrypter) {
+    this.encrypter = encrypter;
+    this.properties = Maps.newHashMap();
+  }
+
+  @Override
+  public boolean equals(final Object obj) {
+    if (obj == this) {
+      return true;
+    }
+    if (!(obj instanceof OAuth2Token)) {
+      return false;
+    }
+    final OAuth2Token other = (OAuth2Token) obj;
+    if (this.gadgetUri == null) {
+      if (other.getGadgetUri() != null) {
+        return false;
+      }
+    } else if (!this.gadgetUri.equals(other.getGadgetUri())) {
+      return false;
+    }
+    if (this.serviceName == null) {
+      if (other.getServiceName() != null) {
+        return false;
+      }
+    } else if (!this.serviceName.equals(other.getServiceName())) {
+      return false;
+    }
+
+    if (this.user == null) {
+      if (other.getUser() != null) {
+        return false;
+      }
+    } else if (!this.user.equals(other.getUser())) {
+      return false;
+    }
+    if (this.scope == null) {
+      if (other.getScope() != null) {
+        return false;
+      }
+    } else if (!this.scope.equals(other.getScope())) {
+      return false;
+    }
+    if (this.type == null) {
+      if (other.getType() != null) {
+        return false;
+      }
+    } else if (!this.type.equals(other.getType())) {
+      return false;
+    }
+
+    return true;
+  }
+
+  public byte[] getEncryptedMacSecret() {
+    return this.encryptedMacSecret;
+  }
+
+  public byte[] getEncryptedSecret() {
+    return this.encryptedSecret;
+  }
+
+  public long getExpiresAt() {
+    return this.expiresAt;
+  }
+
+  public String getGadgetUri() {
+    return this.gadgetUri;
+  }
+
+  public long getIssuedAt() {
+    return this.issuedAt;
+  }
+
+  public String getMacAlgorithm() {
+    return this.macAlgorithm;
+  }
+
+  public String getMacExt() {
+    return this.macExt;
+  }
+
+  public byte[] getMacSecret() {
+    return this.macSecret;
+  }
+
+  public Map<String, String> getProperties() {
+    return this.properties;
+  }
+
+  public String getScope() {
+    return this.scope;
+  }
+
+  public byte[] getSecret() {
+    return this.secret;
+  }
+
+  public String getServiceName() {
+    return this.serviceName;
+  }
+
+  public String getTokenType() {
+    if ((this.tokenType == null) || (this.tokenType.length() == 0)) {
+      this.tokenType = OAuth2Message.BEARER_TOKEN_TYPE;
+    }
+    return this.tokenType;
+  }
+
+  public Type getType() {
+    return this.type;
+  }
+
+  public String getUser() {
+    return this.user;
+  }
+
+  @Override
+  public int hashCode() {
+    if ((this.serviceName != null) && (this.gadgetUri != null)) {
+      return (this.serviceName + ":" + this.gadgetUri + ":" + this.user + ":" + this.scope + ":" + this.type)
+          .hashCode();
+    }
+
+    return 0;
+  }
+
+  public void setEncryptedMacSecret(final byte[] encryptedSecret) throws OAuth2EncryptionException {
+    this.encryptedMacSecret = encryptedSecret;
+    this.macSecret = this.encrypter.decrypt(encryptedSecret);
+  }
+
+  public void setEncryptedSecret(final byte[] encryptedSecret) throws OAuth2EncryptionException {
+    this.encryptedSecret = encryptedSecret;
+    this.secret = this.encrypter.decrypt(encryptedSecret);
+  }
+
+  public void setExpiresAt(long expiresAt) {
+    this.expiresAt = expiresAt;
+  }
+
+  public void setGadgetUri(final String gadgetUri) {
+    this.gadgetUri = gadgetUri;
+  }
+
+  public void setIssuedAt(long issuedAt) {
+    this.issuedAt = issuedAt;
+  }
+
+  public void setMacAlgorithm(String algorithm) {
+    this.macAlgorithm = algorithm;
+  }
+
+  public void setMacExt(String macExt) {
+    this.macExt = macExt;
+  }
+
+  public void setMacSecret(byte[] secret) throws OAuth2RequestException {
+    this.macSecret = secret;
+    try {
+      this.encryptedMacSecret = this.encrypter.encrypt(secret);
+    } catch (final OAuth2EncryptionException e) {
+      throw new OAuth2RequestException(OAuth2Error.SECRET_ENCRYPTION_PROBLEM,
+          "OAuth2TokenPersistence could not encrypt the mac secret", e);
+    }
+  }
+
+  public void setProperties(final Map<String, String> properties) {
+    this.properties.clear();
+    if (properties != null) {
+      this.properties.putAll(properties);
+    }
+  }
+
+  public void setScope(final String scope) {
+    this.scope = scope;
+  }
+
+  public void setSecret(final byte[] secret) throws OAuth2RequestException {
+    this.secret = secret;
+    try {
+      this.encryptedSecret = this.encrypter.encrypt(secret);
+    } catch (final OAuth2EncryptionException e) {
+      throw new OAuth2RequestException(OAuth2Error.SECRET_ENCRYPTION_PROBLEM,
+          "OAuth2TokenPersistence could not encrypt the token secret", e);
+    }
+  }
+
+  public void setServiceName(final String serviceName) {
+    this.serviceName = serviceName;
+  }
+
+  public void setTokenType(final String tokenType) {
+    this.tokenType = tokenType;
+  }
+
+  public void setType(final Type type) {
+    this.type = type;
+  }
+
+  public void setUser(final String user) {
+    this.user = user;
+  }
+
+  @Override
+  public String toString() {
+    return "org.apache.shindig.gadgets.oauth2.persistence.sample.OAuth2TokenImpl: serviceName = "
+        + this.serviceName + " , user = " + this.user + " , gadgetUri = " + this.gadgetUri
+        + " , scope = " + this.scope + " , tokenType = " + this.getTokenType() + " , issuedAt = "
+        + this.issuedAt + " , expiresAt = " + this.expiresAt + " , type = " + this.type;
+  }
+}

Added: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/sample/InMemoryCache.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/sample/InMemoryCache.java?rev=1182565&view=auto
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/sample/InMemoryCache.java (added)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth2/persistence/sample/InMemoryCache.java Wed Oct 12 20:10:39 2011
@@ -0,0 +1,166 @@
+/*
+ * 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.persistence.sample;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.shindig.gadgets.oauth2.OAuth2Accessor;
+import org.apache.shindig.gadgets.oauth2.OAuth2Token;
+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 com.google.common.collect.Maps;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+/**
+ * 
+ * {@link OAuth2Cache} implementation using in-memory {@link HashMap}s.
+ * 
+ */
+@Singleton
+public class InMemoryCache implements OAuth2Cache {
+  private final static String OAUTH2_CLIENT_PREFIX = InMemoryCache.OAUTH2_PREFIX + "CLIENT_";
+
+  private final static String OAUTH2_PREFIX = "OAUTH2_";
+  private final static String OAUTH2_TOKEN_PREFIX = InMemoryCache.OAUTH2_PREFIX + "TOKEN_";
+
+  private final Map<Integer, OAuth2Accessor> accessors;
+  private final Map<Integer, OAuth2Client> clients;
+  private final Map<Integer, OAuth2Token> tokens;
+
+  @Inject
+  public InMemoryCache() {
+    this.tokens = Maps.newHashMap();
+    this.clients = Maps.newHashMap();
+    this.accessors = Maps.newHashMap();
+  }
+
+  public void clearClients() throws OAuth2CacheException {
+    this.clients.clear();
+  }
+
+  public void clearTokens() throws OAuth2CacheException {
+    this.tokens.clear();
+  }
+
+  public OAuth2Client getClient(final Integer index) {
+    final OAuth2Client ret = this.clients.get(index);
+    return ret;
+  }
+
+  public Integer getClientIndex(final String gadgetUri, final String serviceName) {
+    return Integer
+        .valueOf((InMemoryCache.OAUTH2_CLIENT_PREFIX + ":" + gadgetUri + ":" + serviceName)
+            .hashCode());
+  }
+
+  public OAuth2Accessor getOAuth2Accessor(final Integer index) {
+    OAuth2Accessor ret = null;
+    if (index != null) {
+      ret = this.accessors.get(index);
+    }
+
+    return ret;
+  }
+
+  public Integer getOAuth2AccessorIndex(final String gadgetUri, final String serviceName,
+      final String user, final String scope) {
+    return Integer.valueOf((gadgetUri + ":" + serviceName + ":" + ":" + user + ":" + scope)
+        .hashCode());
+  }
+
+  public OAuth2Token getToken(final Integer index) {
+    return this.tokens.get(index);
+  }
+
+  public Integer getTokenIndex(final OAuth2Token token) {
+    if (token != null) {
+      return this.getTokenIndex(token.getGadgetUri(), token.getServiceName(), token.getUser(),
+          token.getScope(), token.getType());
+    }
+
+    return null;
+  }
+
+  public Integer getTokenIndex(final String gadgetUri, final String serviceName, final String user,
+      final String scope, final OAuth2Token.Type type) {
+
+    return Integer.valueOf((InMemoryCache.OAUTH2_TOKEN_PREFIX + ":" + gadgetUri + ":" + serviceName
+        + ":" + user + ":" + scope + ":" + type.name()).hashCode());
+  }
+
+  public OAuth2Client removeClient(final Integer index) throws OAuth2CacheException {
+    return this.clients.remove(index);
+  }
+
+  public OAuth2Accessor removeOAuth2Accessor(final Integer index) {
+    return this.accessors.remove(index);
+  }
+
+  public OAuth2Token removeToken(final Integer index) throws OAuth2CacheException {
+    return this.tokens.remove(index);
+  }
+
+  public Integer storeClient(final OAuth2Client client) throws OAuth2CacheException {
+    if (client != null) {
+      final Integer index = this.getClientIndex(client.getGadgetUri(), client.getServiceName());
+      this.clients.put(index, client);
+      return index;
+    }
+
+    return null;
+  }
+
+  public void storeClients(final Collection<OAuth2Client> storeClients) throws OAuth2CacheException {
+    for (final OAuth2Client client : storeClients) {
+      final Integer index = this.getClientIndex(client.getGadgetUri(), client.getServiceName());
+      this.clients.put(index, client);
+    }
+  }
+
+  public Integer storeOAuth2Accessor(final OAuth2Accessor accessor) {
+    if (accessor != null) {
+      final Integer index = this.getOAuth2AccessorIndex(accessor.getGadgetUri(),
+          accessor.getServiceName(), accessor.getUser(), accessor.getScope());
+      this.accessors.put(index, accessor);
+      return index;
+    }
+
+    return null;
+  }
+
+  public Integer storeToken(final OAuth2Token token) throws OAuth2CacheException {
+    if (token != null) {
+      final Integer index = this.getTokenIndex(token);
+      this.tokens.put(index, token);
+      return index;
+    }
+
+    return null;
+  }
+
+  public void storeTokens(final Collection<OAuth2Token> storeTokens) throws OAuth2CacheException {
+    for (final OAuth2Token token : storeTokens) {
+      final Integer index = this.getTokenIndex(token);
+      this.tokens.put(index, token);
+    }
+  }
+}