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;
+ }
+}