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 [1/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...
Author: beaton
Date: Tue Sep 9 18:50:41 2008
New Revision: 693675
URL: http://svn.apache.org/viewvc?rev=693675&view=rev
Log:
OAuth for social sites.
This unifies the OAuth and signed fetch code paths. We also get HMAC for
signed fetch from this.
Added:
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/AccessorInfo.java (with props)
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/AccessorInfoBuilder.java (with props)
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreConsumerIndex.java (with props)
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreConsumerKeyAndSecret.java (with props)
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreTokenIndex.java (with props)
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/MakeRequestClient.java (with props)
Removed:
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SigningFetcher.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SigningFetcherFactory.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/BasicGadgetOAuthTokenStore.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetchParams.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/SigningFetcherTest.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/BasicGadgetOAuthTokenStoreTest.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/OAuthFetchParamsTest.java
Modified:
incubator/shindig/trunk/config/oauth.json
incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/crypto/BasicBlobCrypter.java
incubator/shindig/trunk/java/gadgets/conf/gadgets.properties
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/DefaultGuiceModule.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServer.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ContentFetcherFactory.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpRequest.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/BasicOAuthStore.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/GadgetOAuthTokenStore.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthArguments.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/OAuthFetcherConfig.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthFetcherFactory.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthStore.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/preload/HttpPreloader.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/HttpGuiceModule.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/MakeRequestHandler.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetTestFixture.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpRequestTest.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreTest.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/GadgetTokenStoreTest.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/OAuthArgumentsTest.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/OAuthFetcherTest.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/preload/HttpPreloaderTest.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetRenderingTaskTest.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/MakeRequestHandlerTest.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ServletTestFixture.java
incubator/shindig/trunk/java/server/src/test/java/org/apache/shindig/server/endtoend/EndToEndServer.java
Modified: incubator/shindig/trunk/config/oauth.json
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/config/oauth.json?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/config/oauth.json (original)
+++ incubator/shindig/trunk/config/oauth.json Tue Sep 9 18:50:41 2008
@@ -17,12 +17,14 @@
* under the License.
*/
-{"http://localhost:8080/gadgets/files/samplecontainer/examples/oauth.xml" : {
- "" : {
- "consumer_key" : "gadgetConsumer",
- "consumer_secret" : "gadgetSecret",
- "key_type" : "HMAC_SYMMETRIC"
+{
+ "http://localhost:8080/gadgets/files/samplecontainer/examples/oauth.xml" : {
+ "" : {
+ "consumer_key" : "gadgetConsumer",
+ "consumer_secret" : "gadgetSecret",
+ "key_type" : "HMAC_SYMMETRIC"
+ }
}
-}}
+}
Modified: incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/crypto/BasicBlobCrypter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/crypto/BasicBlobCrypter.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/crypto/BasicBlobCrypter.java (original)
+++ incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/crypto/BasicBlobCrypter.java Tue Sep 9 18:50:41 2008
@@ -18,11 +18,17 @@
*/
package org.apache.shindig.common.crypto;
+import org.apache.shindig.common.util.CharsetUtil;
import org.apache.shindig.common.util.TimeSource;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
@@ -55,11 +61,46 @@
private byte[] hmacKey;
/**
+ * Creates a crypter based on a key in a file. The key is the first line
+ * in the file, whitespace trimmed from either end, as UTF-8 bytes.
+ *
+ * The following *nix command line will create an excellent key:
+ *
+ * dd if=/dev/random bs=32 count=1 | openssl base64 > /tmp/key.txt
+ *
+ * @throws IOException if the file can't be read.
+ */
+ public BasicBlobCrypter(File keyfile) throws IOException {
+ FileInputStream openFile = null;
+ try {
+ openFile = new FileInputStream(keyfile);
+ BufferedReader reader = new BufferedReader(
+ new InputStreamReader(openFile, CharsetUtil.UTF8));
+ String line = reader.readLine();
+ line = line.trim();
+ byte[] keyBytes = CharsetUtil.getUtf8Bytes(line);
+ init(keyBytes);
+ } finally {
+ try {
+ if (openFile != null) {
+ openFile.close();
+ }
+ } catch (IOException e) {
+ // oh well.
+ }
+ }
+ }
+
+ /**
* Builds a BlobCrypter from the specified master key
*
* @param masterKey
*/
public BasicBlobCrypter(byte[] masterKey) {
+ init(masterKey);
+ }
+
+ private void init(byte[] masterKey) {
if (masterKey.length < MASTER_KEY_MIN_LEN) {
throw new IllegalArgumentException("Master key needs at least " +
MASTER_KEY_MIN_LEN + " bytes");
Modified: incubator/shindig/trunk/java/gadgets/conf/gadgets.properties
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/conf/gadgets.properties?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/conf/gadgets.properties (original)
+++ incubator/shindig/trunk/java/gadgets/conf/gadgets.properties Tue Sep 9 18:50:41 2008
@@ -3,8 +3,8 @@
shindig.blacklist.file=
shindig.urls.iframe.prefix=/gadgets/ifr?
shindig.urls.js.prefix=/gadgets/js/
-shindig.signing.key-name=
-shindig.signing.key-file=
+#shindig.signing.key-name=
+#shindig.signing.key-file=
shindig.locked-domain.enabled=false
shindig.locked-domain.embed-host=127.0.0.1:8080
shindig.content-rewrite.include-urls=.*
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/DefaultGuiceModule.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/DefaultGuiceModule.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/DefaultGuiceModule.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/DefaultGuiceModule.java Tue Sep 9 18:50:41 2008
@@ -18,14 +18,23 @@
*/
package org.apache.shindig.gadgets;
+import org.apache.commons.io.IOUtils;
+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.common.util.ResourceLoader;
import org.apache.shindig.gadgets.http.HttpResponse;
+import org.apache.shindig.gadgets.oauth.BasicOAuthStoreConsumerKeyAndSecret;
+import org.apache.shindig.gadgets.oauth.OAuthStore;
+import org.apache.shindig.gadgets.oauth.BasicOAuthStore;
+import org.apache.shindig.gadgets.oauth.BasicOAuthStoreConsumerKeyAndSecret.KeyType;
import com.google.inject.AbstractModule;
import com.google.inject.CreationException;
import com.google.inject.name.Names;
import com.google.inject.spi.Message;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
@@ -33,13 +42,26 @@
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.logging.Level;
+import java.util.logging.Logger;
/**
* Creates a module to supply all of the Basic* classes
*/
public class DefaultGuiceModule extends AbstractModule {
+
+ private static final Logger logger
+ = Logger.getLogger(DefaultGuiceModule.class.getName());
+
private final Properties properties;
+ private final String oauthConfig;
+
private final static String DEFAULT_PROPERTIES = "gadgets.properties";
+ private final static String OAUTH_CONFIG = "config/oauth.json";
+
+ public final static String OAUTH_STATE_CRYPTER_ANNOTATION = "shindig.oauth.state-key";
+ public final static String OAUTH_SIGNING_KEY_NAME = "shindig.signing.key-name";
+ public final static String OAUTH_SIGNING_KEY_FILE = "shindig.signing.key-file";
/** {@inheritDoc} */
@Override
@@ -49,13 +71,89 @@
ExecutorService service = Executors.newCachedThreadPool();
bind(Executor.class).toInstance(service);
bind(ExecutorService.class).toInstance(service);
-
+
+ try {
+ configureOAuthStore();
+ configureOAuthStateCrypter();
+ } 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);
+ }
+
// We perform static injection on HttpResponse for cache TTLs.
requestStaticInjection(HttpResponse.class);
}
+
+ /**
+ * Create a store for OAuth consumer keys and access tokens. By default consumer keys are read
+ * from config/oauth.json, and access tokens are stored in memory.
+ *
+ * We read the default key from disk, in a location specified in our properties file.
+ */
+ private void configureOAuthStore() throws GadgetException {
+ BasicOAuthStore store = new BasicOAuthStore();
+ bind(OAuthStore.class).toInstance(store);
+ store.initFromConfigString(oauthConfig);
+
+ String keyName = properties.getProperty(OAUTH_SIGNING_KEY_NAME);
+ String keyFile = properties.getProperty(OAUTH_SIGNING_KEY_FILE);
+ BasicOAuthStoreConsumerKeyAndSecret defaultKey = null;
+ if (keyFile != null) {
+ try {
+ logger.info("Loading OAuth signing key from " + keyFile);
+ String privateKey = IOUtils.toString(ResourceLoader.open(keyFile), "UTF-8");
+ privateKey = BasicOAuthStore.convertFromOpenSsl(privateKey);
+ defaultKey = new BasicOAuthStoreConsumerKeyAndSecret(null, privateKey, KeyType.RSA_PRIVATE,
+ keyName);
+ } catch (IOException e) {
+ logger.log(Level.WARNING, "Couldn't load key file " + keyFile, e);
+ }
+ }
+ if (defaultKey != null) {
+ store.setDefaultKey(defaultKey);
+ } else {
+ logger.log(Level.WARNING, "Couldn't load OAuth signing key. To create a key, run:\n" +
+ " openssl req -newkey rsa:1024 -days 365 -nodes -x509 -keyout testkey.pem \\\n" +
+ " -out testkey.pem -subj '/CN=mytestkey'\n" +
+ " openssl pkcs8 -in testkey.pem -out oauthkey.pem -topk8 -nocrypt -outform PEM\n" +
+ "\n" +
+ "Then edit gadgets.properties and add these lines:\n" +
+ OAUTH_SIGNING_KEY_FILE + "=<path-to-oauthkey.pem>\n" +
+ OAUTH_SIGNING_KEY_NAME + "=mykey\n");
+ }
+ }
+
+ /**
+ * Create a crypter to handle OAuth state. This can be loaded from disk, if
+ * shindig.oauth.state-key-file is specified in your gadgets.properties file, or it can be
+ * created using a random key.
+ */
+ private void configureOAuthStateCrypter() {
+ // Create the oauth state crypter based on a file from disk
+ BasicBlobCrypter oauthCrypter = null;
+ String keyFileName = properties.getProperty("shindig.oauth.state-key-file");
+ if (keyFileName != null) {
+ logger.info("Loading OAuth state crypter from " + keyFileName);
+ try {
+ oauthCrypter = new BasicBlobCrypter(new File(keyFileName));
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, "Failed to load " + keyFileName, e);
+ }
+ }
+ if (oauthCrypter == null) {
+ logger.info("Creating OAuth state crypter with random key");
+ oauthCrypter = new BasicBlobCrypter(
+ Crypto.getRandomBytes(BasicBlobCrypter.MASTER_KEY_MIN_LEN));
+ }
+ bind(BlobCrypter.class).annotatedWith(
+ Names.named(OAUTH_STATE_CRYPTER_ANNOTATION))
+ .toInstance(oauthCrypter);
+ }
- public DefaultGuiceModule(Properties properties) {
+ public DefaultGuiceModule(Properties properties, String oauthConfig) {
this.properties = properties;
+ this.oauthConfig = oauthConfig;
}
/**
@@ -63,14 +161,21 @@
*/
public DefaultGuiceModule() {
Properties properties = null;
+ String oauthConfig = null;
try {
InputStream is = ResourceLoader.openResource(DEFAULT_PROPERTIES);
properties = new Properties();
properties.load(is);
+ try {
+ oauthConfig = ResourceLoader.getContent(OAUTH_CONFIG);
+ } catch (IOException e) {
+ logger.log(Level.WARNING, "Can't load " + OAUTH_CONFIG, e);
+ }
} catch (IOException e) {
throw new CreationException(Arrays.asList(
new Message("Unable to load properties: " + DEFAULT_PROPERTIES)));
}
this.properties = properties;
+ this.oauthConfig = oauthConfig;
}
}
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServer.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServer.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServer.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetServer.java Tue Sep 9 18:50:41 2008
@@ -193,8 +193,7 @@
public HttpResponse call() {
try {
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()));
@@ -202,11 +201,8 @@
case NONE:
return preloadFetcherFactory.get().fetch(request);
case SIGNED:
- return preloadFetcherFactory.getSigningFetcher(context.getToken())
- .fetch(request);
case OAUTH:
- return preloadFetcherFactory.getOAuthFetcher(context.getToken(),
- new OAuthArguments(preload)).fetch(request);
+ return preloadFetcherFactory.getOAuthFetcher(request).fetch(request);
default:
return HttpResponse.error();
}
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ContentFetcherFactory.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ContentFetcherFactory.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ContentFetcherFactory.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ContentFetcherFactory.java Tue Sep 9 18:50:41 2008
@@ -17,10 +17,7 @@
*/
package org.apache.shindig.gadgets.http;
-import org.apache.shindig.auth.SecurityToken;
import org.apache.shindig.gadgets.GadgetException;
-import org.apache.shindig.gadgets.SigningFetcherFactory;
-import org.apache.shindig.gadgets.oauth.OAuthArguments;
import org.apache.shindig.gadgets.oauth.OAuthFetcherFactory;
import com.google.inject.Inject;
@@ -34,41 +31,23 @@
public class ContentFetcherFactory implements Provider<HttpFetcher> {
private final RemoteContentFetcherFactory remoteContentFetcherFactory;
- private final SigningFetcherFactory signingFetcherFactory;
private final OAuthFetcherFactory oauthFetcherFactory;
@Inject
public ContentFetcherFactory(RemoteContentFetcherFactory remoteContentFetcherFactory,
- SigningFetcherFactory signingFetcherFactory,
OAuthFetcherFactory oauthFetcherFactory) {
- this.signingFetcherFactory = signingFetcherFactory;
this.remoteContentFetcherFactory = remoteContentFetcherFactory;
this.oauthFetcherFactory = oauthFetcherFactory;
}
/**
- * @param token
- * @return A signing content fetcher
- * @throws GadgetException
- */
- public HttpFetcher getSigningFetcher(SecurityToken token)
- throws GadgetException {
- return signingFetcherFactory.getSigningFetcher(
- remoteContentFetcherFactory.get(), token);
- }
-
- /**
- * @param token
- * @param params
+ * @param request HttpRequest that will be sent through the fetcher
* @return an OAuth fetcher
* @throws GadgetException
*/
- public HttpFetcher getOAuthFetcher(
- SecurityToken token,
- OAuthArguments params)
+ public HttpFetcher getOAuthFetcher(HttpRequest request)
throws GadgetException {
- return oauthFetcherFactory.getOAuthFetcher(
- remoteContentFetcherFactory.get(), token, params);
+ return oauthFetcherFactory.getOAuthFetcher(remoteContentFetcherFactory.get(), request);
}
/**
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpRequest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpRequest.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpRequest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/HttpRequest.java Tue Sep 9 18:50:41 2008
@@ -21,6 +21,7 @@
import org.apache.shindig.auth.SecurityToken;
import org.apache.shindig.common.ContainerConfig;
import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.gadgets.oauth.OAuthArguments;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -62,8 +63,7 @@
// For signed fetch & OAuth
private SecurityToken securityToken;
- private boolean signOwner = true;
- private boolean signViewer = true;
+ private OAuthArguments oauthArguments;
private String rewriteMimeType;
@@ -87,8 +87,9 @@
gadget = request.gadget;
container = request.container;
securityToken = request.securityToken;
- signOwner = request.signOwner;
- signViewer = request.signViewer;
+ if (request.oauthArguments != null) {
+ oauthArguments = new OAuthArguments(request.oauthArguments);
+ }
rewriteMimeType = request.rewriteMimeType;
}
@@ -221,20 +222,10 @@
}
/**
- * @param signOwner Whether to include the owner id when making authenticated requests. Defaults
- * to true.
- */
- public HttpRequest setSignOwner(boolean signOwner) {
- this.signOwner = signOwner;
- return this;
- }
-
- /**
- * @param signViewer Whether to include the viewer id when making authenticated requests. Defaults
- * to true.
+ * @param oauthArguments arguments for OAuth/signed fetched
*/
- public HttpRequest setSignViewer(boolean signViewer) {
- this.signViewer = signViewer;
+ public HttpRequest setOAuthArguments(OAuthArguments oauthArguments) {
+ this.oauthArguments = oauthArguments;
return this;
}
@@ -366,17 +357,10 @@
}
/**
- * @return True if the owner id should be passed in the request parameters.
- */
- public boolean getSignOwner() {
- return signOwner;
- }
-
- /**
- * @return True if the viewer id should be passed in the request parameters.
+ * @return arguments for OAuth and signed fetch
*/
- public boolean getSignViewer() {
- return signViewer;
+ public OAuthArguments getOAuthArguments() {
+ return oauthArguments;
}
/**
Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/AccessorInfo.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/AccessorInfo.java?rev=693675&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/AccessorInfo.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/AccessorInfo.java Tue Sep 9 18:50:41 2008
@@ -0,0 +1,65 @@
+/*
+ * 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.OAuthAccessor;
+
+import org.apache.shindig.gadgets.oauth.OAuthStore.ConsumerInfo;
+
+public class AccessorInfo {
+
+ public static enum HttpMethod {
+ GET,
+ POST
+ }
+
+ public static enum OAuthParamLocation {
+ AUTH_HEADER,
+ POST_BODY,
+ URI_QUERY
+ }
+
+ private final OAuthAccessor accessor;
+ private final ConsumerInfo consumer;
+ private final HttpMethod httpMethod;
+ private final OAuthParamLocation paramLocation;
+
+ public AccessorInfo(OAuthAccessor accessor, ConsumerInfo consumer, HttpMethod httpMethod,
+ OAuthParamLocation paramLocation) {
+ this.accessor = accessor;
+ this.consumer = consumer;
+ this.httpMethod = httpMethod;
+ this.paramLocation = paramLocation;
+ }
+
+ public OAuthParamLocation getParamLocation() {
+ return paramLocation;
+ }
+
+ public OAuthAccessor getAccessor() {
+ return accessor;
+ }
+
+ public ConsumerInfo getConsumer() {
+ return consumer;
+ }
+
+ public HttpMethod getHttpMethod() {
+ return httpMethod;
+ }
+}
\ No newline at end of file
Propchange: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/AccessorInfo.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/AccessorInfoBuilder.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/AccessorInfoBuilder.java?rev=693675&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/AccessorInfoBuilder.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/AccessorInfoBuilder.java Tue Sep 9 18:50:41 2008
@@ -0,0 +1,85 @@
+/*
+ * 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.OAuthAccessor;
+
+import org.apache.shindig.gadgets.GadgetException;
+import org.apache.shindig.gadgets.oauth.AccessorInfo.HttpMethod;
+import org.apache.shindig.gadgets.oauth.AccessorInfo.OAuthParamLocation;
+import org.apache.shindig.gadgets.oauth.OAuthStore.ConsumerInfo;
+
+/**
+ * Builder for AccessorInfo object.
+ */
+public class AccessorInfoBuilder {
+
+ private ConsumerInfo consumer;
+ private String requestToken;
+ private String accessToken;
+ private String tokenSecret;
+ private OAuthParamLocation location;
+ private HttpMethod method;
+
+ public AccessorInfoBuilder() {
+ }
+
+ public AccessorInfo create() throws GadgetException {
+ if (location == null) {
+ throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, "no location");
+ }
+ if (consumer == null) {
+ throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR, "no consumer");
+ }
+
+ OAuthAccessor accessor = new OAuthAccessor(consumer.getConsumer());
+
+ // request token/access token/token secret can all be null, for signed fetch, or if the OAuth
+ // dance is just beginning
+ accessor.requestToken = requestToken;
+ accessor.accessToken = accessToken;
+ accessor.tokenSecret = tokenSecret;
+ return new AccessorInfo(accessor, consumer, method, location);
+ }
+
+ public void setConsumer(ConsumerInfo consumer) {
+ this.consumer = consumer;
+ }
+
+ public void setRequestToken(String requestToken) {
+ this.requestToken = requestToken;
+ }
+
+ public void setAccessToken(String accessToken) {
+ this.accessToken = accessToken;
+ }
+
+ public void setTokenSecret(String tokenSecret) {
+ this.tokenSecret = tokenSecret;
+ }
+
+ public void setParameterLocation(OAuthParamLocation location) {
+ this.location = location;
+ }
+
+ public void setMethod(HttpMethod method) {
+ this.method = method;
+ }
+}
Propchange: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/AccessorInfoBuilder.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/BasicOAuthStore.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/BasicOAuthStore.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/BasicOAuthStore.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/BasicOAuthStore.java Tue Sep 9 18:50:41 2008
@@ -17,12 +17,23 @@
*/
package org.apache.shindig.gadgets.oauth;
-import net.oauth.OAuthAccessor;
+import com.google.inject.Singleton;
+
+import net.oauth.OAuth;
import net.oauth.OAuthConsumer;
import net.oauth.OAuthServiceProvider;
import net.oauth.signature.RSA_SHA1;
+import org.apache.shindig.auth.SecurityToken;
+import org.apache.shindig.gadgets.GadgetException;
+import org.apache.shindig.gadgets.oauth.BasicOAuthStoreConsumerKeyAndSecret.KeyType;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.net.URI;
+import java.net.URISyntaxException;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.Map;
/**
@@ -31,178 +42,160 @@
* return an OAuthAccessor in {@code getOAuthAccessor} that uses that private
* key if no consumer key and secret could be found.
*/
+@Singleton
public class BasicOAuthStore implements OAuthStore {
+ private static final String CONSUMER_SECRET_KEY = "consumer_secret";
+ private static final String CONSUMER_KEY_KEY = "consumer_key";
+ private static final String KEY_TYPE_KEY = "key_type";
+
/**
- * HashMap of provider and consumer information. Maps ProviderKeys (i.e.
+ * HashMap of provider and consumer information. Maps BasicOAuthStoreConsumerIndexs (i.e.
* nickname of a service provider and the gadget that uses that nickname) to
- * {@link OAuthStore.ProviderInfo}s.
+ * {@link BasicOAuthStoreConsumerKeyAndSecret}s.
*/
- private Map<ProviderKey, ConsumerKeyAndSecret> consumerInfos =
- new HashMap<ProviderKey, ConsumerKeyAndSecret>();
+ private final Map<BasicOAuthStoreConsumerIndex, BasicOAuthStoreConsumerKeyAndSecret> consumerInfos;
/**
- * HashMap of token information. Maps TokenKeys (i.e. gadget id, token
+ * HashMap of token information. Maps BasicOAuthStoreTokenIndexs (i.e. gadget id, token
* nickname, module id, etc.) to TokenInfos (i.e. access token and token
* secrets).
*/
- private Map<TokenKey, TokenInfo> tokens = new HashMap<TokenKey, TokenInfo>();
-
- /**
- * The default consumer key to be used if no consumer key could be found in
- * the store.
- */
- private String defaultConsumerKey;
-
+ private final Map<BasicOAuthStoreTokenIndex, TokenInfo> tokens;
+
/**
- * The default consumer "secret" to be used when no secret could be found in
- * store. This <b>must</b> be a PKCS8-then-Base64-encoded RSA private key.
- * (Can also be null.)
+ * Key to use when no other key is found.
*/
- private String defaultConsumerSecret;
+ private BasicOAuthStoreConsumerKeyAndSecret defaultKey;
- /**
- * Public constructor. Makes an OAuthStoreImpl that doesn't have a fallback
- * RSA key to sign outgoing requests. When no consumer secret can be found,
- * {@code getOAuthAccessor} will throw an exception.
- */
public BasicOAuthStore() {
- this(null, null);
- }
-
- /**
- * Public constructor. Makes an OAuthStoreImpl with a fallback
- * RSA key to sign outgoing requests. When no consumer secret can be found,
- * {@code getOAuthAccessor} will create an OAuthAccessor that uses the
- * fallback RSA private key.
- *
- * @param consumerKey the consumer key to be used when no consumer key
- * can be found in the oauth store for a specific
- * {@code getOAuthAccessor} request.
- * @param privateKey the RSA private key to be used when no consumer secret
- * can be found in the oauth store for a specific
- * {@code getOAuthAccessor} request.
- */
- public BasicOAuthStore(String consumerKey, String privateKey) {
- defaultConsumerKey = consumerKey;
- defaultConsumerSecret = privateKey;
+ consumerInfos = new HashMap<BasicOAuthStoreConsumerIndex, BasicOAuthStoreConsumerKeyAndSecret>();
+ tokens = new HashMap<BasicOAuthStoreTokenIndex, TokenInfo>();
}
-
- void setHashMapsForTesting(
- Map<ProviderKey, ConsumerKeyAndSecret> consumers,
- Map<TokenKey, TokenInfo> tokens) {
- this.consumerInfos = consumers;
- this.tokens = tokens;
- }
-
- /**
- * {@inheritDoc}
- */
- public AccessorInfo getOAuthAccessor(TokenKey tokenKey, ProviderInfo provInfo)
- throws OAuthNoDataException {
-
- ProviderKey provKey = new ProviderKey();
- provKey.setGadgetUri(tokenKey.getGadgetUri());
- provKey.setServiceName(tokenKey.getServiceName());
-
- AccessorInfo result = getOAuthAccessor(provKey, provInfo);
-
- TokenInfo accessToken = tokens.get(tokenKey);
-
- if (accessToken != null) {
- result.getAccessor().accessToken = accessToken.getAccessToken();
- result.getAccessor().tokenSecret = accessToken.getTokenSecret();
+
+ public void initFromConfigString(String oauthConfigStr) throws GadgetException {
+ try {
+ JSONObject oauthConfigs = new JSONObject(oauthConfigStr);
+ for (Iterator<?> i = oauthConfigs.keys(); i.hasNext();) {
+ String url = (String) i.next();
+ URI gadgetUri = new URI(url);
+ JSONObject oauthConfig = oauthConfigs.getJSONObject(url);
+ storeConsumerInfos(gadgetUri, oauthConfig);
+ }
+ } catch (JSONException e) {
+ throw new GadgetException(GadgetException.Code.OAUTH_STORAGE_ERROR, e);
+ } catch (URISyntaxException e) {
+ throw new GadgetException(GadgetException.Code.OAUTH_STORAGE_ERROR, e);
}
-
- return result;
}
- private AccessorInfo getOAuthAccessor(ProviderKey providerKey,
- ProviderInfo provInfo)
- throws OAuthNoDataException {
-
- if (provInfo == null) {
- throw new OAuthNoDataException("must pass non-null provider info to" +
- " getOAuthAccessor");
- }
-
- AccessorInfo result = new AccessorInfo();
- result.setHttpMethod(provInfo.getHttpMethod());
- result.setParamLocation(provInfo.getParamLocation());
-
- ConsumerKeyAndSecret consumerKeyAndSecret = consumerInfos.get(providerKey);
-
- if (consumerKeyAndSecret == null) {
- if (defaultConsumerKey == null || defaultConsumerSecret == null) {
- // if we don't have a fallback key and secret, that's all we can do
- throw new OAuthNoDataException("ConsumerKeyAndSecret " +
- "was null in oauth store");
- } else {
- // we'll use the fallback key and secret.
- consumerKeyAndSecret =
- new ConsumerKeyAndSecret(defaultConsumerKey,
- defaultConsumerSecret,
- OAuthStore.KeyType.RSA_PRIVATE);
- }
+ private void storeConsumerInfos(URI gadgetUri, JSONObject oauthConfig)
+ throws JSONException, GadgetException {
+ for (String serviceName : JSONObject.getNames(oauthConfig)) {
+ JSONObject consumerInfo = oauthConfig.getJSONObject(serviceName);
+ storeConsumerInfo(gadgetUri, serviceName, consumerInfo);
}
+ }
- OAuthServiceProvider oauthProvider = provInfo.getProvider();
+ @SuppressWarnings("unused")
+ private void storeConsumerInfo(URI gadgetUri, String serviceName, JSONObject consumerInfo)
+ throws JSONException, GadgetException {
+ realStoreConsumerInfo(gadgetUri, serviceName, consumerInfo);
+ }
+
+ private void realStoreConsumerInfo(URI gadgetUri, String serviceName, JSONObject consumerInfo)
+ throws JSONException {
+ String consumerSecret = consumerInfo.getString(CONSUMER_SECRET_KEY);
+ String consumerKey = consumerInfo.getString(CONSUMER_KEY_KEY);
+ String keyTypeStr = consumerInfo.getString(KEY_TYPE_KEY);
+ KeyType keyType = KeyType.HMAC_SYMMETRIC;
- if (oauthProvider == null) {
- throw new OAuthNoDataException("OAuthService provider " +
- "was null in provider info");
- }
-
- boolean usePublicKeyCrypto =
- (consumerKeyAndSecret.getKeyType() == OAuthStore.KeyType.RSA_PRIVATE);
-
- OAuthConsumer consumer = usePublicKeyCrypto
- ? new OAuthConsumer(null, // no callback URL
- consumerKeyAndSecret.getConsumerKey(),
- null,
- oauthProvider)
- : new OAuthConsumer(null, // no callback URL
- consumerKeyAndSecret.getConsumerKey(),
- consumerKeyAndSecret.getConsumerSecret(),
- oauthProvider);
-
- if (usePublicKeyCrypto) {
- consumer.setProperty(RSA_SHA1.PRIVATE_KEY,
- consumerKeyAndSecret.getConsumerSecret());
- result.setSignatureType(OAuthStore.SignatureType.RSA_SHA1);
- } else {
- result.setSignatureType(OAuthStore.SignatureType.HMAC_SHA1);
+ if (keyTypeStr.equals("RSA_PRIVATE")) {
+ keyType = KeyType.RSA_PRIVATE;
+ consumerSecret = convertFromOpenSsl(consumerSecret);
}
- result.setAccessor(new OAuthAccessor(consumer));
+ BasicOAuthStoreConsumerKeyAndSecret kas = new BasicOAuthStoreConsumerKeyAndSecret(
+ consumerKey, consumerSecret, keyType, null);
- return result;
+ BasicOAuthStoreConsumerIndex index = new BasicOAuthStoreConsumerIndex();
+ index.setGadgetUri(gadgetUri.toASCIIString());
+ index.setServiceName(serviceName);
+ setConsumerKeyAndSecret(index, kas);
+ }
+
+ // Support standard openssl keys by stripping out the headers and blank lines
+ public static String convertFromOpenSsl(String privateKey) {
+ return privateKey.replaceAll("-----[A-Z ]*-----", "").replace("\n", "");
+ }
+
+ public void setDefaultKey(BasicOAuthStoreConsumerKeyAndSecret defaultKey) {
+ this.defaultKey = defaultKey;
}
- /**
- * {@inheritDoc}
- */
- public void setOAuthConsumerKeyAndSecret(ProviderKey providerKey,
- ConsumerKeyAndSecret keyAndSecret) {
+ public void setConsumerKeyAndSecret(
+ BasicOAuthStoreConsumerIndex providerKey, BasicOAuthStoreConsumerKeyAndSecret keyAndSecret) {
consumerInfos.put(providerKey, keyAndSecret);
}
- /**
- * {@inheritDoc}
- */
- public void setTokenAndSecret(TokenKey tokenKey, TokenInfo tokenInfo) {
+ public ConsumerInfo getConsumerKeyAndSecret(
+ SecurityToken securityToken, String serviceName, OAuthServiceProvider provider)
+ throws GadgetException {
+ BasicOAuthStoreConsumerIndex pk = new BasicOAuthStoreConsumerIndex();
+ pk.setGadgetUri(securityToken.getAppUrl());
+ pk.setServiceName(serviceName);
+ BasicOAuthStoreConsumerKeyAndSecret cks = consumerInfos.get(pk);
+ if (cks == null) {
+ cks = defaultKey;
+ }
+ if (cks == null) {
+ throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR,
+ "No key for gadget " + securityToken.getAppUrl() + " and service " + serviceName);
+ }
+ OAuthConsumer consumer = null;
+ if (cks.getKeyType() == KeyType.RSA_PRIVATE) {
+ consumer = new OAuthConsumer(null, cks.getConsumerKey(), null, provider);
+ // The oauth.net java code has lots of magic. By setting this property here, code thousands
+ // of lines away knows that the consumerSecret value in the consumer should be treated as
+ // an RSA private key and not an HMAC key.
+ consumer.setProperty(OAuth.OAUTH_SIGNATURE_METHOD, OAuth.RSA_SHA1);
+ consumer.setProperty(RSA_SHA1.PRIVATE_KEY, cks.getConsumerSecret());
+ } else {
+ consumer = new OAuthConsumer(null, cks.getConsumerKey(), cks.getConsumerSecret(), provider);
+ consumer.setProperty(OAuth.OAUTH_SIGNATURE_METHOD, OAuth.HMAC_SHA1);
+ }
+ return new ConsumerInfo(consumer, cks.getKeyName());
+ }
+
+ private BasicOAuthStoreTokenIndex makeBasicOAuthStoreTokenIndex(
+ SecurityToken securityToken, String serviceName, String tokenName) {
+ BasicOAuthStoreTokenIndex tokenKey = new BasicOAuthStoreTokenIndex();
+ tokenKey.setGadgetUri(securityToken.getAppUrl());
+ tokenKey.setModuleId(securityToken.getModuleId());
+ tokenKey.setServiceName(serviceName);
+ tokenKey.setTokenName(tokenName);
+ tokenKey.setUserId(securityToken.getViewerId());
+ return tokenKey;
+ }
+
+ public TokenInfo getTokenInfo(SecurityToken securityToken, ConsumerInfo consumerInfo,
+ String serviceName, String tokenName) {
+ BasicOAuthStoreTokenIndex tokenKey =
+ makeBasicOAuthStoreTokenIndex(securityToken, serviceName, tokenName);
+ return tokens.get(tokenKey);
+ }
+
+ public void setTokenInfo(SecurityToken securityToken, ConsumerInfo consumerInfo,
+ String serviceName, String tokenName, TokenInfo tokenInfo) {
+ BasicOAuthStoreTokenIndex tokenKey =
+ makeBasicOAuthStoreTokenIndex(securityToken, serviceName, tokenName);
tokens.put(tokenKey, tokenInfo);
}
- /**
- * {@inheritDoc}
- */
- public void removeToken(TokenKey tokenKey) throws OAuthStoreException,
- OAuthNoDataException {
- if (tokens.containsKey(tokenKey)) {
- tokens.remove(tokenKey);
- } else {
- throw new OAuthNoDataException("Could not find access token");
- }
+ public void removeToken(SecurityToken securityToken, ConsumerInfo consumerInfo,
+ String serviceName, String tokenName) {
+ BasicOAuthStoreTokenIndex tokenKey =
+ makeBasicOAuthStoreTokenIndex(securityToken, serviceName, tokenName);
+ tokens.remove(tokenKey);
}
}
Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreConsumerIndex.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreConsumerIndex.java?rev=693675&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreConsumerIndex.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreConsumerIndex.java Tue Sep 9 18:50:41 2008
@@ -0,0 +1,67 @@
+/*
+ * 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;
+
+/**
+ * Index into the token store by
+ */
+public class BasicOAuthStoreConsumerIndex {
+ 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 BasicOAuthStoreConsumerIndex other = (BasicOAuthStoreConsumerIndex) 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;
+ }
+}
Propchange: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreConsumerIndex.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreConsumerKeyAndSecret.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreConsumerKeyAndSecret.java?rev=693675&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreConsumerKeyAndSecret.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreConsumerKeyAndSecret.java Tue Sep 9 18:50:41 2008
@@ -0,0 +1,63 @@
+/*
+ * 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;
+
+/**
+ * @author beaton@google.com (Your Name Here)
+ *
+ */
+public class BasicOAuthStoreConsumerKeyAndSecret {
+
+ public static enum KeyType { HMAC_SYMMETRIC, RSA_PRIVATE }
+
+ /** Value for oauth_consumer_key */
+ private final String consumerKey;
+
+ /** HMAC secret, or RSA private key, depending on keyType */
+ private final String consumerSecret;
+
+ /** Type of key */
+ private final KeyType keyType;
+
+ /** Name of public key to use with xoauth_public_key parameter. May be null */
+ private final String keyName;
+
+ public BasicOAuthStoreConsumerKeyAndSecret(String key, String secret, KeyType type, String name) {
+ consumerKey = key;
+ consumerSecret = secret;
+ keyType = type;
+ keyName = name;
+ }
+
+ public String getConsumerKey() {
+ return consumerKey;
+ }
+
+ public String getConsumerSecret() {
+ return consumerSecret;
+ }
+
+ public KeyType getKeyType() {
+ return keyType;
+ }
+
+ public String getKeyName() {
+ return keyName;
+ }
+}
Propchange: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreConsumerKeyAndSecret.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreTokenIndex.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreTokenIndex.java?rev=693675&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreTokenIndex.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreTokenIndex.java Tue Sep 9 18:50:41 2008
@@ -0,0 +1,100 @@
+/*
+ * 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;
+
+/**
+ *
+ */
+public class BasicOAuthStoreTokenIndex {
+
+ 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 BasicOAuthStoreTokenIndex other = (BasicOAuthStoreTokenIndex) 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;
+ }
+}
Propchange: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreTokenIndex.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/GadgetOAuthTokenStore.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/GadgetOAuthTokenStore.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/GadgetOAuthTokenStore.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/GadgetOAuthTokenStore.java Tue Sep 9 18:50:41 2008
@@ -17,18 +17,26 @@
*/
package org.apache.shindig.gadgets.oauth;
+import com.google.inject.Inject;
+
import net.oauth.OAuthServiceProvider;
+import org.apache.commons.lang.StringUtils;
+import org.apache.shindig.auth.SecurityToken;
import org.apache.shindig.gadgets.GadgetException;
import org.apache.shindig.gadgets.GadgetSpecFactory;
+import org.apache.shindig.gadgets.oauth.AccessorInfo.HttpMethod;
+import org.apache.shindig.gadgets.oauth.AccessorInfo.OAuthParamLocation;
+import org.apache.shindig.gadgets.oauth.OAuthStore.ConsumerInfo;
+import org.apache.shindig.gadgets.oauth.OAuthStore.TokenInfo;
import org.apache.shindig.gadgets.spec.GadgetSpec;
import org.apache.shindig.gadgets.spec.OAuthService;
import org.apache.shindig.gadgets.spec.OAuthSpec;
+import org.apache.shindig.gadgets.spec.OAuthService.Location;
+import org.apache.shindig.gadgets.spec.OAuthService.Method;
import java.net.URI;
import java.net.URISyntaxException;
-import java.util.Iterator;
-import java.util.logging.Logger;
/**
* Higher-level interface that allows callers to store and retrieve
@@ -38,33 +46,7 @@
*/
public class GadgetOAuthTokenStore {
- /**
- * Internal class used to communicate results of parsing the gadget spec
- * between methods.
- */
- static class GadgetInfo {
- private String serviceName;
- private OAuthStore.ProviderInfo providerInfo;
-
- public String getServiceName() {
- return serviceName;
- }
- public void setServiceName(String serviceName) {
- this.serviceName = serviceName;
- }
- public OAuthStore.ProviderInfo getProviderInfo() {
- return providerInfo;
- }
- public void setProviderInfo(OAuthStore.ProviderInfo providerInfo) {
- this.providerInfo = providerInfo;
- }
- }
-
- private static final Logger log =
- Logger.getLogger(GadgetOAuthTokenStore.class.getName());
-
private final OAuthStore store;
-
private final GadgetSpecFactory specFactory;
/**
@@ -73,201 +55,199 @@
* @param store an {@link OAuthStore} that can store and retrieve OAuth
* tokens, as well as information about service providers.
*/
- public GadgetOAuthTokenStore(OAuthStore store,
- GadgetSpecFactory specFactory) {
+ @Inject
+ public GadgetOAuthTokenStore(OAuthStore store, GadgetSpecFactory specFactory) {
this.store = store;
this.specFactory = specFactory;
}
/**
- * Stores a negotiated consumer key and secret in the gadget store.
- * 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.
- *
- * @param gadgetUrl the URL of the gadget
- * @param serviceName the service provider with whom we have negotiated a
- * consumer key and secret.
- * @throws OAuthStoreException if there is a problem talking to the
- * backend store.
- * @throws OAuthNoDataException if there is no data about this service
- * provider stored for this gadget.
- */
- public void storeConsumerKeyAndSecret(
- URI gadgetUrl,
- String serviceName,
- OAuthStore.ConsumerKeyAndSecret keyAndSecret)
- throws OAuthStoreException, OAuthNoDataException {
-
- OAuthStore.ProviderKey providerKey = new OAuthStore.ProviderKey();
- providerKey.setGadgetUri(gadgetUrl.toString());
- providerKey.setServiceName(serviceName);
-
- store.setOAuthConsumerKeyAndSecret(providerKey, keyAndSecret);
- }
-
- /**
- * Stores an access token in the OAuth Data Store.
- * @param tokenKey information about the Gadget storing the token.
- * @param tokenInfo the TokenInfo to be stored in the OAuth data store.
- * @throws OAuthStoreException
+ * Retrieve an AccessorInfo and OAuthAccessor that are ready for signing OAuthMessages. To do
+ * this, we need to figure out:
+ *
+ * - what consumer key/secret to use for signing.
+ * - if an access token should be used for the request, and if so what it is. *
+ * - the OAuth request/authorization/access URLs.
+ * - what HTTP method to use for request token and access token requests
+ * - where the OAuth parameters are located.
+ *
+ * Note that most of that work gets skipped for signed fetch, we just look up the consumer key
+ * and secret for that. Signed fetch always sticks the parameters in the query string.
*/
- public void storeTokenKeyAndSecret(OAuthStore.TokenKey tokenKey,
- OAuthStore.TokenInfo tokenInfo)
- throws OAuthStoreException {
+ public AccessorInfo getOAuthAccessor(SecurityToken securityToken,
+ OAuthArguments arguments, OAuthClientState clientState) throws GadgetException {
+
+ AccessorInfoBuilder accessorBuilder = new AccessorInfoBuilder();
- if (isEmpty(tokenKey.getGadgetUri())) {
- throw new IllegalArgumentException("found empty gadget URI in TokenKey");
+ // Does the gadget spec tell us any details about the service provider, like where to put the
+ // OAuth parameters and what methods to use for their URLs?
+ OAuthServiceProvider provider = null;
+ if (arguments.mayUseToken()) {
+ provider = lookupSpecInfo(securityToken, arguments, accessorBuilder);
+ } else {
+ // This is plain old signed fetch.
+ accessorBuilder.setParameterLocation(AccessorInfo.OAuthParamLocation.URI_QUERY);
}
-
- if (isEmpty(tokenKey.getUserId())) {
- throw new IllegalArgumentException("found empty userId in TokenKey");
+
+ // What consumer key/secret should we use?
+ ConsumerInfo consumer = store.getConsumerKeyAndSecret(
+ securityToken, arguments.getServiceName(), provider);
+ accessorBuilder.setConsumer(consumer);
+
+ // Should we use the OAuth access token? We never do this unless the client allows it, and
+ // if owner == viewer.
+ if (arguments.mayUseToken()
+ && securityToken.getOwnerId() != null
+ && securityToken.getViewerId().equals(securityToken.getOwnerId())) {
+ lookupToken(securityToken, consumer, arguments, clientState, accessorBuilder);
+ }
+
+ return accessorBuilder.create();
+ }
+
+ /**
+ * Lookup information contained in the gadget spec.
+ */
+ private OAuthServiceProvider lookupSpecInfo(SecurityToken securityToken, OAuthArguments arguments,
+ AccessorInfoBuilder accessorBuilder) throws GadgetException {
+ GadgetSpec spec = findSpec(securityToken, arguments);
+ OAuthSpec oauthSpec = spec.getModulePrefs().getOAuthSpec();
+ if (oauthSpec == null) {
+ throw oauthNotFoundEx(securityToken);
}
-
- store.setTokenAndSecret(tokenKey, tokenInfo);
- }
-
- /**
- * Removes an access token from the OAuth data store.
- *
- * @return true if the token is removed, false if the token was not found.
- * @throws OAuthStoreException if we can't communicate with the token store.
- */
- public boolean removeToken(OAuthStore.TokenKey tokenKey)
- throws OAuthStoreException {
- try {
- store.removeToken(tokenKey);
- return true;
- } catch (OAuthNoDataException e) {
- return false;
+ OAuthService service = oauthSpec.getServices().get(arguments.getServiceName());
+ if (service == null) {
+ throw serviceNotFoundEx(securityToken, oauthSpec, arguments.getServiceName());
}
+ // In theory some one could specify different parameter locations for request token and
+ // access token requests, but that's probably not useful. We just use the request token
+ // rules for everything.
+ accessorBuilder.setParameterLocation(getStoreLocation(service.getRequestUrl().location));
+ accessorBuilder.setMethod(getStoreMethod(service.getRequestUrl().method));
+ OAuthServiceProvider provider = new OAuthServiceProvider(
+ service.getRequestUrl().url.toASCIIString(),
+ service.getAuthorizationUrl().toASCIIString(),
+ service.getAccessUrl().url.toASCIIString());
+ return provider;
}
-
+
/**
- * Retrieve an OAuthAccessor that is ready to sign OAuthMessages.
- *
- * @param tokenKey information about the gadget retrieving the accessor.
- *
- * @return an OAuthAccessorInfo containing an OAuthAccessor (which can be
- * passed to an OAuthMessage.sign method), as well as httpMethod and
- * signatureType fields.
- * @throws OAuthNoDataException if the token couldn't be found
- * @throws OAuthStoreException if an error occurred accessing the data
- * store.
+ * Figure out the OAuth token that should be used with this request. We check for this in three
+ * places. In order of priority:
+ *
+ * 1) From information we cached on the client.
+ * We encrypt the token and cache on the client for performance.
+ *
+ * 2) From information we have in our persistent state.
+ * We persist the token server-side so we can look it up if necessary.
+ *
+ * 3) From information the gadget developer tells us to use (a preapproved request token.)
+ * Gadgets can be initialized with preapproved request tokens. If the user tells the service
+ * provider they want to add a gadget to a gadget container site, the service provider can
+ * create a preapproved request token for that site and pass it to the gadget as a user
+ * preference.
+ * @throws GadgetException
*/
- public OAuthStore.AccessorInfo getOAuthAccessor(OAuthStore.TokenKey tokenKey,
- boolean bypassSpecCache)
+ private void lookupToken(SecurityToken securityToken, ConsumerInfo consumerInfo,
+ OAuthArguments arguments, OAuthClientState clientState, AccessorInfoBuilder accessorBuilder)
throws GadgetException {
-
- if (isEmpty(tokenKey.getGadgetUri())) {
- throw new OAuthStoreException("found empty gadget URI in TokenKey");
+ if (clientState.getRequestToken() != null) {
+ // We cached the request token on the client.
+ accessorBuilder.setRequestToken(clientState.getRequestToken());
+ accessorBuilder.setTokenSecret(clientState.getRequestTokenSecret());
+ } else if (clientState.getAccessToken() != null) {
+ // We cached the access token on the client
+ accessorBuilder.setAccessToken(clientState.getAccessToken());
+ accessorBuilder.setTokenSecret(clientState.getAccessTokenSecret());
+ } else {
+ // No useful client-side state, check persistent storage
+ TokenInfo tokenInfo = store.getTokenInfo(securityToken, consumerInfo,
+ arguments.getServiceName(), arguments.getTokenName());
+ if (tokenInfo != null && tokenInfo.getAccessToken() != null) {
+ // We have an access token in persistent storage, use that.
+ accessorBuilder.setAccessToken(tokenInfo.getAccessToken());
+ accessorBuilder.setTokenSecret(tokenInfo.getTokenSecret());
+ } else {
+ // We don't have an access token yet, but the client sent us a (hopefully) preapproved
+ // request token.
+ accessorBuilder.setRequestToken(arguments.getRequestToken());
+ accessorBuilder.setTokenSecret(arguments.getRequestTokenSecret());
+ }
}
+ }
- if (isEmpty(tokenKey.getUserId())) {
- throw new OAuthStoreException("found empty userId in TokenKey");
+ private OAuthParamLocation getStoreLocation(Location location) throws GadgetException {
+ switch(location) {
+ case HEADER:
+ return OAuthParamLocation.AUTH_HEADER;
+ case URL:
+ return OAuthParamLocation.URI_QUERY;
+ case BODY:
+ return OAuthParamLocation.POST_BODY;
+ }
+ throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR,
+ "Unknown parameter location " + location);
+ }
+
+ private HttpMethod getStoreMethod(Method method) throws GadgetException {
+ switch(method) {
+ case GET:
+ return HttpMethod.GET;
+ case POST:
+ return HttpMethod.POST;
}
+ throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR,
+ "Unknown method " + method);
+ }
- GadgetSpec spec;
+ private GadgetSpec findSpec(SecurityToken securityToken, OAuthArguments arguments)
+ throws GadgetException {
try {
- spec = specFactory.getGadgetSpec(
- new URI(tokenKey.getGadgetUri()),
- bypassSpecCache);
+ return specFactory.getGadgetSpec(
+ new URI(securityToken.getAppUrl()),
+ arguments.getBypassSpecCache());
} catch (URISyntaxException e) {
- throw new OAuthStoreException("could not fetch gadget spec, gadget URI " +
- "invalid", e);
+ throw new OAuthStoreException("could not fetch gadget spec, gadget URI invalid", e);
}
-
- OAuthStore.ProviderInfo provInfo;
- provInfo = getProviderInfo(spec, tokenKey.getServiceName());
-
- return store.getOAuthAccessor(tokenKey, provInfo);
+ }
+
+ private GadgetException serviceNotFoundEx(SecurityToken securityToken, OAuthSpec oauthSpec,
+ String serviceName) {
+ StringBuilder message = new StringBuilder()
+ .append("Spec for gadget ")
+ .append(securityToken.getAppUrl())
+ .append(" does not contain OAuth service ")
+ .append(serviceName)
+ .append(". Known services: ")
+ .append(StringUtils.join(oauthSpec.getServices().keySet(), ','));
+ return new GadgetException(GadgetException.Code.INVALID_PARAMETER,
+ message.toString());
}
+ private GadgetException oauthNotFoundEx(SecurityToken securityToken) {
+ StringBuilder message = new StringBuilder()
+ .append("Spec for gadget ")
+ .append(securityToken.getAppUrl())
+ .append(" does not contain OAuth element.");
+ return new GadgetException(GadgetException.Code.INVALID_PARAMETER,
+ message.toString());
+ }
+
/**
- * Reads OAuth provider information out of gadget spec.
- * @param spec
- * @return a GadgetInfo
- * @throws GadgetException if some information is missing, or something else
- * is wrong with the spec.
+ * Store an access token for the given user/gadget/service/token name
*/
- public static OAuthStore.ProviderInfo getProviderInfo(
- GadgetSpec spec, String serviceName) throws GadgetException {
-
- OAuthSpec oauthSpec = spec.getModulePrefs().getOAuthSpec();
-
- if (oauthSpec == null) {
- String message = "gadget spec is missing /ModulePrefs/OAuth section";
- log.warning(message);
- throw new GadgetException(GadgetException.Code.MISSING_PARAMETER,
- message);
- }
-
- OAuthService service = oauthSpec.getServices().get(serviceName);
- if (service == null) {
- StringBuilder message = new StringBuilder();
- message.append("Spec does not contain OAuth service '");
- message.append(serviceName);
- message.append("'. Known services: ");
- Iterator<String> known = oauthSpec.getServices().keySet().iterator();
- while (known.hasNext()) {
- message.append('\'');
- message.append(known.next());
- message.append('\'');
- if (known.hasNext()) {
- message.append(", ");
- }
- }
- log.warning(message.toString());
- throw new GadgetException(GadgetException.Code.INVALID_PARAMETER,
- message.toString());
- }
-
- OAuthServiceProvider provider = new OAuthServiceProvider(
- service.getRequestUrl().url.toASCIIString(),
- service.getAuthorizationUrl().toASCIIString(),
- service.getAccessUrl().url.toASCIIString());
-
- OAuthStore.HttpMethod httpMethod;
- switch(service.getRequestUrl().method) {
- case GET:
- httpMethod = OAuthStore.HttpMethod.GET;
- break;
- case POST:
- default:
- httpMethod = OAuthStore.HttpMethod.POST;
- break;
- }
-
- OAuthStore.OAuthParamLocation paramLocation;
- switch(service.getRequestUrl().location) {
- case URL:
- paramLocation = OAuthStore.OAuthParamLocation.URI_QUERY;
- break;
- case BODY:
- paramLocation = OAuthStore.OAuthParamLocation.POST_BODY;
- break;
- case HEADER:
- default:
- paramLocation = OAuthStore.OAuthParamLocation.AUTH_HEADER;
- break;
- }
-
- OAuthStore.ProviderInfo provInfo = new OAuthStore.ProviderInfo();
- provInfo.setHttpMethod(httpMethod);
- provInfo.setParamLocation(paramLocation);
-
- // TODO: for now, we'll just set the signature type to HMAC_SHA1
- // as this will be ignored later on when retrieving consumer information.
- // There, if we find a negotiated HMAC key, we will use HMAC_SHA1. If we
- // find a negotiated RSA key, we will use RSA_SHA1. And if we find neither,
- // we may use RSA_SHA1 with a default signing key.
- provInfo.setSignatureType(OAuthStore.SignatureType.HMAC_SHA1);
- provInfo.setProvider(provider);
-
- return provInfo;
+ public void storeTokenKeyAndSecret(SecurityToken securityToken, ConsumerInfo consumerInfo,
+ OAuthArguments arguments, TokenInfo tokenInfo) throws GadgetException {
+ store.setTokenInfo(securityToken, consumerInfo, arguments.getServiceName(),
+ arguments.getTokenName(), tokenInfo);
}
- static boolean isEmpty(String string) {
- return (string == null) || (string.trim().length() == 0);
+ /**
+ * Remove an access token for the given user/gadget/service/token name
+ */
+ public void removeToken(SecurityToken securityToken, ConsumerInfo consumerInfo,
+ OAuthArguments arguments) throws GadgetException {
+ store.removeToken(securityToken, consumerInfo, arguments.getServiceName(),
+ arguments.getTokenName());
}
}
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthArguments.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthArguments.java?rev=693675&r1=693674&r2=693675&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthArguments.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthArguments.java Tue Sep 9 18:50:41 2008
@@ -18,10 +18,13 @@
*/
package org.apache.shindig.gadgets.oauth;
-import org.apache.shindig.gadgets.spec.RequestAuthenticationInfo;
+import com.google.common.collect.Maps;
+
+import org.apache.shindig.gadgets.GadgetException;
+import org.apache.shindig.gadgets.spec.Auth;
+import org.apache.shindig.gadgets.spec.Preload;
import java.util.Map;
-import java.util.TreeMap;
import javax.servlet.http.HttpServletRequest;
@@ -29,93 +32,242 @@
* Arguments to an OAuth fetch sent by the client.
*/
public class OAuthArguments {
- public static final String SERVICE_PARAM = "OAUTH_SERVICE_NAME";
- public static final String TOKEN_PARAM = "OAUTH_TOKEN_NAME";
- public static final String REQUEST_TOKEN_PARAM = "OAUTH_REQUEST_TOKEN";
- public static final String REQUEST_TOKEN_SECRET_PARAM =
- "OAUTH_REQUEST_TOKEN_SECRET";
- public static final String CLIENT_STATE_PARAM = "oauthState";
- public static final String BYPASS_SPEC_CACHE_PARAM = "bypassSpecCache";
-
- protected String serviceName;
- protected String tokenName;
- protected String requestToken;
- protected String requestTokenSecret;
- protected String origClientState;
- protected boolean bypassSpecCache;
-
- @SuppressWarnings("unchecked")
- public OAuthArguments(HttpServletRequest request) {
- Map<String, String> params = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
- Map<String, String[]> reqParams = request.getParameterMap();
- for (String name : reqParams.keySet()) {
- params.put(name, reqParams.get(name)[0]);
- }
- init(params);
- }
-
- public OAuthArguments(RequestAuthenticationInfo request) {
- Map<String, String> attrs = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
- attrs.putAll(request.getAttributes());
- init(attrs);
- }
-
- private void init(Map<String, String> attrs) {
- serviceName = getParam(attrs, SERVICE_PARAM, "");
- tokenName = getParam(attrs, TOKEN_PARAM, "");
- requestToken = getParam(attrs, REQUEST_TOKEN_PARAM, null);
- requestTokenSecret = getParam(attrs, REQUEST_TOKEN_SECRET_PARAM, null);
- origClientState = getParam(attrs, CLIENT_STATE_PARAM, null);
- bypassSpecCache = "1".equals(getParam(attrs, BYPASS_SPEC_CACHE_PARAM, null));
+ private static final String SERVICE_PARAM = "OAUTH_SERVICE_NAME";
+ private static final String TOKEN_PARAM = "OAUTH_TOKEN_NAME";
+ private static final String REQUEST_TOKEN_PARAM = "OAUTH_REQUEST_TOKEN";
+ private static final String REQUEST_TOKEN_SECRET_PARAM = "OAUTH_REQUEST_TOKEN_SECRET";
+ private static final String USE_TOKEN_PARAM = "OAUTH_USE_TOKEN";
+ private static final String CLIENT_STATE_PARAM = "oauthState";
+ private static final String BYPASS_SPEC_CACHE_PARAM = "bypassSpecCache";
+ private static final String SIGN_OWNER_PARAM = "signOwner";
+ private static final String SIGN_VIEWER_PARAM = "signViewer";
+
+ /**
+ * Should the OAuth access token be used?
+ */
+ public static enum UseToken {
+ /** Do not use the OAuth access token */
+ NEVER,
+ /** Use the access token if it exists already, but don't prompt for permission */
+ IF_AVAILABLE,
+ /** Use the access token if it exists, and prompt if it doesn't */
+ ALWAYS,
+ }
+
+ /** Should we attempt to use an access token for the request */
+ private UseToken useToken = UseToken.ALWAYS;
+
+ /** OAuth service nickname. Signed fetch uses the empty string */
+ private String serviceName = "";
+
+ /** OAuth token nickname. Signed fetch uses the empty string */
+ private String tokenName = "";
+
+ /** Request token the client wants us to use, may be null */
+ private String requestToken = null;
+
+ /** Token secret that goes with the request token */
+ private String requestTokenSecret = null;
+
+ /** Encrypted state blob stored on the client */
+ private String origClientState = null;
+
+ /** Whether we should bypass the gadget spec cache */
+ private boolean bypassSpecCache = false;
+
+ /** Include information about the owner? */
+ private boolean signOwner = false;
+
+ /** Include information about the viewer? */
+ private boolean signViewer = false;
+
+ /**
+ * Parse OAuthArguments from parameters to the makeRequest servlet.
+ *
+ * @param auth authentication type for the request
+ * @param request servlet request
+ * @throws GadgetException if any parameters are invalid.
+ */
+ public OAuthArguments(Auth auth, HttpServletRequest request) throws GadgetException {
+ useToken = parseUseToken(auth, getRequestParam(request, USE_TOKEN_PARAM, ""));
+ serviceName = getRequestParam(request, SERVICE_PARAM, "");
+ tokenName = getRequestParam(request, TOKEN_PARAM, "");
+ requestToken = getRequestParam(request, REQUEST_TOKEN_PARAM, null);
+ requestTokenSecret = getRequestParam(request, REQUEST_TOKEN_SECRET_PARAM, null);
+ origClientState = getRequestParam(request, CLIENT_STATE_PARAM, null);
+ bypassSpecCache = "1".equals(getRequestParam(request, BYPASS_SPEC_CACHE_PARAM, null));
+ signOwner = Boolean.parseBoolean(getRequestParam(request, SIGN_OWNER_PARAM, "true"));
+ signViewer = Boolean.parseBoolean(getRequestParam(request, SIGN_VIEWER_PARAM, "true"));
+ }
+
+ public OAuthArguments(Preload preload) throws GadgetException {
+ Map<String, String> attrs = Maps.newTreeMap(String.CASE_INSENSITIVE_ORDER);
+ attrs.putAll(preload.getAttributes());
+ useToken = parseUseToken(preload.getAuthType(), getPreloadParam(attrs, USE_TOKEN_PARAM, ""));
+ serviceName = getPreloadParam(attrs, SERVICE_PARAM, "");
+ tokenName = getPreloadParam(attrs, TOKEN_PARAM, "");
+ requestToken = getPreloadParam(attrs, REQUEST_TOKEN_PARAM, null);
+ requestTokenSecret = getPreloadParam(attrs, REQUEST_TOKEN_SECRET_PARAM, null);
+ origClientState = null;
+ bypassSpecCache = false;
+ signOwner = preload.isSignOwner();
+ signViewer = preload.isSignViewer();
+ }
+
+ /**
+ * @return the named attribute from the Preload tag attributes, or default if the attribute is
+ * not present.
+ */
+ private String getPreloadParam(Map<String, String> attrs, String name, String def) {
+ String val = attrs.get(name);
+ if (val == null) {
+ val = def;
+ }
+ return val;
}
- private String getParam(Map<String, String> attrs, String name, String def) {
- String val = attrs.get(name);
+ /**
+ * @return the named parameter from the request, or default if the named parameter is not present.
+ */
+ private static String getRequestParam(HttpServletRequest request, String name, String def) {
+ String val = request.getParameter(name);
if (val == null) {
val = def;
}
return val;
}
- // Testing only
- public OAuthArguments(String serviceName, String tokenName,
- String origClientState, boolean bypassSpecCache) {
- this(serviceName, tokenName, origClientState, bypassSpecCache, null, null);
+
+ /**
+ * Figure out what the client wants us to do with the OAuth access token.
+ */
+ private static UseToken parseUseToken(Auth auth, String useTokenStr) throws GadgetException {
+ if (useTokenStr.length() == 0) {
+ if (auth == Auth.SIGNED) {
+ // signed fetch defaults to not using the token
+ return UseToken.NEVER;
+ } else {
+ // OAuth defaults to always using it.
+ return UseToken.ALWAYS;
+ }
+ }
+ useTokenStr = useTokenStr.toLowerCase();
+ if ("always".equals(useTokenStr)) {
+ return UseToken.ALWAYS;
+ }
+ if ("if_available".equals(useTokenStr)) {
+ return UseToken.IF_AVAILABLE;
+ }
+ if ("never".equals(useTokenStr)) {
+ return UseToken.NEVER;
+ }
+ throw new GadgetException(GadgetException.Code.INVALID_PARAMETER,
+ "Unknown use token value " + useTokenStr);
+ }
+
+ /**
+ * Create an OAuthArguments object with all default values. The details can be filled in later
+ * using the setters.
+ *
+ * Be careful using this in anything except test code. If you find yourself wanting to use this
+ * method in real code, consider writing a new constructor instead.
+ */
+ public OAuthArguments() {
+ }
+
+
+ /**
+ * Copy constructor.
+ */
+ public OAuthArguments(OAuthArguments orig) {
+ useToken = orig.useToken;
+ serviceName = orig.serviceName;
+ tokenName = orig.tokenName;
+ requestToken = orig.requestToken;
+ requestTokenSecret = orig.requestTokenSecret;
+ origClientState = orig.origClientState;
+ bypassSpecCache = orig.bypassSpecCache;
+ signOwner = orig.signOwner;
+ signViewer = orig.signViewer;
+ }
+
+ public boolean mustUseToken() {
+ return (useToken == UseToken.ALWAYS);
+ }
+
+ public boolean mayUseToken() {
+ return (useToken == UseToken.IF_AVAILABLE || useToken == UseToken.ALWAYS);
}
- // Testing only
- public OAuthArguments(String serviceName, String tokenName,
- String origClientState, boolean bypassSpecCache, String requestToken,
- String requestTokenSecret) {
- this.serviceName = serviceName;
- this.tokenName = tokenName;
- this.requestToken = requestToken;
- this.requestTokenSecret = requestTokenSecret;
- this.origClientState = origClientState;
- this.bypassSpecCache = bypassSpecCache;
+ public UseToken getUseToken() {
+ return useToken;
+ }
+
+ public void setUseToken(UseToken useToken) {
+ this.useToken = useToken;
}
public String getServiceName() {
return serviceName;
}
+ public void setServiceName(String serviceName) {
+ this.serviceName = serviceName;
+ }
+
public String getTokenName() {
return tokenName;
}
+ public void setTokenName(String tokenName) {
+ this.tokenName = tokenName;
+ }
+
+ public String getRequestToken() {
+ return requestToken;
+ }
+
+ public void setRequestToken(String requestToken) {
+ this.requestToken = requestToken;
+ }
+
+ public String getRequestTokenSecret() {
+ return requestTokenSecret;
+ }
+
+ public void setRequestTokenSecret(String requestTokenSecret) {
+ this.requestTokenSecret = requestTokenSecret;
+ }
+
public String getOrigClientState() {
return origClientState;
}
+ public void setOrigClientState(String origClientState) {
+ this.origClientState = origClientState;
+ }
+
public boolean getBypassSpecCache() {
return bypassSpecCache;
}
- public String getRequestToken() {
- return requestToken;
+ public void setBypassSpecCache(boolean bypassSpecCache) {
+ this.bypassSpecCache = bypassSpecCache;
}
- public String getRequestTokenSecret() {
- return requestTokenSecret;
+ public boolean getSignOwner() {
+ return signOwner;
+ }
+
+ public void setSignOwner(boolean signOwner) {
+ this.signOwner = signOwner;
+ }
+
+ public boolean getSignViewer() {
+ return signViewer;
+ }
+
+ public void setSignViewer(boolean signViewer) {
+ this.signViewer = signViewer;
}
}