You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@shindig.apache.org by be...@apache.org on 2008/09/10 03:50:42 UTC
svn commit: r693675 [2/4] - in /incubator/shindig/trunk: config/
java/common/src/main/java/org/apache/shindig/common/crypto/
java/gadgets/conf/ java/gadgets/src/main/java/org/apache/shindig/gadgets/
java/gadgets/src/main/java/org/apache/shindig/gadgets...
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetcher.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetcher.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetcher.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetcher.java Tue Sep 9 18:50:41 2008
@@ -18,20 +18,25 @@
import org.apache.shindig.auth.SecurityToken;
import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.common.uri.UriBuilder;
import org.apache.shindig.gadgets.ChainedContentFetcher;
import org.apache.shindig.gadgets.GadgetException;
+import org.apache.shindig.gadgets.RequestSigningException;
import org.apache.shindig.gadgets.http.HttpCacheKey;
import org.apache.shindig.gadgets.http.HttpFetcher;
import org.apache.shindig.gadgets.http.HttpRequest;
import org.apache.shindig.gadgets.http.HttpResponse;
import org.apache.shindig.gadgets.http.HttpResponseBuilder;
-import org.apache.shindig.gadgets.oauth.OAuthStore.OAuthParamLocation;
+import org.apache.shindig.gadgets.oauth.AccessorInfo.HttpMethod;
+import org.apache.shindig.gadgets.oauth.AccessorInfo.OAuthParamLocation;
+import org.apache.shindig.gadgets.oauth.OAuthStore.TokenInfo;
import net.oauth.OAuth;
import net.oauth.OAuthAccessor;
import net.oauth.OAuthException;
import net.oauth.OAuthMessage;
import net.oauth.OAuthProblemException;
+import net.oauth.OAuth.Parameter;
import java.io.IOException;
import java.io.PrintWriter;
@@ -41,15 +46,22 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.regex.Pattern;
/**
- * Implements the OAuth dance (http://oauth.net/core/1.0/) for gadgets.
- *
- * Reading the example in the appendix to the OAuth spec will be helpful to
- * those reading this code.
- *
- * This class is not thread-safe; create a new one for each request that
- * requires OAuth signing.
+ * Implements both signed fetch and full OAuth for gadgets, as well as a combination of the two that
+ * is necessary to build OAuth enabled gadgets for social sites.
+ *
+ * Signed fetch sticks identity information in the query string, signed either with the container's
+ * private key, or else with a secret shared between the container and the gadget.
+ *
+ * Full OAuth redirects the user to the OAuth service provider site to obtain the user's permission
+ * to access their data. Read the example in the appendix to the OAuth spec for a summary of how
+ * this works (The spec is at http://oauth.net/core/1.0/).
+ *
+ * The combination protocol works by sending identity information in all requests, and allows the
+ * OAuth dance to happen as well when owner == viewer. This lets OAuth service providers build up
+ * an identity mapping from ids on social network sites to their own local ids.
*/
public class OAuthFetcher extends ChainedContentFetcher {
@@ -57,12 +69,26 @@
private static final int MAX_ATTEMPTS = 2;
// names of additional OAuth parameters we include in outgoing requests
+ // TODO(beaton): can we do away with this bit in favor of the opensocial param?
public static final String XOAUTH_APP_URL = "xoauth_app_url";
+
+ protected static final String OPENSOCIAL_OWNERID = "opensocial_owner_id";
+
+ protected static final String OPENSOCIAL_VIEWERID = "opensocial_viewer_id";
+
+ protected static final String OPENSOCIAL_APPID = "opensocial_app_id";
+
+ // TODO(beaton): figure out if this is the name in the 0.8 spec.
+ protected static final String OPENSOCIAL_APPURL = "opensocial_app_url";
+
+ protected static final String XOAUTH_PUBLIC_KEY = "xoauth_signature_publickey";
+
+ protected static final Pattern ALLOWED_PARAM_NAME = Pattern.compile("[-:\\w~!@$*()_\\[\\]:,./]+");
/**
- * Per request configuration for this OAuth fetch.
+ * State information from client
*/
- protected final OAuthFetchParams fetchParams;
+ protected final OAuthClientState clientState;
/**
* Configuration options for the fetcher.
@@ -79,7 +105,7 @@
* the service provider, such as their URLs and the keys we use to access
* those URLs.
*/
- private OAuthStore.AccessorInfo accessorInfo;
+ private AccessorInfo accessorInfo;
/**
* The request the client really wants to make.
@@ -89,20 +115,17 @@
/**
* @param fetcherConfig configuration options for the fetcher
* @param nextFetcher fetcher to use for actually making requests
- * @param authToken user's gadget security token
- * @param params OAuth fetch parameters sent from makeRequest
+ * @param request request that will be sent through the fetcher
*/
public OAuthFetcher(
OAuthFetcherConfig fetcherConfig,
HttpFetcher nextFetcher,
- SecurityToken authToken,
- OAuthArguments params) {
+ HttpRequest request) {
super(nextFetcher);
this.fetcherConfig = fetcherConfig;
- this.fetchParams = new OAuthFetchParams(
- params,
- new OAuthClientState(fetcherConfig.getStateCrypter(), params.getOrigClientState()),
- authToken);
+ this.clientState = new OAuthClientState(
+ fetcherConfig.getStateCrypter(),
+ request.getOAuthArguments().getOrigClientState());
this.responseParams = new OAuthResponseParams(fetcherConfig.getStateCrypter());
}
@@ -115,43 +138,13 @@
* @throws GadgetException
*/
private void lookupOAuthMetadata() throws GadgetException {
- OAuthStore.TokenKey tokenKey = buildTokenKey();
accessorInfo = fetcherConfig.getTokenStore().getOAuthAccessor(
- tokenKey, fetchParams.getArguments().getBypassSpecCache());
-
- // The persistent data store may be out of sync with reality; we trust
- // the state we stored on the client to be accurate.
- OAuthAccessor accessor = accessorInfo.getAccessor();
- if (fetchParams.getClientState().getRequestToken() != null) {
- accessor.requestToken = fetchParams.getClientState().getRequestToken();
- accessor.tokenSecret = fetchParams.getClientState().getRequestTokenSecret();
- } else if (fetchParams.getClientState().getAccessToken() != null) {
- accessor.accessToken = fetchParams.getClientState().getAccessToken();
- accessor.tokenSecret = fetchParams.getClientState().getAccessTokenSecret();
- } else if (accessor.accessToken == null &&
- fetchParams.getArguments().getRequestToken() != null) {
- // We don't have an access token yet, but the client sent us a
- // (hopefully) preapproved request token.
- accessor.requestToken = fetchParams.getArguments().getRequestToken();
- accessor.tokenSecret = fetchParams.getArguments().getRequestTokenSecret();
- }
- }
-
- private OAuthStore.TokenKey buildTokenKey() {
- OAuthStore.TokenKey tokenKey = new OAuthStore.TokenKey();
- tokenKey.setGadgetUri(fetchParams.getAuthToken().getAppUrl());
- tokenKey.setModuleId(fetchParams.getAuthToken().getModuleId());
- tokenKey.setServiceName(fetchParams.getArguments().getServiceName());
- tokenKey.setTokenName(fetchParams.getArguments().getTokenName());
- // At some point we might want to let gadgets specify whether to use OAuth
- // for the owner, the viewer, or someone else. For now always using the
- // owner identity seems reasonable.
- tokenKey.setUserId(fetchParams.getAuthToken().getOwnerId());
- return tokenKey;
+ realRequest.getSecurityToken(), realRequest.getOAuthArguments(), clientState);
}
public HttpResponse fetch(HttpRequest request) throws GadgetException {
- HttpCacheKey cacheKey = makeCacheKey(request);
+ this.realRequest = request;
+ HttpCacheKey cacheKey = makeCacheKey();
HttpResponse response = fetcherConfig.getHttpCache().getResponse(cacheKey, request);
if (response != null) {
return response;
@@ -164,8 +157,6 @@
return buildErrorResponse(e);
}
- this.realRequest = request;
-
int attempts = 0;
boolean retry;
do {
@@ -189,19 +180,30 @@
return fetcherConfig.getHttpCache().addResponse(cacheKey, request, response);
}
- // Builds up a cache key based on the same key that we use into the OAuth
- // token storage, which should identify precisely which data to return for the
- // response. Using the OAuth access token as the cache key is another
- // possibility.
- private HttpCacheKey makeCacheKey(HttpRequest request) {
- HttpCacheKey key = new HttpCacheKey(request);
+ // Builds up a cache key. Full OAuth and signed fetch have slightly different cache semantics
+ // that both need to be accounted for here. For signed fetch, we need to remember what identity
+ // information we passed along (owner only? viewer only? both?). For OAuth, we need to
+ // remember whose OAuth token we used. We only use the OAuth token when owner == viewer, and
+ // it's possible we won't do it even then.
+ private HttpCacheKey makeCacheKey() {
+ HttpCacheKey key = new HttpCacheKey(realRequest);
+ SecurityToken st = realRequest.getSecurityToken();
key.set("authentication", "oauth");
- OAuthStore.TokenKey tokenKey = buildTokenKey();
- key.set("user", tokenKey.getUserId());
- key.set("gadget", tokenKey.getGadgetUri());
- key.set("instance", Long.toString(tokenKey.getModuleId()));
- key.set("service", tokenKey.getServiceName());
- key.set("token", tokenKey.getTokenName());
+ if (realRequest.getOAuthArguments().getSignOwner()) {
+ key.set("owner", st.getOwnerId());
+ }
+ if (realRequest.getOAuthArguments().getSignViewer()) {
+ key.set("viewer", st.getViewerId());
+ }
+ if (st.getOwnerId() != null
+ && st.getOwnerId().equals(st.getViewerId())
+ && realRequest.getOAuthArguments().mayUseToken()) {
+ key.set("tokenOwner", st.getOwnerId());
+ }
+ key.set("gadget", st.getAppUrl());
+ key.set("instance", Long.toString(st.getModuleId()));
+ key.set("service", realRequest.getOAuthArguments().getServiceName());
+ key.set("token", realRequest.getOAuthArguments().getTokenName());
return key;
}
@@ -226,14 +228,13 @@
}
private boolean handleProtocolException(
- OAuthProtocolException pe, int attempts) throws OAuthStoreException {
+ OAuthProtocolException pe, int attempts) throws GadgetException {
if (pe.startFromScratch()) {
- OAuthStore.TokenKey tokenKey = buildTokenKey();
- fetcherConfig.getTokenStore().removeToken(tokenKey);
-
- accessorInfo.accessor.accessToken = null;
- accessorInfo.accessor.requestToken = null;
- accessorInfo.accessor.tokenSecret = null;
+ fetcherConfig.getTokenStore().removeToken(realRequest.getSecurityToken(),
+ accessorInfo.getConsumer(), realRequest.getOAuthArguments());
+ accessorInfo.getAccessor().accessToken = null;
+ accessorInfo.getAccessor().requestToken = null;
+ accessorInfo.getAccessor().tokenSecret = null;
}
return (attempts < MAX_ATTEMPTS && pe.canRetry());
}
@@ -264,7 +265,8 @@
* Do we need to get the user's approval to access the data?
*/
private boolean needApproval() {
- return (accessorInfo.getAccessor().requestToken == null
+ return (realRequest.getOAuthArguments().mustUseToken()
+ && accessorInfo.getAccessor().requestToken == null
&& accessorInfo.getAccessor().accessToken == null);
}
@@ -275,9 +277,9 @@
* @throws GadgetException
*/
private void checkCanApprove() throws GadgetException {
- String pageOwner = fetchParams.getAuthToken().getOwnerId();
- String pageViewer = fetchParams.getAuthToken().getViewerId();
- String stateOwner = fetchParams.getClientState().getOwner();
+ String pageOwner = realRequest.getSecurityToken().getOwnerId();
+ String pageViewer = realRequest.getSecurityToken().getViewerId();
+ String stateOwner = clientState.getOwner();
if (!pageOwner.equals(pageViewer)) {
throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR,
"Only page owners can grant OAuth approval");
@@ -292,11 +294,17 @@
throws GadgetException, OAuthProtocolException {
try {
OAuthAccessor accessor = accessorInfo.getAccessor();
- String url = accessor.consumer.serviceProvider.requestTokenURL;
- List<OAuth.Parameter> msgParams = new ArrayList<OAuth.Parameter>();
- msgParams.add(new OAuth.Parameter(XOAUTH_APP_URL, fetchParams.getAuthToken().getAppUrl()));
- OAuthMessage request = newRequestMessage(url, msgParams);
- OAuthMessage reply = sendOAuthMessage(request);
+ HttpRequest request = new HttpRequest(
+ Uri.parse(accessor.consumer.serviceProvider.requestTokenURL));
+ request.setMethod(accessorInfo.getHttpMethod().toString());
+ if (accessorInfo.getHttpMethod() == HttpMethod.POST) {
+ request.setHeader("Content-Type", OAuth.FORM_ENCODED);
+ }
+
+ HttpRequest signed = sanitizeAndSign(request, null);
+
+ OAuthMessage reply = sendOAuthMessage(signed);
+
reply.requireParameters(OAuth.OAUTH_TOKEN, OAuth.OAUTH_TOKEN_SECRET);
accessor.requestToken = reply.getParameter(OAuth.OAUTH_TOKEN);
accessor.tokenSecret = reply.getParameter(OAuth.OAUTH_TOKEN_SECRET);
@@ -304,50 +312,73 @@
throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
} catch (IOException e) {
throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
- } catch (URISyntaxException e) {
- throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
}
}
- private OAuthMessage newRequestMessage(String method,
- String url, List<OAuth.Parameter> params)
- throws OAuthException, IOException, URISyntaxException {
-
- if (params == null) {
- throw new IllegalArgumentException("params was null in " +
- "newRequestMessage(String, String, List<OAuth.Parameter> " +
- "Use newRequesMessage(String) if you don't have a params to pass");
+ /**
+ * Strip out any owner or viewer identity information passed by the client.
+ *
+ * @throws RequestSigningException
+ */
+ private List<Parameter> sanitize(List<Parameter> params)
+ throws RequestSigningException {
+ ArrayList<Parameter> list = new ArrayList<Parameter>();
+ for (Parameter p : params) {
+ String name = p.getKey();
+ if (allowParam(name)) {
+ list.add(p);
+ } else {
+ throw new RequestSigningException("invalid parameter name " + name);
+ }
}
-
- switch (accessorInfo.signatureType) {
- case RSA_SHA1:
- params.add(new OAuth.Parameter(OAuth.OAUTH_SIGNATURE_METHOD,
- OAuth.RSA_SHA1));
- break;
-
- case PLAINTEXT:
- params.add(new OAuth.Parameter(OAuth.OAUTH_SIGNATURE_METHOD,
- "PLAINTEXT"));
- break;
-
- default:
- params.add(new OAuth.Parameter(OAuth.OAUTH_SIGNATURE_METHOD,
- OAuth.HMAC_SHA1));
+ return list;
+ }
+
+ private boolean allowParam(String paramName) {
+ String canonParamName = paramName.toLowerCase();
+ return (!(canonParamName.startsWith("oauth") ||
+ canonParamName.startsWith("xoauth") ||
+ canonParamName.startsWith("opensocial")) &&
+ ALLOWED_PARAM_NAME.matcher(canonParamName).matches());
+ }
+
+ /**
+ * Add identity information, such as owner/viewer/gadget.
+ */
+ private void addIdentityParams(List<Parameter> params) {
+ String owner = realRequest.getSecurityToken().getOwnerId();
+ if (owner != null && realRequest.getOAuthArguments().getSignOwner()) {
+ params.add(new Parameter(OPENSOCIAL_OWNERID, owner));
}
- OAuthAccessor accessor = accessorInfo.getAccessor();
+ String viewer = realRequest.getSecurityToken().getViewerId();
+ if (viewer != null && realRequest.getOAuthArguments().getSignViewer()) {
+ params.add(new Parameter(OPENSOCIAL_VIEWERID, viewer));
+ }
- return accessor.newRequestMessage(method, url, params);
+ String app = realRequest.getSecurityToken().getAppId();
+ if (app != null) {
+ params.add(new Parameter(OPENSOCIAL_APPID, app));
+ }
+
+ String appUrl = realRequest.getSecurityToken().getAppUrl();
+ if (appUrl != null) {
+ params.add(new Parameter(OPENSOCIAL_APPURL, appUrl));
+ }
+
+ if (accessorInfo.getConsumer().getConsumer().consumerKey == null) {
+ params.add(
+ new Parameter(OAuth.OAUTH_CONSUMER_KEY, realRequest.getSecurityToken().getDomain()));
+ }
}
-
- private OAuthMessage newRequestMessage(String url,
- List<OAuth.Parameter> params)
- throws OAuthException, IOException, URISyntaxException {
- String method = "POST";
- if (accessorInfo.getHttpMethod() == OAuthStore.HttpMethod.GET) {
- method = "GET";
+
+ /**
+ * Add signature type to the message.
+ */
+ private void addSignatureParams(List<Parameter> params) {
+ if (accessorInfo.getConsumer().getKeyName() != null) {
+ params.add(new Parameter(XOAUTH_PUBLIC_KEY, accessorInfo.getConsumer().getKeyName()));
}
- return newRequestMessage(method, url, params);
}
private String getAuthorizationHeader(
@@ -369,10 +400,49 @@
return result.toString();
}
+
+ /*
+ Start with an HttpRequest.
+ Throw if there are any attacks in the query.
+ Throw if there are any attacks in the post body.
+ Build up OAuth parameter list
+ Sign it.
+ Add OAuth parameters to new request
+ Send it.
+ */
+ public HttpRequest sanitizeAndSign(HttpRequest base, List<Parameter> params)
+ throws GadgetException {
+ if (params == null) {
+ params = new ArrayList<Parameter>();
+ }
+ UriBuilder target = new UriBuilder(base.getUri());
+ String query = target.getQuery();
+ target.setQuery(null);
+ params.addAll(sanitize(OAuth.decodeForm(query)));
+ params.addAll(sanitize(OAuth.decodeForm(base.getPostBodyAsString())));
+
+ addIdentityParams(params);
+
+ addSignatureParams(params);
+
+ try {
+ OAuthMessage signed = accessorInfo.getAccessor().newRequestMessage(
+ base.getMethod(), target.toString(), params);
+ HttpRequest oauthHttpRequest = createHttpRequest(base, selectOAuthParams(signed));
+ return oauthHttpRequest;
+ } catch (IOException e) {
+ throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
+ } catch (OAuthException e) {
+ throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
+ } catch (URISyntaxException e) {
+ throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
+ }
+ }
+
private HttpRequest createHttpRequest(HttpRequest base,
List<Map.Entry<String, String>> oauthParams) throws IOException, GadgetException {
- OAuthStore.OAuthParamLocation paramLocation = accessorInfo.getParamLocation();
+ OAuthParamLocation paramLocation = accessorInfo.getParamLocation();
// paramLocation could be overriden by a run-time parameter to fetchRequest
@@ -383,9 +453,9 @@
// can't have a body, or we can stick the parameters somewhere else, like, say, the header.
// We opt to put them in the header, since that stands some chance of working with some
// OAuth service providers.
- if (paramLocation == OAuthStore.OAuthParamLocation.POST_BODY &&
+ if (paramLocation == OAuthParamLocation.POST_BODY &&
!result.getMethod().equals("POST")) {
- paramLocation = OAuthStore.OAuthParamLocation.AUTH_HEADER;
+ paramLocation = OAuthParamLocation.AUTH_HEADER;
}
switch (paramLocation) {
@@ -394,7 +464,8 @@
break;
case POST_BODY:
- if (!OAuth.isFormEncoded(result.getContentType())) {
+ String contentType = result.getHeader("Content-Type");
+ if (!OAuth.isFormEncoded(contentType)) {
throw new GadgetException(GadgetException.Code.INVALID_PARAMETER,
"OAuth param location can only be post_body if post body if of " +
"type x-www-form-urlencoded");
@@ -417,22 +488,13 @@
/**
* Sends OAuth request token and access token messages.
- */
- private OAuthMessage sendOAuthMessage(OAuthMessage request)
- throws IOException, OAuthProtocolException, GadgetException {
-
- HttpRequest req = new HttpRequest(Uri.parse(request.URL))
- .setMethod(request.method)
- .setIgnoreCache(true);
-
- // Per section 5.2 of OAuth spec
- if (accessorInfo.paramLocation == OAuthParamLocation.POST_BODY) {
- req.setHeader("Content-Type", "application/x-www-form-urlencoded");
- }
-
- HttpRequest oauthRequest = createHttpRequest(req, filterOAuthParams(request));
-
- HttpResponse response = nextFetcher.fetch(oauthRequest);
+ * @throws GadgetException
+ * @throws IOException
+ * @throws OAuthProtocolException
+ */
+ private OAuthMessage sendOAuthMessage(HttpRequest request)
+ throws GadgetException, OAuthProtocolException, IOException {
+ HttpResponse response = nextFetcher.fetch(request);
checkForProtocolProblem(response);
OAuthMessage reply = new OAuthMessage(null, null, null);
@@ -468,7 +530,7 @@
OAuthAccessor accessor = accessorInfo.getAccessor();
responseParams.getNewClientState().setRequestToken(accessor.requestToken);
responseParams.getNewClientState().setRequestTokenSecret(accessor.tokenSecret);
- responseParams.getNewClientState().setOwner(fetchParams.getAuthToken().getOwnerId());
+ responseParams.getNewClientState().setOwner(realRequest.getSecurityToken().getOwnerId());
}
/**
@@ -506,7 +568,8 @@
* Do we need to exchange a request token for an access token?
*/
private boolean needAccessToken() {
- return (accessorInfo.getAccessor().requestToken != null
+ return (realRequest.getOAuthArguments().mustUseToken()
+ && accessorInfo.getAccessor().requestToken != null
&& accessorInfo.getAccessor().accessToken == null);
}
@@ -518,13 +581,20 @@
throws GadgetException, OAuthProtocolException {
try {
OAuthAccessor accessor = accessorInfo.getAccessor();
- String url = accessor.consumer.serviceProvider.accessTokenURL;
- List<OAuth.Parameter> msgParams = new ArrayList<OAuth.Parameter>();
- msgParams.add(new OAuth.Parameter(XOAUTH_APP_URL, fetchParams.getAuthToken().getAppUrl()));
- msgParams.add(
- new OAuth.Parameter(OAuth.OAUTH_TOKEN, accessor.requestToken));
- OAuthMessage request = newRequestMessage(url, msgParams);
- OAuthMessage reply = sendOAuthMessage(request);
+ HttpRequest request = new HttpRequest(
+ Uri.parse(accessor.consumer.serviceProvider.accessTokenURL));
+ request.setMethod(accessorInfo.getHttpMethod().toString());
+ if (accessorInfo.getHttpMethod() == HttpMethod.POST) {
+ request.setHeader("Content-Type", OAuth.FORM_ENCODED);
+ }
+
+ List<Parameter> msgParams = new ArrayList<Parameter>();
+ msgParams.add(new Parameter(OAuth.OAUTH_TOKEN, accessor.requestToken));
+
+ HttpRequest signed = sanitizeAndSign(request, msgParams);
+
+ OAuthMessage reply = sendOAuthMessage(signed);
+
reply.requireParameters(OAuth.OAUTH_TOKEN, OAuth.OAUTH_TOKEN_SECRET);
accessor.accessToken = reply.getParameter(OAuth.OAUTH_TOKEN);
accessor.tokenSecret = reply.getParameter(OAuth.OAUTH_TOKEN_SECRET);
@@ -532,8 +602,6 @@
throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
} catch (IOException e) {
throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
- } catch (URISyntaxException e) {
- throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
}
}
@@ -544,10 +612,9 @@
*/
private void saveAccessToken() throws GadgetException {
OAuthAccessor accessor = accessorInfo.getAccessor();
- OAuthStore.TokenKey tokenKey = buildTokenKey();
- OAuthStore.TokenInfo tokenInfo = new OAuthStore.TokenInfo(
- accessor.accessToken, accessor.tokenSecret);
- fetcherConfig.getTokenStore().storeTokenKeyAndSecret(tokenKey, tokenInfo);
+ TokenInfo tokenInfo = new TokenInfo(accessor.accessToken, accessor.tokenSecret);
+ fetcherConfig.getTokenStore().storeTokenKeyAndSecret(realRequest.getSecurityToken(),
+ accessorInfo.getConsumer(), realRequest.getOAuthArguments(), tokenInfo);
}
/**
@@ -557,7 +624,7 @@
OAuthAccessor accessor = accessorInfo.getAccessor();
responseParams.getNewClientState().setAccessToken(accessor.accessToken);
responseParams.getNewClientState().setAccessTokenSecret(accessor.tokenSecret);
- responseParams.getNewClientState().setOwner(fetchParams.getAuthToken().getOwnerId());
+ responseParams.getNewClientState().setOwner(realRequest.getSecurityToken().getOwnerId());
}
/**
@@ -569,28 +636,10 @@
private HttpResponse fetchData()
throws GadgetException, OAuthProtocolException {
try {
- List<OAuth.Parameter> msgParams =
- OAuth.isFormEncoded(realRequest.getContentType())
- ? OAuth.decodeForm(realRequest.getPostBodyAsString())
- : new ArrayList<OAuth.Parameter>();
-
- String method = realRequest.getMethod();
-
- msgParams.add(new OAuth.Parameter(XOAUTH_APP_URL, fetchParams.getAuthToken().getAppUrl()));
-
- // Build and sign the message.
- OAuthMessage oauthRequest = newRequestMessage(
- method, realRequest.getUri().toString(), msgParams);
-
- HttpRequest oauthHttpRequest = createHttpRequest(
- realRequest,
- filterOAuthParams(oauthRequest));
-
- // Not externally cacheable.
- oauthHttpRequest.setIgnoreCache(true);
-
- HttpResponse response = nextFetcher.fetch(oauthHttpRequest);
-
+ HttpRequest signed = sanitizeAndSign(realRequest, null);
+
+ HttpResponse response = nextFetcher.fetch(signed);
+
checkForProtocolProblem(response);
// Track metadata on the response
@@ -601,10 +650,6 @@
throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
} catch (IOException e) {
throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
- } catch (URISyntaxException e) {
- throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
- } catch (OAuthException e) {
- throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
}
}
@@ -640,15 +685,19 @@
* @throws IOException
*/
private List<Map.Entry<String, String>>
- filterOAuthParams(OAuthMessage message) throws IOException {
+ selectOAuthParams(OAuthMessage message) throws IOException {
List<Map.Entry<String, String>> result =
new ArrayList<Map.Entry<String, String>>();
for (Map.Entry<String, String> param : message.getParameters()) {
- if (param.getKey().toLowerCase().startsWith("oauth")
- || param.getKey().toLowerCase().startsWith("xoauth")) {
+ if (isContainerInjectedParameter(param.getKey())) {
result.add(param);
}
}
return result;
}
+
+ private boolean isContainerInjectedParameter(String key) {
+ key = key.toLowerCase();
+ return key.startsWith("oauth") || key.startsWith("xoauth") || key.startsWith("opensocial");
+ }
}
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetcherConfig.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetcherConfig.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetcherConfig.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetcherConfig.java Tue Sep 9 18:50:41 2008
@@ -17,7 +17,11 @@
package org.apache.shindig.gadgets.oauth;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+
import org.apache.shindig.common.crypto.BlobCrypter;
+import org.apache.shindig.gadgets.DefaultGuiceModule;
import org.apache.shindig.gadgets.http.HttpCache;
/**
@@ -29,6 +33,16 @@
private final GadgetOAuthTokenStore tokenStore;
private final HttpCache httpCache;
+ @Inject
+ public OAuthFetcherConfig(
+ @Named(DefaultGuiceModule.OAUTH_STATE_CRYPTER_ANNOTATION) BlobCrypter stateCrypter,
+ GadgetOAuthTokenStore tokenStore,
+ HttpCache httpCache) {
+ this.stateCrypter = stateCrypter;
+ this.tokenStore = tokenStore;
+ this.httpCache = httpCache;
+ }
+
/**
* Used to encrypt state stored on the client.
*/
@@ -50,10 +64,4 @@
return httpCache;
}
- public OAuthFetcherConfig(BlobCrypter stateCrypter, GadgetOAuthTokenStore tokenStore,
- HttpCache httpCache) {
- this.stateCrypter = stateCrypter;
- this.tokenStore = tokenStore;
- this.httpCache = httpCache;
- }
}
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetcherFactory.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetcherFactory.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetcherFactory.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetcherFactory.java Tue Sep 9 18:50:41 2008
@@ -18,20 +18,12 @@
*/
package org.apache.shindig.gadgets.oauth;
-import org.apache.shindig.auth.SecurityToken;
-import org.apache.shindig.common.crypto.BasicBlobCrypter;
-import org.apache.shindig.common.crypto.BlobCrypter;
-import org.apache.shindig.common.crypto.Crypto;
-import org.apache.shindig.gadgets.GadgetException;
-import org.apache.shindig.gadgets.GadgetSpecFactory;
-import org.apache.shindig.gadgets.http.HttpCache;
-import org.apache.shindig.gadgets.http.HttpFetcher;
-
import com.google.inject.Inject;
import com.google.inject.Singleton;
-import java.util.logging.Level;
-import java.util.logging.Logger;
+import org.apache.shindig.gadgets.GadgetException;
+import org.apache.shindig.gadgets.http.HttpFetcher;
+import org.apache.shindig.gadgets.http.HttpRequest;
/**
* Produces OAuth content fetchers for input tokens.
@@ -41,35 +33,12 @@
protected OAuthFetcherConfig fetcherConfig;
- private static final Logger logger
- = Logger.getLogger(OAuthFetcherFactory.class.getName());
-
- /**
- * Initialize the OAuth factory with a default implementation of
- * BlobCrypter and consumer keys/secrets read from oauth.js
- */
- @Inject
- public OAuthFetcherFactory(GadgetSpecFactory specFactory, HttpCache cache) {
- try {
- BlobCrypter oauthCrypter = new BasicBlobCrypter(
- Crypto.getRandomBytes(BasicBlobCrypter.MASTER_KEY_MIN_LEN));
-
- BasicGadgetOAuthTokenStore store =
- new BasicGadgetOAuthTokenStore(new BasicOAuthStore(), specFactory);
- store.initFromConfigFile();
- fetcherConfig = new OAuthFetcherConfig(oauthCrypter, store, cache);
- } catch (Throwable t) {
- // Since this happens at startup, we don't want to kill the server just
- // because we can't initialize the OAuth config.
- logger.log(Level.WARNING, "Failed to initialize OAuth", t);
- }
- }
-
/**
* Creates an OAuthFetcherFactory based on prepared crypter and token store.
*
* @param fetcherConfig configuration
*/
+ @Inject
protected OAuthFetcherFactory(OAuthFetcherConfig fetcherConfig) {
this.fetcherConfig = fetcherConfig;
}
@@ -79,17 +48,16 @@
* network retrieval to the {@code nextFetcher}
*
* @param nextFetcher The fetcher that will fetch real content
- * @param token The gadget token used to identity the user and gadget
- * @param params The parsed parameters the gadget requested
+ * @param request request that will be sent through the fetcher
* @return The oauth fetcher.
* @throws GadgetException
*/
@SuppressWarnings("unused")
- public OAuthFetcher getOAuthFetcher(
- HttpFetcher nextFetcher,
- SecurityToken token,
- OAuthArguments params) throws GadgetException {
- OAuthFetcher fetcher = new OAuthFetcher(fetcherConfig, nextFetcher, token, params);
+ public OAuthFetcher getOAuthFetcher(HttpFetcher nextFetcher, HttpRequest request)
+ throws GadgetException {
+ OAuthFetcher fetcher = new OAuthFetcher(fetcherConfig, nextFetcher, request);
return fetcher;
}
+
+
}
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthStore.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthStore.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthStore.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthStore.java Tue Sep 9 18:50:41 2008
@@ -17,7 +17,10 @@
*/
package org.apache.shindig.gadgets.oauth;
-import net.oauth.OAuthAccessor;
+import org.apache.shindig.auth.SecurityToken;
+import org.apache.shindig.gadgets.GadgetException;
+
+import net.oauth.OAuthConsumer;
import net.oauth.OAuthServiceProvider;
/**
@@ -44,306 +47,37 @@
public interface OAuthStore {
/**
- * If we or a gadget negotiate a separate consumer key and secret with a
- * service provider, use this method to store it. The "secret" can either
- * be a consumer secret in the strict OAuth sense, or it can be a
- * PKCS8-then-Base64 encoded private key that we'll be using with this
- * service provider. Even if we never set a consumer secret, an implementation
- * of this interface may still be able to return useful OAuthAccessors in
- * the getOAuthAccessor method, e.g. by returning a fallback private key and
- * default consumer key, which could be used with service providers that we
- * haven't negotiated a consumer secret with.
- *
- * @param providerKey the gadget that wants to use the service provider, and
- * a nickName under which the gadget will refer to this
- * service provider in the future.
- * @param keyAndSecret the consumer key and secret. If the secret is an RSA
- * private key, it must be PKCS8-then-Base64 encoded.
- * @throws OAuthStoreException if something goes wrong accessing the
- * data store.
- * @throws OAuthNoDataException if no provider info can be found for the
- * provider specified in the providerKey.
- */
- public void setOAuthConsumerKeyAndSecret(ProviderKey providerKey,
- ConsumerKeyAndSecret keyAndSecret)
- throws OAuthStoreException, OAuthNoDataException;
-
- /**
- * Stores an access token.
- * @param tokenKey a structure uniquely identifying the key under which this
- * access token should be retrievable: a userId, a gadgetId,
- * a moduleId (in case there are more than one gadget of the
- * same type on a page), a tokenName (which distinguishes
- * this token from others that the same gadget might hold for
- * the same service provider) and a serviceName (which is the
- * same as the service name in the ProviderKey structure).
- * @param tokenInfo an access token and token secret.
- * @throws OAuthStoreException if an error occurs talking to the
- * data store.
+ * Information about an OAuth consumer.
*/
- public void setTokenAndSecret(TokenKey tokenKey, TokenInfo tokenInfo)
- throws OAuthStoreException;
-
-
- /**
- * Removes an access token
- * @param tokenKey the identifier for the access token
- * @throws OAuthStoreException if an error occurs talking to the data store.
- * @throws OAuthNoDataException if no existing access token is found.
- */
- public void removeToken(TokenKey tokenKey)
- throws OAuthStoreException, OAuthNoDataException;
+ public static class ConsumerInfo {
+ private final OAuthConsumer consumer;
+ private final String keyName;
+
+ /**
+ * @param consumer the OAuth consumer
+ * @param keyName the name of the key to use for this consumer (passed on query parameters to
+ * help with key rotation.)
+ */
+ public ConsumerInfo(OAuthConsumer consumer, String keyName) {
+ this.consumer = consumer;
+ this.keyName = keyName;
+ }
+
+ public OAuthConsumer getConsumer() {
+ return consumer;
+ }
+
+ public String getKeyName() {
+ return keyName;
+ }
+ }
/**
- * Retrieve an OAuthAccessor that is ready to sign OAuthMessages for
- * resource access.
- * @param tokenKey a structure uniquely identifying the token: a userId,
- * a gadgetId, a moduleId (in case there are more than one
- * gadget of the same type on a page), a tokenName (which
- * distinguishes this token from others that the same gadget
- * might hold for the same service provider) and a serviceName
- * (which is the same as the service name in the ProviderKey
- * structure).
- * @param provInfo provider information. The store combines information stored
- * in the store (consumer key/secret, token, token secret,
- * etc.) with the provider information (access URL, request
- * URL etc.) passed in here to create an AccessorInfo object.
- * If no information can be found in the
- * store, it may use default keys that identify the container,
- * as opposed to consumer keys and secrets that are specific
- * to this gadget.
- * @return an OAuthAccessor object than can be passed to an OAuthMessage.sign
- * method.
- * @throws OAuthNoDataException if the token couldn't be found
- * @throws OAuthStoreException if an error occurred accessing the data
- * store.
+ * Information about an access token.
*/
- public AccessorInfo getOAuthAccessor(TokenKey tokenKey,
- ProviderInfo provInfo)
- throws OAuthNoDataException, OAuthStoreException;
-
-
- //////////////////////////////////////////////////////////////////////////////
- // Auxiliary types needed to work with this interface
- //////////////////////////////////////////////////////////////////////////////
-
- public static enum HttpMethod { GET, POST }
- public static enum SignatureType {HMAC_SHA1, RSA_SHA1, PLAINTEXT}
- public static enum KeyType { HMAC_SYMMETRIC, RSA_PRIVATE }
- public static enum OAuthParamLocation {
- AUTH_HEADER,
- POST_BODY,
- URI_QUERY
- }
-
- public static class AccessorInfo {
- OAuthAccessor accessor;
- HttpMethod httpMethod;
- SignatureType signatureType;
- OAuthParamLocation paramLocation;
-
- public OAuthParamLocation getParamLocation() {
- return paramLocation;
- }
- public void setParamLocation(OAuthParamLocation paramLocation) {
- this.paramLocation = paramLocation;
- }
- public OAuthAccessor getAccessor() {
- return accessor;
- }
- public void setAccessor(OAuthAccessor accessor) {
- this.accessor = accessor;
- }
- public HttpMethod getHttpMethod() {
- return httpMethod;
- }
- public void setHttpMethod(HttpMethod httpMethod) {
- this.httpMethod = httpMethod;
- }
- public SignatureType getSignatureType() {
- return signatureType;
- }
- public void setSignatureType(SignatureType signatureType) {
- this.signatureType = signatureType;
- }
- }
-
- public static class ConsumerKeyAndSecret {
- private String consumerKey;
- private String consumerSecret;
- private KeyType keyType;
-
- public ConsumerKeyAndSecret(String key, String secret, KeyType type) {
- consumerKey = key;
- consumerSecret = secret;
- keyType = type;
- }
- public String getConsumerKey() {
- return consumerKey;
- }
- public String getConsumerSecret() {
- return consumerSecret;
- }
- public KeyType getKeyType() {
- return keyType;
- }
- }
-
- public static class ProviderKey {
- private String gadgetUri;
- private String serviceName;
-
- public String getGadgetUri() {
- return gadgetUri;
- }
- public void setGadgetUri(String gadgetUri) {
- this.gadgetUri = gadgetUri;
- }
- public String getServiceName() {
- return serviceName;
- }
- public void setServiceName(String serviceName) {
- this.serviceName = serviceName;
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result =
- prime * result + ((gadgetUri == null) ? 0 : gadgetUri.hashCode());
- result =
- prime * result + ((serviceName == null) ? 0 : serviceName.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) return true;
- if (obj == null) return false;
- if (getClass() != obj.getClass()) return false;
- final ProviderKey other = (ProviderKey) obj;
- if (gadgetUri == null) {
- if (other.gadgetUri != null) return false;
- } else if (!gadgetUri.equals(other.gadgetUri)) return false;
- if (serviceName == null) {
- if (other.serviceName != null) return false;
- } else if (!serviceName.equals(other.serviceName)) return false;
- return true;
- }
- }
-
- public static class ProviderInfo {
- private OAuthServiceProvider provider;
- private HttpMethod httpMethod;
- private SignatureType signatureType;
- private OAuthParamLocation paramLocation;
-
- public OAuthParamLocation getParamLocation() {
- return paramLocation;
- }
- public void setParamLocation(OAuthParamLocation paramLocation) {
- this.paramLocation = paramLocation;
- }
- public OAuthServiceProvider getProvider() {
- return provider;
- }
- public void setProvider(OAuthServiceProvider provider) {
- this.provider = provider;
- }
- public HttpMethod getHttpMethod() {
- return httpMethod;
- }
- public void setHttpMethod(HttpMethod httpMethod) {
- this.httpMethod = httpMethod;
- }
- public SignatureType getSignatureType() {
- return signatureType;
- }
- public void setSignatureType(SignatureType signatureType) {
- this.signatureType = signatureType;
- }
- }
-
- public static class TokenKey {
- private String userId;
- private String gadgetUri;
- private long moduleId;
- private String tokenName;
- private String serviceName;
-
- public String getUserId() {
- return userId;
- }
- public void setUserId(String userId) {
- this.userId = userId;
- }
- public String getGadgetUri() {
- return gadgetUri;
- }
- public void setGadgetUri(String gadgetUri) {
- this.gadgetUri = gadgetUri;
- }
- public long getModuleId() {
- return moduleId;
- }
- public void setModuleId(long moduleId) {
- this.moduleId = moduleId;
- }
- public String getTokenName() {
- return tokenName;
- }
- public void setTokenName(String tokenName) {
- this.tokenName = tokenName;
- }
- public String getServiceName() {
- return serviceName;
- }
- public void setServiceName(String serviceName) {
- this.serviceName = serviceName;
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result =
- prime * result + ((gadgetUri == null) ? 0 : gadgetUri.hashCode());
- result = prime * result + (int) (moduleId ^ (moduleId >>> 32));
- result =
- prime * result + ((serviceName == null) ? 0 : serviceName.hashCode());
- result =
- prime * result + ((tokenName == null) ? 0 : tokenName.hashCode());
- result = prime * result + ((userId == null) ? 0 : userId.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) return true;
- if (obj == null) return false;
- if (getClass() != obj.getClass()) return false;
- final TokenKey other = (TokenKey) obj;
- if (gadgetUri == null) {
- if (other.gadgetUri != null) return false;
- } else if (!gadgetUri.equals(other.gadgetUri)) return false;
- if (moduleId != other.moduleId) return false;
- if (serviceName == null) {
- if (other.serviceName != null) return false;
- } else if (!serviceName.equals(other.serviceName)) return false;
- if (tokenName == null) {
- if (other.tokenName != null) return false;
- } else if (!tokenName.equals(other.tokenName)) return false;
- if (userId == null) {
- if (other.userId != null) return false;
- } else if (!userId.equals(other.userId)) return false;
- return true;
- }
- }
-
public static class TokenInfo {
- private String accessToken;
- private String tokenSecret;
+ private final String accessToken;
+ private final String tokenSecret;
public TokenInfo(String token, String secret) {
accessToken = token;
tokenSecret = secret;
@@ -355,4 +89,41 @@
return tokenSecret;
}
}
+
+ /**
+ * Retrieve OAuth consumer to use for requests. The returned consumer is ready to use for signed
+ * fetch requests.
+ *
+ * @param securityToken token for user/gadget making request.
+ * @param serviceName gadget's nickname for the service being accessed.
+ * @param provider OAuth service provider info to be inserted into the returned consumer.
+ *
+ * @throws GadgetException if no OAuth consumer can be found (e.g. no consumer key can be used.)
+ */
+ public ConsumerInfo getConsumerKeyAndSecret(SecurityToken securityToken, String serviceName,
+ OAuthServiceProvider provider) throws GadgetException;
+
+ /**
+ * Retrieve OAuth access token to use for the request.
+ * @param securityToken token for user/gadget making request.
+ * @param consumerInfo OAuth consumer that will be used for the request.
+ * @param serviceName gadget's nickname for the service being accessed.
+ * @param tokenName gadget's nickname for the token to use.
+ * @return the token and secret, or null if none exist
+ * @throws GadgetException if an error occurs during lookup
+ */
+ public TokenInfo getTokenInfo(SecurityToken securityToken, ConsumerInfo consumerInfo,
+ String serviceName, String tokenName) throws GadgetException;
+
+ /**
+ * Set the access token for the given user/gadget/service/token
+ */
+ public void setTokenInfo(SecurityToken securityToken, ConsumerInfo consumerInfo, String serviceName,
+ String tokenName, TokenInfo tokenInfo) throws GadgetException;
+
+ /**
+ * Remove the access token for the given user/gadget/service/token
+ */
+ public void removeToken(SecurityToken securityToken, ConsumerInfo consumerInfo,
+ String serviceName, String tokenName) throws GadgetException;
}
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/HttpPreloader.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/HttpPreloader.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/HttpPreloader.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/HttpPreloader.java Tue Sep 9 18:50:41 2008
@@ -71,8 +71,7 @@
// TODO: This should be extracted into a common helper that takes any
// org.apache.shindig.gadgets.spec.RequestAuthenticationInfo.
HttpRequest request = new HttpRequest(Uri.fromJavaUri(preload.getHref()))
- .setSignOwner(preload.isSignOwner())
- .setSignViewer(preload.isSignViewer())
+ .setOAuthArguments(new OAuthArguments(preload))
.setContainer(context.getContainer())
.setSecurityToken(context.getToken())
.setGadget(Uri.fromJavaUri(context.getUrl()));
@@ -82,11 +81,8 @@
response = fetcher.get().fetch(request);
break;
case SIGNED:
- response = fetcher.getSigningFetcher(context.getToken()).fetch(request);
- break;
case OAUTH:
- response = fetcher.getOAuthFetcher(context.getToken(), new OAuthArguments(preload))
- .fetch(request);
+ response = fetcher.getOAuthFetcher(request).fetch(request);
break;
}
return new HttpPreloadData(response);
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HttpGuiceModule.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HttpGuiceModule.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HttpGuiceModule.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HttpGuiceModule.java Tue Sep 9 18:50:41 2008
@@ -33,8 +33,8 @@
super.configure();
}
- public HttpGuiceModule(Properties properties) {
- super(properties);
+ public HttpGuiceModule(Properties properties, String oauthConfigJson) {
+ super(properties, oauthConfigJson);
}
public HttpGuiceModule() {
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/MakeRequestHandler.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/MakeRequestHandler.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/MakeRequestHandler.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/MakeRequestHandler.java Tue Sep 9 18:50:41 2008
@@ -56,8 +56,6 @@
public static final String METHOD_PARAM = "httpMethod";
public static final String HEADERS_PARAM = "headers";
public static final String NOCACHE_PARAM = "nocache";
- public static final String SIGN_VIEWER = "signViewer";
- public static final String SIGN_OWNER = "signOwner";
public static final String CONTENT_TYPE_PARAM = "contentType";
public static final String NUM_ENTRIES_PARAM = "numEntries";
public static final String DEFAULT_NUM_ENTRIES = "3";
@@ -82,14 +80,17 @@
// Figure out whether authentication is required
Auth auth = Auth.parse(getParameter(request, AUTHZ_PARAM, ""));
SecurityToken authToken = null;
+ OAuthArguments oauthArguments = null;
if (auth != Auth.NONE) {
authToken = extractAndValidateToken(request);
+ oauthArguments = new OAuthArguments(auth, request);
}
rcr.setSecurityToken(authToken);
+ rcr.setOAuthArguments(oauthArguments);
// Build the chain of fetchers that will handle the request
- HttpFetcher fetcher = getHttpFetcher(auth, authToken, request);
+ HttpFetcher fetcher = getHttpFetcher(auth, rcr);
// Serialize the response
HttpResponse results = fetcher.fetch(rcr);
@@ -140,12 +141,6 @@
req.setIgnoreCache("1".equals(request.getParameter(NOCACHE_PARAM)));
- if (request.getParameter(SIGN_VIEWER) != null) {
- req.setSignViewer(Boolean.parseBoolean(request.getParameter(SIGN_VIEWER)));
- }
- if (request.getParameter(SIGN_OWNER) != null) {
- req.setSignOwner(Boolean.parseBoolean(request.getParameter(SIGN_OWNER)));
- }
if (request.getParameter(GADGET_PARAM) != null) {
req.setGadget(Uri.parse(request.getParameter(GADGET_PARAM)));
}
@@ -179,17 +174,13 @@
* Whatever we do needs to return a reference to the OAuthFetcher, if it is
* present, so we can pull data out as needed.
*/
- private HttpFetcher getHttpFetcher(Auth auth, SecurityToken token, HttpServletRequest request)
- throws GadgetException {
+ private HttpFetcher getHttpFetcher(Auth auth, HttpRequest request) throws GadgetException {
switch (auth) {
case NONE:
return contentFetcherFactory.get();
case SIGNED:
- // TODO: Remove token from signature and use what's on the request object instead.
- return contentFetcherFactory.getSigningFetcher(token);
case OAUTH:
- // TODO: Remove token from signature, return what's on the request object.
- return contentFetcherFactory.getOAuthFetcher(token, new OAuthArguments(request));
+ return contentFetcherFactory.getOAuthFetcher(request);
default:
return contentFetcherFactory.get();
}
Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java Tue Sep 9 18:50:41 2008
@@ -305,7 +305,8 @@
"</Module>";
expect(fetcher.fetch(SPEC_REQUEST))
.andReturn(new HttpResponse(gadgetXml));
- expect(fetcherFactory.getSigningFetcher(BASIC_CONTEXT.getToken()))
+ expect(fetcherFactory.getOAuthFetcher(
+ isA(HttpRequest.class)))
.andReturn(fetcher);
expect(fetcher.fetch(preloadRequest))
.andReturn(new HttpResponse(preloadData));
@@ -332,7 +333,7 @@
expect(fetcher.fetch(SPEC_REQUEST))
.andReturn(new HttpResponse(gadgetXml));
expect(fetcherFactory.getOAuthFetcher(
- isA(SecurityToken.class), isA(OAuthArguments.class)))
+ isA(HttpRequest.class)))
.andReturn(fetcher);
expect(fetcher.fetch(preloadRequest))
.andReturn(new HttpResponse(preloadData));
Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetTestFixture.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetTestFixture.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetTestFixture.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetTestFixture.java Tue Sep 9 18:50:41 2008
@@ -39,7 +39,6 @@
public final GadgetServer gadgetServer;
public final ContentFetcherFactory fetcherFactory = mock(ContentFetcherFactory.class);
public final HttpFetcher fetcher = mock(HttpFetcher.class);
- public final SigningFetcher signingFetcher = mock(SigningFetcher.class);
public final OAuthFetcher oauthFetcher = mock(OAuthFetcher.class);
public final ContentFetcherFactory contentFetcherFactory = mock(ContentFetcherFactory.class);
public final GadgetBlacklist blacklist = mock(GadgetBlacklist.class);
Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpRequestTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpRequestTest.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpRequestTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpRequestTest.java Tue Sep 9 18:50:41 2008
@@ -23,6 +23,7 @@
import org.apache.shindig.auth.AnonymousSecurityToken;
import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.gadgets.oauth.OAuthArguments;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
@@ -85,6 +86,9 @@
@Test
public void copyCtorCopiesAllFields() {
+ OAuthArguments oauthArguments = new OAuthArguments();
+ oauthArguments.setSignOwner(false);
+ oauthArguments.setSignViewer(true);
HttpRequest request = new HttpRequest(DEFAULT_URI)
.setCacheTtl(100)
.addHeader(TEST_HEADER_KEY, TEST_HEADER_VALUE)
@@ -94,8 +98,7 @@
.setPostBody(POST_BODY.getBytes())
.setRewriteMimeType("text/fake")
.setSecurityToken(new AnonymousSecurityToken())
- .setSignOwner(false)
- .setSignViewer(false);
+ .setOAuthArguments(oauthArguments);
HttpRequest request2 = new HttpRequest(request).setUri(Uri.parse("http://example.org/foo"));
@@ -107,7 +110,9 @@
assertEquals(request.getPostBodyAsString(), request2.getPostBodyAsString());
assertEquals(request.getRewriteMimeType(), request2.getRewriteMimeType());
assertEquals(request.getSecurityToken(), request2.getSecurityToken());
- assertEquals(request.getSignOwner(), request2.getSignOwner());
- assertEquals(request.getSignViewer(), request2.getSignViewer());
+ assertEquals(request.getOAuthArguments().getSignOwner(),
+ request2.getOAuthArguments().getSignOwner());
+ assertEquals(request.getOAuthArguments().getSignViewer(),
+ request2.getOAuthArguments().getSignViewer());
}
}
Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreTest.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreTest.java Tue Sep 9 18:50:41 2008
@@ -18,330 +18,122 @@
*/
package org.apache.shindig.gadgets.oauth;
-import static org.easymock.EasyMock.eq;
-import static org.easymock.EasyMock.expect;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
-import org.apache.shindig.auth.SecurityTokenDecoder;
-
-import junit.framework.TestCase;
-
-import net.oauth.OAuthAccessor;
+import net.oauth.OAuthConsumer;
import net.oauth.OAuthServiceProvider;
import net.oauth.signature.RSA_SHA1;
-import org.easymock.classextension.EasyMock;
-import org.easymock.classextension.IMocksControl;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class BasicOAuthStoreTest extends TestCase {
-
- private IMocksControl control;
- private Map<OAuthStore.ProviderKey, OAuthStore.ConsumerKeyAndSecret>
- mockConsumerInfos;
- private Map<OAuthStore.TokenKey, OAuthStore.TokenInfo> mockTokens;
- private BasicOAuthStore noDefaultStore;
- private BasicOAuthStore withDefaultStore;
- private String defaultKey = "defaultkey";
- private String defaultSecret = "defaultsecret"; // not quite a PKCS8-encoded
- // RSA key, but that's ok
-
- @Override
- @SuppressWarnings("unchecked")
- protected void setUp() throws Exception {
- super.setUp();
- control = EasyMock.createStrictControl();
- mockConsumerInfos = control.createMock(
- new HashMap<OAuthStore.ProviderKey,
- OAuthStore.ConsumerKeyAndSecret>().getClass());
- mockTokens = control.createMock(
- new HashMap<OAuthStore.TokenKey, OAuthStore.TokenInfo>().getClass());
-
- noDefaultStore = new BasicOAuthStore();
- noDefaultStore.setHashMapsForTesting(mockConsumerInfos, mockTokens);
-
- withDefaultStore = new BasicOAuthStore(defaultKey, defaultSecret);
- withDefaultStore.setHashMapsForTesting(mockConsumerInfos, mockTokens);
+import org.apache.shindig.common.testing.FakeGadgetToken;
+import org.apache.shindig.gadgets.GadgetException;
+import org.apache.shindig.gadgets.oauth.BasicOAuthStoreConsumerKeyAndSecret.KeyType;
+import org.apache.shindig.gadgets.oauth.OAuthStore.ConsumerInfo;
+import org.apache.shindig.gadgets.oauth.OAuthStore.TokenInfo;
+import org.junit.Before;
+import org.junit.Test;
+
+public class BasicOAuthStoreTest {
+
+ private static final String SAMPLE_FILE =
+ "{" +
+ "'http://localhost:8080/gadgets/files/samplecontainer/examples/oauth.xml' : {" +
+ "'' : {" +
+ "'consumer_key' : 'gadgetConsumer'," +
+ "'consumer_secret' : 'gadgetSecret'," +
+ "'key_type' : 'HMAC_SYMMETRIC'" +
+ "}" +
+ "}," +
+ "'http://rsagadget/test.xml' : {" +
+ "'' : {" +
+ "'consumer_key' : 'rsaconsumer'," +
+ "'consumer_secret' : 'rsaprivate'," +
+ "'key_type' : 'RSA_PRIVATE'" +
+ "}" +
+ "}" +
+
+ "}";
+
+ private BasicOAuthStore store;
+
+ @Before
+ public void setUp() throws Exception {
+ store = new BasicOAuthStore();
+ store.initFromConfigString(SAMPLE_FILE);
}
-
- public void testGetOAuthAccessor() throws Exception {
- OAuthStore.TokenKey tokenKey = new OAuthStore.TokenKey();
- tokenKey.setGadgetUri("http://foo.bar.com/gadget.xml");
- tokenKey.setModuleId(2348709L);
- tokenKey.setUserId("testuser");
- tokenKey.setServiceName("testservice");
- tokenKey.setTokenName("testtoken");
-
- OAuthStore.TokenInfo tokenInfo = new OAuthStore.TokenInfo("accesstoken",
- "tokensecret");
-
- OAuthStore.ProviderKey provKey = new OAuthStore.ProviderKey();
- provKey.setGadgetUri(tokenKey.getGadgetUri());
- provKey.setServiceName(tokenKey.getServiceName());
-
- OAuthServiceProvider provider = new OAuthServiceProvider(
- "request", "authorize", "access");
-
- OAuthStore.ProviderInfo info = new BasicOAuthStore.ProviderInfo();
-
- info.setHttpMethod(OAuthStore.HttpMethod.GET);
- info.setSignatureType(OAuthStore.SignatureType.HMAC_SHA1);
- info.setProvider(provider);
- info.setParamLocation(OAuthStore.OAuthParamLocation.AUTH_HEADER);
-
- ////////////////////////////////////////////////////////////////////////////
- // first, the case where we don't have a consumer key/secret
-
- control.checkOrder(false);
-
- expect(mockConsumerInfos.get(eq(provKey))).andReturn(null).once();
- expect(mockTokens.get(tokenKey)).andReturn(tokenInfo);
-
- control.replay();
-
- OAuthStore.AccessorInfo accessorInfo =
- withDefaultStore.getOAuthAccessor(tokenKey, info);
-
- control.verify();
-
- OAuthAccessor accessor = accessorInfo.getAccessor();
-
- assertSame(info.getHttpMethod(), accessorInfo.getHttpMethod());
- assertSame(OAuthStore.OAuthParamLocation.AUTH_HEADER,
- accessorInfo.getParamLocation());
-
- assertEquals("accesstoken", accessor.accessToken);
- assertEquals("tokensecret", accessor.tokenSecret);
- assertEquals(defaultKey, accessor.consumer.consumerKey);
- assertNull(accessor.consumer.consumerSecret);
- assertEquals(defaultSecret, accessor.consumer
- .getProperty(RSA_SHA1.PRIVATE_KEY));
- assertEquals("access", accessor.consumer.serviceProvider.accessTokenURL);
- assertEquals("request", accessor.consumer.serviceProvider.requestTokenURL);
- assertEquals("authorize",
- accessor.consumer.serviceProvider.userAuthorizationURL);
-
- // now for the one that doesn't have default keys set
- control.reset();
- control.checkOrder(false);
-
- expect(mockConsumerInfos.get(eq(provKey))).andReturn(null).once();
- expect(mockTokens.get(tokenKey)).andStubReturn(tokenInfo);
-
- control.replay();
-
- try {
- accessorInfo = noDefaultStore.getOAuthAccessor(tokenKey, info);
- fail("expected exception, but didn't get it");
- } catch (OAuthNoDataException e) {
- // this is expected
- }
-
- control.verify();
-
- ////////////////////////////////////////////////////////////////////////////
- // now the case where we have negotiated an HMAC consumer secret
-
- OAuthStore.ConsumerKeyAndSecret kas =
- new OAuthStore.ConsumerKeyAndSecret("negotiatedkey",
- "negotiatedsecret",
- OAuthStore.KeyType.HMAC_SYMMETRIC);
-
- info.setParamLocation(OAuthStore.OAuthParamLocation.POST_BODY);
-
- control.reset();
- control.checkOrder(false);
-
- expect(mockConsumerInfos.get(eq(provKey))).andReturn(kas).once();
- expect(mockTokens.get(tokenKey)).andReturn(tokenInfo);
-
- control.replay();
-
- accessorInfo = noDefaultStore.getOAuthAccessor(tokenKey, info);
-
- control.verify();
-
- assertSame(OAuthStore.OAuthParamLocation.POST_BODY,
- accessorInfo.getParamLocation());
-
- accessor = accessorInfo.getAccessor();
-
- assertEquals("accesstoken", accessor.accessToken);
- assertEquals("tokensecret", accessor.tokenSecret);
- assertEquals("negotiatedkey", accessor.consumer.consumerKey);
- assertEquals("negotiatedsecret", accessor.consumer.consumerSecret);
- assertEquals("access", accessor.consumer.serviceProvider.accessTokenURL);
- assertEquals("request", accessor.consumer.serviceProvider.requestTokenURL);
- assertEquals("authorize",
- accessor.consumer.serviceProvider.userAuthorizationURL);
-
- // the store with fallback keys should do the same thing
-
- control.reset();
- control.checkOrder(false);
-
- expect(mockConsumerInfos.get(eq(provKey))).andReturn(kas).once();
- expect(mockTokens.get(tokenKey)).andReturn(tokenInfo);
-
- control.replay();
-
- accessorInfo = withDefaultStore.getOAuthAccessor(tokenKey, info);
-
- control.verify();
-
- accessor = accessorInfo.getAccessor();
-
- assertEquals("accesstoken", accessor.accessToken);
- assertEquals("tokensecret", accessor.tokenSecret);
- assertEquals("negotiatedkey", accessor.consumer.consumerKey);
- assertEquals("negotiatedsecret", accessor.consumer.consumerSecret);
- assertEquals("access", accessor.consumer.serviceProvider.accessTokenURL);
- assertEquals("request", accessor.consumer.serviceProvider.requestTokenURL);
- assertEquals("authorize",
- accessor.consumer.serviceProvider.userAuthorizationURL);
-
- ////////////////////////////////////////////////////////////////////////////
- // now the case where we have negotiated an RSA consumer key
-
- kas = new OAuthStore.ConsumerKeyAndSecret("negotiatedkey",
- "negotiatedsecret",
- OAuthStore.KeyType.RSA_PRIVATE);
-
- control.reset();
- control.checkOrder(false);
-
- expect(mockConsumerInfos.get(eq(provKey))).andReturn(kas).once();
- expect(mockTokens.get(tokenKey)).andReturn(tokenInfo);
-
- control.replay();
-
- accessorInfo = noDefaultStore.getOAuthAccessor(tokenKey, info);
-
- control.verify();
-
- accessor = accessorInfo.getAccessor();
-
- assertEquals("accesstoken", accessor.accessToken);
- assertEquals("tokensecret", accessor.tokenSecret);
- assertEquals("negotiatedkey", accessor.consumer.consumerKey);
- assertNull(accessor.consumer.consumerSecret);
- assertEquals("negotiatedsecret",
- accessor.consumer.getProperty(RSA_SHA1.PRIVATE_KEY));
- assertEquals("access", accessor.consumer.serviceProvider.accessTokenURL);
- assertEquals("request", accessor.consumer.serviceProvider.requestTokenURL);
- assertEquals("authorize",
- accessor.consumer.serviceProvider.userAuthorizationURL);
-
- // store with fallback keys should do the same
-
- control.reset();
- control.checkOrder(false);
-
- expect(mockConsumerInfos.get(eq(provKey))).andReturn(kas).once();
- expect(mockTokens.get(tokenKey)).andReturn(tokenInfo);
-
- control.replay();
-
- accessorInfo = noDefaultStore.getOAuthAccessor(tokenKey, info);
-
- control.verify();
-
- accessor = accessorInfo.getAccessor();
-
- assertEquals("accesstoken", accessor.accessToken);
- assertEquals("tokensecret", accessor.tokenSecret);
- assertEquals("negotiatedkey", accessor.consumer.consumerKey);
- assertNull(accessor.consumer.consumerSecret);
- assertEquals("negotiatedsecret",
- accessor.consumer.getProperty(RSA_SHA1.PRIVATE_KEY));
- assertEquals("access", accessor.consumer.serviceProvider.accessTokenURL);
- assertEquals("request", accessor.consumer.serviceProvider.requestTokenURL);
- assertEquals("authorize",
- accessor.consumer.serviceProvider.userAuthorizationURL);
-
- ////////////////////////////////////////////////////////////////////////////
- // now, test some error conditions: no token found
-
- control.reset();
- control.checkOrder(false);
-
- expect(mockConsumerInfos.get(eq(provKey))).andStubReturn(kas);
- expect(mockTokens.get(tokenKey)).andReturn(null);
-
- control.replay();
-
- accessorInfo = noDefaultStore.getOAuthAccessor(tokenKey, info);
-
- control.verify();
-
- assertNull(accessorInfo.getAccessor().accessToken);
- assertNull(accessorInfo.getAccessor().requestToken);
-
- // same with the store with fallback keys
-
- control.reset();
- control.checkOrder(false);
-
- expect(mockConsumerInfos.get(eq(provKey))).andStubReturn(kas);
- expect(mockTokens.get(tokenKey)).andReturn(null);
-
- control.replay();
-
- accessorInfo = withDefaultStore.getOAuthAccessor(tokenKey, info);
- assertNull(accessorInfo.getAccessor().accessToken);
- assertNull(accessorInfo.getAccessor().requestToken);
-
- control.verify();
-
+
+ @Test
+ public void testInit() throws Exception {
+ FakeGadgetToken t = new FakeGadgetToken();
+ t.setAppUrl("http://localhost:8080/gadgets/files/samplecontainer/examples/oauth.xml");
+ OAuthServiceProvider provider = new OAuthServiceProvider("req", "authorize", "access");
+ ConsumerInfo consumerInfo = store.getConsumerKeyAndSecret(t, "", provider);
+ OAuthConsumer consumer = consumerInfo.getConsumer();
+ assertEquals("gadgetConsumer", consumer.consumerKey);
+ assertEquals("gadgetSecret", consumer.consumerSecret);
+ assertEquals("HMAC-SHA1", consumer.getProperty("oauth_signature_method"));
+ assertEquals(provider, consumer.serviceProvider);
+ assertNull(consumerInfo.getKeyName());
+
+ t.setAppUrl("http://rsagadget/test.xml");
+ consumerInfo = store.getConsumerKeyAndSecret(t, "", provider);
+ consumer = consumerInfo.getConsumer();
+ assertEquals("rsaconsumer", consumer.consumerKey);
+ assertNull(consumer.consumerSecret);
+ assertEquals("RSA-SHA1", consumer.getProperty("oauth_signature_method"));
+ assertEquals(provider, consumer.serviceProvider);
+ assertEquals("rsaprivate", consumer.getProperty(RSA_SHA1.PRIVATE_KEY));
+ assertNull(consumerInfo.getKeyName());
}
-
- public void testSetOAuthConsumerKeyAndSecret() throws Exception {
- OAuthStore.ProviderKey provKey = new OAuthStore.ProviderKey();
- provKey.setGadgetUri("http://foo.bar.com/gadget.xml");
- provKey.setServiceName("testservice");
-
- OAuthStore.ConsumerKeyAndSecret kas =
- new OAuthStore.ConsumerKeyAndSecret("consumerkey",
- "consumersecret",
- OAuthStore.KeyType.HMAC_SYMMETRIC);
-
- OAuthServiceProvider provider = new OAuthServiceProvider(
- "request", "authorize", "access");
-
- OAuthStore.ProviderInfo info = new OAuthStore.ProviderInfo();
- info.setHttpMethod(OAuthStore.HttpMethod.GET);
- info.setSignatureType(OAuthStore.SignatureType.HMAC_SHA1);
- info.setProvider(provider);
-
- expect(mockConsumerInfos.put(provKey, kas)).andReturn(kas).once();
-
- control.replay();
-
- noDefaultStore.setOAuthConsumerKeyAndSecret(provKey, kas);
-
- control.verify();
-
+
+ @Test
+ public void testGetAndSetAndRemoveToken() {
+ FakeGadgetToken t = new FakeGadgetToken();
+ ConsumerInfo consumer = new ConsumerInfo(null, null);
+ t.setAppUrl("http://localhost:8080/gadgets/files/samplecontainer/examples/oauth.xml");
+ t.setViewerId("viewer-one");
+ assertNull(store.getTokenInfo(t, consumer, "", ""));
+
+ TokenInfo info = new TokenInfo("token", "secret");
+ store.setTokenInfo(t, consumer, "service", "token", info);
+
+ info = store.getTokenInfo(t, consumer, "service", "token");
+ assertEquals("token", info.getAccessToken());
+ assertEquals("secret", info.getTokenSecret());
+
+ FakeGadgetToken t2 = new FakeGadgetToken();
+ t2.setAppUrl("http://localhost:8080/gadgets/files/samplecontainer/examples/oauth.xml");
+ t2.setViewerId("viewer-two");
+ assertNull(store.getTokenInfo(t2, consumer, "service", "token"));
+
+ store.removeToken(t, consumer, "service", "token");
+ assertNull(store.getTokenInfo(t, consumer, "service", "token"));
}
+
+ @Test
+ public void testDefaultKey() throws Exception {
+ FakeGadgetToken t = new FakeGadgetToken();
+ t.setAppUrl("http://localhost:8080/not-in-store.xml");
+ OAuthServiceProvider provider = new OAuthServiceProvider("req", "authorize", "access");
- public void testSetTokenAndSecret() throws Exception {
- OAuthStore.TokenKey tokenKey = new OAuthStore.TokenKey();
- tokenKey.setGadgetUri("http://foo.bar.com/gadget.xml");
- tokenKey.setServiceName("testservice");
- tokenKey.setModuleId(9843243278L);
- tokenKey.setTokenName("testtoken");
- tokenKey.setUserId("test user");
-
- OAuthStore.TokenInfo tokenInfo =
- new OAuthStore.TokenInfo(SecurityTokenDecoder.SECURITY_TOKEN_NAME, "secret");
-
-
- expect(mockTokens.put(tokenKey, tokenInfo)).andReturn(null);
-
- control.replay();
-
- noDefaultStore.setTokenAndSecret(tokenKey, tokenInfo);
-
- control.verify();
+ try {
+ store.getConsumerKeyAndSecret(t, "", provider);
+ fail();
+ } catch (GadgetException e) {
+ // good
+ }
+
+ BasicOAuthStoreConsumerKeyAndSecret cks = new BasicOAuthStoreConsumerKeyAndSecret(
+ "somekey", "default", KeyType.RSA_PRIVATE, "keyname");
+ store.setDefaultKey(cks);
+
+ ConsumerInfo consumer = store.getConsumerKeyAndSecret(t, "", provider);
+ assertEquals("somekey", consumer.getConsumer().consumerKey);
+ assertNull(consumer.getConsumer().consumerSecret);
+ assertEquals("RSA-SHA1", consumer.getConsumer().getProperty("oauth_signature_method"));
+ assertEquals("default", consumer.getConsumer().getProperty(RSA_SHA1.PRIVATE_KEY));
+ assertEquals(provider, consumer.getConsumer().serviceProvider);
+ assertEquals("keyname", consumer.getKeyName());
}
}
Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/FakeOAuthServiceProvider.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/FakeOAuthServiceProvider.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/FakeOAuthServiceProvider.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/FakeOAuthServiceProvider.java Tue Sep 9 18:50:41 2008
@@ -24,6 +24,7 @@
import net.oauth.OAuthServiceProvider;
import net.oauth.OAuthValidator;
import net.oauth.SimpleOAuthValidator;
+import net.oauth.signature.RSA_SHA1;
import org.apache.shindig.common.crypto.Crypto;
import org.apache.shindig.gadgets.GadgetException;
@@ -31,7 +32,7 @@
import org.apache.shindig.gadgets.http.HttpRequest;
import org.apache.shindig.gadgets.http.HttpResponse;
import org.apache.shindig.gadgets.http.HttpResponseBuilder;
-import org.apache.shindig.gadgets.oauth.OAuthStore.OAuthParamLocation;
+import org.apache.shindig.gadgets.oauth.AccessorInfo.OAuthParamLocation;
import java.io.IOException;
import java.util.ArrayList;
@@ -59,6 +60,9 @@
public final static String CONSUMER_KEY = "consumer";
public final static String CONSUMER_SECRET = "secret";
+
+ public final static String SIGNED_FETCH_CONSUMER_KEY = "signedfetch";
+
private static class TokenState {
String tokenSecret;
@@ -112,7 +116,8 @@
*/
private final HashMap<String, TokenState> tokenState;
private final OAuthValidator validator;
- private final OAuthConsumer consumer;
+ private final OAuthConsumer signedFetchConsumer;
+ private final OAuthConsumer oauthConsumer;
private boolean throttled;
private boolean vagueErrors;
@@ -128,14 +133,26 @@
public FakeOAuthServiceProvider() {
OAuthServiceProvider provider = new OAuthServiceProvider(
REQUEST_TOKEN_URL, APPROVAL_URL, ACCESS_TOKEN_URL);
- consumer = new OAuthConsumer(
- null, CONSUMER_KEY, CONSUMER_SECRET, provider);
+
+ signedFetchConsumer = new OAuthConsumer(null, null, null, null);
+ signedFetchConsumer.setProperty(RSA_SHA1.X509_CERTIFICATE, OAuthFetcherTest.CERTIFICATE_TEXT);
+
+ oauthConsumer = new OAuthConsumer(null, CONSUMER_KEY, CONSUMER_SECRET, provider);
+
tokenState = new HashMap<String, TokenState>();
validator = new SimpleOAuthValidator();
vagueErrors = false;
validParamLocations = new HashSet<OAuthParamLocation>();
validParamLocations.add(OAuthParamLocation.URI_QUERY);
}
+
+ public OAuthConsumer getConsumer(String consumerKey) {
+ if (consumerKey.equals("signedfetch")) {
+ return signedFetchConsumer;
+ } else {
+ return oauthConsumer;
+ }
+ }
public void setVagueErrors(boolean vagueErrors) {
this.vagueErrors = vagueErrors;
@@ -183,7 +200,12 @@
throws Exception {
OAuthMessage message = parseMessage(request).message;
String requestConsumer = message.getParameter(OAuth.OAUTH_CONSUMER_KEY);
- if (!CONSUMER_KEY.equals(requestConsumer)) {
+ OAuthConsumer consumer;
+ if (CONSUMER_KEY.equals(requestConsumer)) {
+ consumer = oauthConsumer;
+ } else if (SIGNED_FETCH_CONSUMER_KEY.equals(requestConsumer)) {
+ consumer = signedFetchConsumer;
+ } else {
return makeOAuthProblemReport(
"consumer_key_unknown", "invalid consumer: " + requestConsumer);
}
@@ -238,7 +260,7 @@
}
}
}
-
+
// Parse authorization header
if (validParamLocations.contains(OAuthParamLocation.AUTH_HEADER)) {
String aznHeader = request.getHeader("Authorization");
@@ -253,15 +275,21 @@
}
// Parse body
- if (validParamLocations.contains(OAuthParamLocation.POST_BODY)) {
- String body = request.getPostBodyAsString();
- if (request.getMethod().equals("POST")) {
- String type = request.getHeader("Content-Type");
- if (!"application/x-www-form-urlencoded".equals(type)) {
- throw new RuntimeException("Wrong content-type header: " + type);
- }
- info.body = body;
- params.addAll(OAuth.decodeForm(request.getPostBodyAsString()));
+ String body = request.getPostBodyAsString();
+ if (request.getMethod().equals("POST")) {
+ String type = request.getHeader("Content-Type");
+ if (!"application/x-www-form-urlencoded".equals(type)) {
+ throw new RuntimeException("Wrong content-type header: " + type);
+ }
+ info.body = body;
+ params.addAll(OAuth.decodeForm(request.getPostBodyAsString()));
+ }
+
+ // If we're not configured to pass oauth parameters in the post body, double check
+ // that they didn't end up there.
+ if (!validParamLocations.contains(OAuthParamLocation.POST_BODY)) {
+ if (body.contains("oauth_")) {
+ throw new RuntimeException("Found unexpected post body data" + body);
}
}
@@ -359,7 +387,7 @@
public TokenPair getPreapprovedToken(String userData) {
String requestToken = Crypto.getRandomString(16);
String requestTokenSecret = Crypto.getRandomString(16);
- TokenState state = new TokenState(requestTokenSecret, consumer);
+ TokenState state = new TokenState(requestTokenSecret, oauthConsumer);
state.setState(TokenState.State.APPROVED);
state.setUserData(userData);
tokenState.put(requestToken, state);
@@ -391,7 +419,7 @@
if (state.getState() != TokenState.State.APPROVED) {
throw new Exception("Token not approved");
}
- OAuthAccessor accessor = new OAuthAccessor(consumer);
+ OAuthAccessor accessor = new OAuthAccessor(oauthConsumer);
accessor.requestToken = requestToken;
accessor.tokenSecret = state.tokenSecret;
message.validateMessage(accessor, validator);
@@ -409,27 +437,50 @@
private HttpResponse handleResourceUrl(HttpRequest request)
throws Exception {
MessageInfo info = parseMessage(request);
- String accessToken = info.message.getParameter("oauth_token");
- TokenState state = tokenState.get(accessToken);
- if (throttled) {
- return makeOAuthProblemReport(
- "consumer_key_refused", "exceeded quota");
- }
- if (state == null) {
- return makeOAuthProblemReport(
- "token_rejected", "Access token unknown");
- }
- if (state.getState() != TokenState.State.APPROVED) {
- return makeOAuthProblemReport(
- "token_revoked", "User revoked permissions");
+ String consumerId = info.message.getParameter("oauth_consumer_key");
+ OAuthConsumer consumer;
+ if (CONSUMER_KEY.equals(consumerId)) {
+ consumer = oauthConsumer;
+ } else if ("signedfetch".equals(consumerId)) {
+ consumer = signedFetchConsumer;
+ } else if ("container.com".equals(consumerId)) {
+ consumer = signedFetchConsumer;
+ } else {
+ return makeOAuthProblemReport("parameter_missing", "oauth_consumer_key not found");
}
OAuthAccessor accessor = new OAuthAccessor(consumer);
- accessor.accessToken = accessToken;
- accessor.tokenSecret = state.getSecret();
+ String responseBody = null;
+ if (consumer == oauthConsumer) {
+ // for OAuth, check the access token. We skip this for signed fetch
+ String accessToken = info.message.getParameter("oauth_token");
+ TokenState state = tokenState.get(accessToken);
+ if (throttled) {
+ return makeOAuthProblemReport(
+ "consumer_key_refused", "exceeded quota");
+ }
+ if (state == null) {
+ return makeOAuthProblemReport(
+ "token_rejected", "Access token unknown");
+ }
+ if (state.getState() != TokenState.State.APPROVED) {
+ return makeOAuthProblemReport(
+ "token_revoked", "User revoked permissions");
+ }
+ accessor.accessToken = accessToken;
+ accessor.tokenSecret = state.getSecret();
+ responseBody = "User data is " + state.getUserData();
+ } else {
+ // For signed fetch, just echo back the query parameters in the body
+ responseBody = request.getUri().getQuery();
+ }
+
+ // Check the signature
info.message.validateMessage(accessor, validator);
+
+ // Send back a response
HttpResponseBuilder resp = new HttpResponseBuilder()
.setHttpStatusCode(HttpResponse.SC_OK)
- .setResponseString("User data is " + state.getUserData());
+ .setResponseString(responseBody);
if (info.aznHeader != null) {
resp.setHeader(AUTHZ_ECHO_HEADER, info.aznHeader);
}