Author: etnu
Date: Fri May 2 18:08:37 2008
New Revision: 652963
URL: http://svn.apache.org/viewvc?rev=652963&view=rev
Log:
Applied SHINDIG-216 from Brian Eaton and Dirk Balfanz.
Added:
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RequestSigningException.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/FakeOAuthServiceProvider.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/OAuthFetcherTest.java
Modified:
incubator/shindig/trunk/config/container.js
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetcher.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthRequestParams.java
Modified: incubator/shindig/trunk/config/container.js
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/config/container.js?rev=652963&r1=652962&r2=652963&view=diff
==============================================================================
--- incubator/shindig/trunk/config/container.js (original)
+++ incubator/shindig/trunk/config/container.js Fri May 2 18:08:37 2008
@@ -57,7 +57,7 @@
// See individual feature.xml files for configuration details.
"gadgets.features" : {
"core.io" : {
- // Note: /proxy is an open proxy. Be careful how you explose this!
+ // Note: /proxy is an open proxy. Be careful how you explose this!
"proxyUrl" : "proxy?url=%url%",
"jsonProxyUrl" : "proxy?output=js"
},
@@ -72,8 +72,8 @@
}
},
"rpc" : {
- // Path to the relay file. Automatically appended to the parent
- // parameter if it passes input validation and is not null.
+ // Path to the relay file. Automatically appended to the parent
+ /// parameter if it passes input validation and is not null.
// This should never be on the same host in a production environment!
// Only use this for TESTING!
"parentRelayUrl" : "/gadgets/files/container/rpc_relay.html",
@@ -85,12 +85,12 @@
// Skin defaults
"skins" : {
"properties" : {
- "BG_COLOR": "",
- "BG_IMAGE": "",
- "BG_POSITION": "",
- "BG_REPEAT": "",
- "FONT_COLOR": "",
- "ANCHOR_COLOR": ""
+ "BG_COLOR": "",
+ "BG_IMAGE": "",
+ "BG_POSITION": "",
+ "BG_REPEAT": "",
+ "FONT_COLOR": "",
+ "ANCHOR_COLOR": ""
}
},
"opensocial-0.7" : {
Added:
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RequestSigningException.java
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RequestSigningException.java?rev=652963&view=auto
==============================================================================
---
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RequestSigningException.java
(added)
+++
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RequestSigningException.java
Fri May 2 18:08:37 2008
@@ -0,0 +1,36 @@
+/*
+ * 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;
+
+/**
+ * Exception thrown during request signing.
+ */
+public class RequestSigningException extends GadgetException {
+
+ public RequestSigningException(Throwable cause) {
+ super(GadgetException.Code.REQUEST_SIGNING_FAILURE, cause);
+ }
+
+ public RequestSigningException(String msg, Throwable cause) {
+ super(GadgetException.Code.REQUEST_SIGNING_FAILURE, msg, cause);
+ }
+
+ public RequestSigningException(String msg) {
+ super(GadgetException.Code.REQUEST_SIGNING_FAILURE, msg);
+ }
+}
Modified:
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java?rev=652963&r1=652962&r2=652963&view=diff
==============================================================================
---
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java
(original)
+++
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java
Fri May 2 18:08:37 2008
@@ -237,10 +237,9 @@
RemoteContent results) {
try {
JSONObject resp = new JSONObject();
- if (results != null) {
- resp.put("body", results.getResponseAsString());
- resp.put("rc", results.getHttpStatusCode());
- }
+
+ resp.put("body", results.getResponseAsString());
+ resp.put("rc", results.getHttpStatusCode());
// Merge in additional response data
for (Map.Entry<String, String> entry : results.getMetadata().entrySet())
{
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=652963&r1=652962&r2=652963&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
Fri May 2 18:08:37 2008
@@ -210,7 +210,7 @@
buildAznUrl();
// break out of the content fetching chain, we need permission from
// the user to do this
- return null;
+ return buildOAuthApprovalResponse();
} else if (needAccessToken()) {
// This is section 6.3 of the OAuth spec
checkCanApprove();
@@ -438,6 +438,21 @@
aznUrl = azn.toString();
}
+ private RemoteContent buildOAuthApprovalResponse() {
+ RemoteContent content = new RemoteContent(0, null, null);
+ addResponseMetadata(content);
+ return content;
+ }
+
+ private void addResponseMetadata(RemoteContent content) {
+ if (newClientState != null) {
+ content.getMetadata().put(CLIENT_STATE, newClientState);
+ }
+ if (aznUrl != null) {
+ content.getMetadata().put(APPROVAL_URL, aznUrl);
+ }
+ }
+
/**
* Do we need to exchange a request token for an access token?
*/
@@ -523,12 +538,7 @@
realRequest.getOptions()));
// Track metadata on the response
- if (newClientState != null) {
- content.getMetadata().put(CLIENT_STATE, newClientState);
- }
- if (aznUrl != null) {
- content.getMetadata().put(APPROVAL_URL, aznUrl);
- }
+ addResponseMetadata(content);
return content;
} catch (UnsupportedEncodingException e) {
throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, e);
Modified:
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthRequestParams.java
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthRequestParams.java?rev=652963&r1=652962&r2=652963&view=diff
==============================================================================
---
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthRequestParams.java
(original)
+++
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthRequestParams.java
Fri May 2 18:08:37 2008
@@ -28,9 +28,9 @@
public static final String TOKEN_PARAM = "oauthToken";
public static final String CLIENT_STATE_PARAM = "oauthState";
- private final String serviceName;
- private final String tokenName;
- private final String origClientState;
+ protected final String serviceName;
+ protected final String tokenName;
+ protected final String origClientState;
public OAuthRequestParams(HttpServletRequest request) {
serviceName = request.getParameter(SERVICE_PARAM);
@@ -38,6 +38,14 @@
origClientState = request.getParameter(CLIENT_STATE_PARAM);
}
+ // Really only use this for testing, please
+ public OAuthRequestParams(String serviceName, String tokenName,
+ String origClientState) {
+ this.serviceName = serviceName;
+ this.tokenName = tokenName;
+ this.origClientState = origClientState;
+ }
+
public String getServiceName() {
return serviceName;
}
Added:
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=652963&view=auto
==============================================================================
---
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/FakeOAuthServiceProvider.java
(added)
+++
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/FakeOAuthServiceProvider.java
Fri May 2 18:08:37 2008
@@ -0,0 +1,270 @@
+/*
+ * 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.oauth;
+
+import net.oauth.OAuth;
+import net.oauth.OAuthAccessor;
+import net.oauth.OAuthConsumer;
+import net.oauth.OAuthMessage;
+import net.oauth.OAuthServiceProvider;
+import net.oauth.OAuthValidator;
+import net.oauth.SimpleOAuthValidator;
+
+import org.apache.shindig.gadgets.ContentFetcher;
+import org.apache.shindig.gadgets.GadgetException;
+import org.apache.shindig.gadgets.RemoteContent;
+import org.apache.shindig.gadgets.RemoteContentRequest;
+import org.apache.shindig.util.Crypto;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class FakeOAuthServiceProvider implements ContentFetcher {
+
+ public final static String SP_HOST = "http://www.example.com";
+
+ public final static String REQUEST_TOKEN_URL =
+ SP_HOST + "/request?param=foo";
+ public final static String ACCESS_TOKEN_URL =
+ SP_HOST + "/access";
+ public final static String APPROVAL_URL =
+ SP_HOST + "/authorize";
+ public final static String RESOURCE_URL =
+ SP_HOST + "/data";
+
+ public final static String CONSUMER_KEY = "consumer";
+ public final static String CONSUMER_SECRET = "secret";
+
+ private static class TokenState {
+ String tokenSecret;
+ OAuthConsumer consumer;
+ State state;
+ String userData;
+
+ enum State {
+ PENDING,
+ APPROVED,
+ }
+
+ public TokenState(String tokenSecret, OAuthConsumer consumer) {
+ this.tokenSecret = tokenSecret;
+ this.consumer = consumer;
+ this.state = State.PENDING;
+ this.userData = null;
+ }
+
+ public static TokenState makeAccessTokenState(String tokenSecret,
+ OAuthConsumer consumer) {
+ TokenState s = new TokenState(tokenSecret, consumer);
+ s.setState(State.APPROVED);
+ return s;
+ }
+
+ public void setState(State state) {
+ this.state = state;
+ }
+
+ public State getState() {
+ return state;
+ }
+
+ public String getSecret() {
+ return tokenSecret;
+ }
+
+ public void setUserData(String userData) {
+ this.userData = userData;
+ }
+
+ public String getUserData() {
+ return userData;
+ }
+ }
+
+ /**
+ * Table of OAuth access tokens
+ */
+ private final HashMap<String, TokenState> tokenState;
+ private final OAuthValidator validator;
+ private final OAuthConsumer consumer;
+
+ public FakeOAuthServiceProvider() {
+ OAuthServiceProvider provider = new OAuthServiceProvider(
+ REQUEST_TOKEN_URL, APPROVAL_URL, ACCESS_TOKEN_URL);
+ consumer = new OAuthConsumer(
+ null, CONSUMER_KEY, CONSUMER_SECRET, provider);
+ tokenState = new HashMap<String, TokenState>();
+ validator = new SimpleOAuthValidator();
+ }
+
+ public RemoteContent fetch(RemoteContentRequest request)
+ throws GadgetException {
+ String url = request.getUri().toASCIIString();
+ try {
+ if (url.startsWith(REQUEST_TOKEN_URL)) {
+ return handleRequestTokenUrl(request);
+ } else if (url.startsWith(ACCESS_TOKEN_URL)) {
+ return handleAccessTokenUrl(request);
+ } else if (url.startsWith(RESOURCE_URL)){
+ return handleResourceUrl(request);
+ }
+ } catch (Exception e) {
+ throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR,
+ "Problem with request for URL " + url, e);
+ }
+ throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR,
+ "Unexpected request for " + url);
+ }
+
+ private RemoteContent handleRequestTokenUrl(RemoteContentRequest request)
+ throws Exception {
+ OAuthMessage message = parseMessage(request);
+ OAuthAccessor accessor = new OAuthAccessor(consumer);
+ message.validateMessage(accessor, validator);
+ String requestToken = Crypto.getRandomString(16);
+ String requestTokenSecret = Crypto.getRandomString(16);
+ tokenState.put(
+ requestToken, new TokenState(requestToken, accessor.consumer));
+ String resp = OAuth.formEncode(OAuth.newList(
+ "oauth_token", requestToken,
+ "oauth_token_secret", requestToken));
+ return new RemoteContent(resp);
+ }
+
+ // Loosely based off net.oauth.OAuthServlet, and even more loosely related
+ // to the OAuth specification
+ private OAuthMessage parseMessage(RemoteContentRequest request) {
+ String method = request.getMethod();
+ if (!method.equals("GET")) {
+ throw new RuntimeException("Only GET supported for now");
+ }
+ ParsedUrl url = new ParsedUrl(request.getUri().toASCIIString());
+ List<OAuth.Parameter> params = new ArrayList<OAuth.Parameter>();
+ params.addAll(url.getParsedQuery());
+ String aznHeader = request.getHeader("Authorization");
+ if (aznHeader != null) {
+ for (OAuth.Parameter p : OAuthMessage.decodeAuthorization(aznHeader)) {
+ if (!p.getKey().equalsIgnoreCase("realm")) {
+ params.add(p);
+ }
+ }
+ }
+ return new OAuthMessage(method, url.getLocation(), params);
+ }
+
+ /**
+ * Utility class for parsing OAuth URLs.
+ */
+ private static class ParsedUrl {
+ String location = null;
+ String query = null;
+ List<OAuth.Parameter> decodedQuery = null;
+
+ public ParsedUrl(String url) {
+ int queryIndex = url.indexOf('?');
+ if (queryIndex != -1) {
+ query = url.substring(queryIndex+1, url.length());
+ location = url.substring(0, queryIndex);
+ } else {
+ location = url;
+ }
+ }
+
+ public String getLocation() {
+ return location;
+ }
+
+ public String getRawQuery() {
+ return query;
+ }
+
+ public List<OAuth.Parameter> getParsedQuery() {
+ if (decodedQuery == null) {
+ if (query != null) {
+ decodedQuery = OAuth.decodeForm(query);
+ } else {
+ decodedQuery = new ArrayList<OAuth.Parameter>();
+ }
+ }
+ return decodedQuery;
+ }
+
+ public String getQueryParam(String name) {
+ for (OAuth.Parameter p : getParsedQuery()) {
+ if (p.getKey().equals(name)) {
+ return p.getValue();
+ }
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Used to fake a browser visit to approve a token.
+ * @param url
+ * @throws Exception
+ */
+ public void browserVisit(String url) throws Exception {
+ ParsedUrl parsed = new ParsedUrl(url);
+ String requestToken = parsed.getQueryParam("oauth_token");
+ TokenState state = tokenState.get(requestToken);
+ state.setState(TokenState.State.APPROVED);
+ // Not part of the OAuth spec, just a handy thing for testing.
+ state.setUserData(parsed.getQueryParam("user_data"));
+ }
+
+ private RemoteContent handleAccessTokenUrl(RemoteContentRequest request)
+ throws Exception {
+ OAuthMessage message = parseMessage(request);
+ String requestToken = message.getParameter("oauth_token");
+ TokenState state = tokenState.get(requestToken);
+ if (state.getState() != TokenState.State.APPROVED) {
+ throw new Exception("Token not approved");
+ }
+ OAuthAccessor accessor = new OAuthAccessor(consumer);
+ accessor.requestToken = requestToken;
+ accessor.tokenSecret = state.tokenSecret;
+ message.validateMessage(accessor, validator);
+ String accessToken = Crypto.getRandomString(16);
+ String accessTokenSecret = Crypto.getRandomString(16);
+ state.tokenSecret = accessTokenSecret;
+ tokenState.put(accessToken, state);
+ tokenState.remove(requestToken);
+ String resp = OAuth.formEncode(OAuth.newList(
+ "oauth_token", accessToken,
+ "oauth_token_secret", accessTokenSecret));
+ return new RemoteContent(resp);
+ }
+
+ private RemoteContent handleResourceUrl(RemoteContentRequest request)
+ throws Exception {
+ OAuthMessage message = parseMessage(request);
+ String accessToken = message.getParameter("oauth_token");
+ TokenState state = tokenState.get(accessToken);
+ if (state.getState() != TokenState.State.APPROVED) {
+ throw new Exception("Token not approved");
+ }
+ OAuthAccessor accessor = new OAuthAccessor(consumer);
+ accessor.accessToken = accessToken;
+ accessor.tokenSecret = state.getSecret();
+ message.validateMessage(accessor, validator);
+ return new RemoteContent("User data is " + state.getUserData());
+ }
+
+}
Added:
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/OAuthFetcherTest.java
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/OAuthFetcherTest.java?rev=652963&view=auto
==============================================================================
---
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/OAuthFetcherTest.java
(added)
+++
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/OAuthFetcherTest.java
Fri May 2 18:08:37 2008
@@ -0,0 +1,170 @@
+/*
+ * 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.oauth;
+
+import junit.framework.TestCase;
+
+import net.oauth.OAuthServiceProvider;
+
+import org.apache.shindig.gadgets.BasicGadgetToken;
+import org.apache.shindig.gadgets.ContentFetcher;
+import org.apache.shindig.gadgets.GadgetException;
+import org.apache.shindig.gadgets.GadgetToken;
+import org.apache.shindig.gadgets.RemoteContent;
+import org.apache.shindig.gadgets.RemoteContentRequest;
+import org.apache.shindig.gadgets.oauth.OAuthStore.HttpMethod;
+import org.apache.shindig.gadgets.oauth.OAuthStore.OAuthParamLocation;
+import org.apache.shindig.gadgets.oauth.OAuthStore.SignatureType;
+import org.apache.shindig.util.BasicBlobCrypter;
+import org.apache.shindig.util.BlobCrypter;
+import org.apache.shindig.util.BlobCrypterException;
+
+import java.net.URI;
+
+/**
+ * Primitive test of the main code paths in OAuthFetcher.
+ *
+ * This is a fairly crappy regression test, so if you find yourself wanting
+ * to modify this code, you should probably write additional test cases first.
+ */
+public class OAuthFetcherTest extends TestCase {
+
+ private GadgetOAuthTokenStore tokenStore;
+ private BlobCrypter blobCrypter;
+ private FakeOAuthServiceProvider serviceProvider;
+
+ public static final String SERVICE_NAME = "test";
+ public static final String GADGET_URL = "http://www.example.com/gadget.xml";
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ serviceProvider = new FakeOAuthServiceProvider();
+ tokenStore = getOAuthStore();
+ blobCrypter = new BasicBlobCrypter("abcdefghijklmnop".getBytes());
+ }
+
+ /**
+ * Builds a nicely populated fake token store.
+ */
+ public static GadgetOAuthTokenStore getOAuthStore() {
+ BasicOAuthStore base = new BasicOAuthStore();
+
+ OAuthStore.ProviderKey providerKey = new OAuthStore.ProviderKey();
+ providerKey.setGadgetUri(GADGET_URL);
+ providerKey.setServiceName(SERVICE_NAME);
+
+ OAuthStore.ProviderInfo providerInfo = new OAuthStore.ProviderInfo();
+ OAuthServiceProvider provider = new OAuthServiceProvider(
+ FakeOAuthServiceProvider.REQUEST_TOKEN_URL,
+ FakeOAuthServiceProvider.APPROVAL_URL,
+ FakeOAuthServiceProvider.ACCESS_TOKEN_URL);
+ providerInfo.setProvider(provider);
+ providerInfo.setHttpMethod(HttpMethod.GET);
+ OAuthStore.ConsumerKeyAndSecret kas = new OAuthStore.ConsumerKeyAndSecret(
+ FakeOAuthServiceProvider.CONSUMER_KEY,
+ FakeOAuthServiceProvider.CONSUMER_SECRET,
+ OAuthStore.KeyType.HMAC_SYMMETRIC);
+ providerInfo.setKeyAndSecret(kas);
+ providerInfo.setParamLocation(OAuthParamLocation.AUTH_HEADER);
+ providerInfo.setSignatureType(SignatureType.HMAC_SHA1);
+
+ base.setOAuthServiceProviderInfo(providerKey, providerInfo);
+ return new BasicGadgetOAuthTokenStore(base);
+ }
+
+ /**
+ * Builds a nicely populated gadget token.
+ */
+ public static GadgetToken getGadgetToken(String owner, String viewer)
+ throws Exception {
+ return new BasicGadgetToken(owner, viewer, "app", "container.com",
+ GADGET_URL, "0");
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ public ContentFetcher getFetcher(
+ GadgetToken authToken, OAuthRequestParams params) throws GadgetException
{
+ OAuthFetcher fetcher = new OAuthFetcher(
+ tokenStore, blobCrypter, serviceProvider, authToken, params);
+ fetcher.init();
+ return fetcher;
+ }
+
+
+ public void testOAuthFlow() throws Exception {
+ ContentFetcher fetcher;
+ RemoteContentRequest request;
+ RemoteContent response;
+
+ fetcher = getFetcher(
+ getGadgetToken("owner", "owner"),
+ new OAuthRequestParams(SERVICE_NAME, null, null));
+ request = new RemoteContentRequest(
+ new URI(FakeOAuthServiceProvider.RESOURCE_URL));
+ response = fetcher.fetch(request);
+ String clientState = response.getMetadata().get("oauthState");
+ assertNotNull(clientState);
+ String approvalUrl = response.getMetadata().get("approvalUrl");
+ assertNotNull(approvalUrl);
+
+ serviceProvider.browserVisit(approvalUrl + "&user_data=hello-oauth");
+
+ fetcher = getFetcher(
+ getGadgetToken("owner", "owner"),
+ new OAuthRequestParams(SERVICE_NAME, null, clientState));
+ request = new RemoteContentRequest(
+ new URI(FakeOAuthServiceProvider.RESOURCE_URL));
+ response = fetcher.fetch(request);
+ assertEquals("User data is hello-oauth", response.getResponseAsString());
+
+ fetcher = getFetcher(
+ getGadgetToken("owner", "somebody else"),
+ new OAuthRequestParams(SERVICE_NAME, null, null));
+ request = new RemoteContentRequest(
+ new URI(FakeOAuthServiceProvider.RESOURCE_URL));
+ response = fetcher.fetch(request);
+ assertEquals("User data is hello-oauth", response.getResponseAsString());
+
+ fetcher = getFetcher(
+ getGadgetToken("somebody else", "somebody else"),
+ new OAuthRequestParams(SERVICE_NAME, null, null));
+ request = new RemoteContentRequest(
+ new URI(FakeOAuthServiceProvider.RESOURCE_URL));
+ response = fetcher.fetch(request);
+ clientState = response.getMetadata().get("oauthState");
+ assertNotNull(clientState);
+ approvalUrl = response.getMetadata().get("approvalUrl");
+ assertNotNull(approvalUrl);
+
+ serviceProvider.browserVisit(approvalUrl + "&user_data=somebody%20else");
+
+ fetcher = getFetcher(
+ getGadgetToken("somebody else", "somebody else"),
+ new OAuthRequestParams(SERVICE_NAME, null, clientState));
+ request = new RemoteContentRequest(
+ new URI(FakeOAuthServiceProvider.RESOURCE_URL));
+ response = fetcher.fetch(request);
+ assertEquals("User data is somebody else", response.getResponseAsString());
+ }
+
+}