You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@shindig.apache.org by et...@apache.org on 2008/04/05 06:37:59 UTC
svn commit: r645027 [2/2] - in /incubator/shindig/trunk: config/
features/core.io/ java/gadgets/
java/gadgets/src/main/java/org/apache/shindig/gadgets/
java/gadgets/src/main/java/org/apache/shindig/gadgets/http/
java/gadgets/src/main/java/org/apache/sh...
Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthNoDataException.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthNoDataException.java?rev=645027&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthNoDataException.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthNoDataException.java Fri Apr 4 21:37:53 2008
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package org.apache.shindig.gadgets.oauth;
+
+/**
+ * Exception thrown when a lookup found no data in the OAuth store.
+ */
+public class OAuthNoDataException extends OAuthStoreException {
+
+ public OAuthNoDataException(String message) {
+ super(message);
+ }
+}
Added: 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=645027&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthRequestParams.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthRequestParams.java Fri Apr 4 21:37:53 2008
@@ -0,0 +1,52 @@
+/*
+ * 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 javax.servlet.http.HttpServletRequest;
+
+/**
+ * Bundles information about a proxy request that requires OAuth
+ */
+public class OAuthRequestParams {
+ public static final String SERVICE_PARAM = "oauthService";
+ 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;
+
+ public OAuthRequestParams(HttpServletRequest request) {
+ serviceName = request.getParameter(SERVICE_PARAM);
+ tokenName = request.getParameter(TOKEN_PARAM);
+ origClientState = request.getParameter(CLIENT_STATE_PARAM);
+ }
+
+ public String getServiceName() {
+ return serviceName;
+ }
+
+ public String getTokenName() {
+ return tokenName;
+ }
+
+ public String getOrigClientState() {
+ return origClientState;
+ }
+}
Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthStore.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthStore.java?rev=645027&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthStore.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthStore.java Fri Apr 4 21:37:53 2008
@@ -0,0 +1,370 @@
+/*
+ * 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 net.oauth.OAuthServiceProvider;
+
+/**
+ * Interface to an OAuth Data Store. A shindig gadget server can act as an
+ * OAuth consumer, using OAuth tokens to talk to OAuth service providers on
+ * behalf of the gadgets it is proxying requests for. An OAuth consumer needs
+ * to permanently store gadgets it has collected, and retrieve the
+ * appropriate tokens when proxying a request for a gadget.
+ *
+ * An OAuth Data Store stores three things:
+ * (1) information about OAuth service providers, including the three
+ * URLs that define OAuth providers (defined in OAuthStore.ProviderInfo)
+ * (2) information about consumer keys and secrets that gadgets might have
+ * negotiated with OAuth service providers, or that containers might have
+ * negotiated on behalf of the gadgets. This information is bound to
+ * the service provider it pertains to and can only be stored if the
+ * corresponding service provider information is already stored in the
+ * OAuth store (defined in OAuthStore.ConsumerKeyAndSecret).
+ * (3) OAuth access tokens and their corresponding token secrets. (defined
+ * in OAuthStore.TokenInfo).
+ *
+ * Note that we do not store request tokens in the OAuth store.
+ */
+public interface OAuthStore {
+
+ /**
+ * Set information about a service provider, as it is known to a certain
+ * gadget.
+ *
+ * @param providerKey the gadget that wants to use the service provider, and
+ * a nickName under which the gadget will refer to this
+ * service provider in the future.
+ * @param providerInfo the three URLs that define this provider. Also
+ * contains the httpMethod used to access the service
+ * provider. (Technically, OAuth allows different methods
+ * for the different URLs, but the Java OAuth library
+ * doesn't support that. So we're also just storing one
+ * preference here.) Also contains the signature type
+ * (RSA, HMAC, or PLAINTEXT) to be
+ * used for this service provider. (Again, OAuth allows
+ * different signature types for each of the three
+ * URLs, but we just assume they're all the same, and
+ * provide just one parameter to specify signature type.)
+ * @throws OAuthStoreException if there was a problem accessing the
+ * store.
+ */
+ public void setOAuthServiceProviderInfo(ProviderKey providerKey,
+ ProviderInfo providerInfo)
+ throws OAuthStoreException;
+
+ /**
+ * Gets information about a service provider (access, request, and authorize
+ * URLs with access methods and signature types), given a gadget description
+ * and a service name.
+ *
+ * @param providerKey the gadget that wants to use the service provider, and
+ * a nickName under which the gadget refers to this
+ * service provider.
+ * @return the provider information.
+ * @throws OAuthStoreException
+ * @throws OAuthNoDataException
+ */
+ public ProviderInfo getOAuthServiceProviderInfo(ProviderKey providerKey)
+ throws OAuthStoreException, OAuthNoDataException;
+
+ /**
+ * If we or a gadget negotiate a separate consumer key and secret with a
+ * service provider, use this method to store it. The "secret" can either
+ * be a consumer secret in the strict OAuth sense, or it can be a
+ * PKCS8-then-Base64 encoded private key that we'll be using with this
+ * service provider. Even if we never set a consumer secret, an implementation
+ * of this interface may still be able to return useful OAuthAccessors in
+ * the getOAuthAccessor method, e.g. by returning a fallback private key and
+ * default consumer key, which could be used with service providers that we
+ * haven't negotiated a consumer secret with.
+ *
+ * @param providerKey the gadget that wants to use the service provider, and
+ * a nickName under which the gadget will refer to this
+ * service provider in the future.
+ * @param keyAndSecret the consumer key and secret. If the secret is an RSA
+ * private key, it must be PKCS8-then-Base64 encoded.
+ * @throws OAuthStoreException if something goes wrong accessing the
+ * data store.
+ * @throws OAuthNoDataException if no provider info can be found for the
+ * provider specified in the providerKey.
+ */
+ public void setOAuthConsumerKeyAndSecret(ProviderKey providerKey,
+ ConsumerKeyAndSecret keyAndSecret)
+ throws OAuthStoreException, OAuthNoDataException;
+
+ /**
+ * Stores an access token.
+ * @param tokenKey a structure uniquely identifying the key under which this
+ * access token should be retrievable: a userId, a gadgetId,
+ * a moduleId (in case there are more than one gadget of the
+ * same type on a page), a tokenName (which distinguishes
+ * this token from others that the same gadget might hold for
+ * the same service provider) and a serviceName (which is the
+ * same as the service name in the ProviderKey structure).
+ * @param tokenInfo an access token and token secret.
+ * @throws OAuthStoreException if an error occurs talking to the
+ * data store.
+ */
+ public void setTokenAndSecret(TokenKey tokenKey, TokenInfo tokenInfo)
+ throws OAuthStoreException;
+
+ /**
+ * Retrieve an OAuthAccessor that is ready to sign OAuthMessages for
+ * resource access.
+ * @param tokenKey a structure uniquely identifying the token: a userId,
+ * a gadgetId, a moduleId (in case there are more than one
+ * gadget of the same type on a page), a tokenName (which
+ * distinguishes this token from others that the same gadget
+ * might hold for the same service provider) and a serviceName
+ * (which is the same as the service name in the ProviderKey
+ * structure).
+ * @return an OAuthAccessor object than can be passed to an OAuthMessage.sign
+ * method.
+ * @throws OAuthNoDataException if the token couldn't be found
+ * @throws OAuthStoreException if an error occurred accessing the data
+ * store.
+ */
+ public AccessorInfo getOAuthAccessor(TokenKey tokenKey)
+ throws OAuthNoDataException, OAuthStoreException;
+
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Auxiliary types needed to work with this interface
+ //////////////////////////////////////////////////////////////////////////////
+
+ public static enum HttpMethod { GET, POST }
+ public static enum SignatureType {HMAC_SHA1, RSA_SHA1, PLAINTEXT}
+ public static enum KeyType { HMAC_SYMMETRIC, RSA_PRIVATE }
+
+ public static class AccessorInfo {
+ OAuthAccessor accessor;
+ HttpMethod httpMethod;
+ SignatureType signatureType;
+ public OAuthAccessor getAccessor() {
+ return accessor;
+ }
+ public void setAccessor(OAuthAccessor accessor) {
+ this.accessor = accessor;
+ }
+ public HttpMethod getHttpMethod() {
+ return httpMethod;
+ }
+ public void setHttpMethod(HttpMethod httpMethod) {
+ this.httpMethod = httpMethod;
+ }
+ public SignatureType getSignatureType() {
+ return signatureType;
+ }
+ public void setSignatureType(SignatureType signatureType) {
+ this.signatureType = signatureType;
+ }
+ }
+
+ public static class ConsumerKeyAndSecret {
+ private String consumerKey;
+ private String consumerSecret;
+ private KeyType keyType;
+
+ public ConsumerKeyAndSecret(String key, String secret, KeyType type) {
+ consumerKey = key;
+ consumerSecret = secret;
+ keyType = type;
+ }
+ public String getConsumerKey() {
+ return consumerKey;
+ }
+ public String getConsumerSecret() {
+ return consumerSecret;
+ }
+ public KeyType getKeyType() {
+ return keyType;
+ }
+ }
+
+ public static class ProviderKey {
+ private String gadgetUri;
+ private String serviceName;
+
+ public String getGadgetUri() {
+ return gadgetUri;
+ }
+ public void setGadgetUri(String gadgetUri) {
+ this.gadgetUri = gadgetUri;
+ }
+ public String getServiceName() {
+ return serviceName;
+ }
+ public void setServiceName(String serviceName) {
+ this.serviceName = serviceName;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result =
+ prime * result + ((gadgetUri == null) ? 0 : gadgetUri.hashCode());
+ result =
+ prime * result + ((serviceName == null) ? 0 : serviceName.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (getClass() != obj.getClass()) return false;
+ final ProviderKey other = (ProviderKey) obj;
+ if (gadgetUri == null) {
+ if (other.gadgetUri != null) return false;
+ } else if (!gadgetUri.equals(other.gadgetUri)) return false;
+ if (serviceName == null) {
+ if (other.serviceName != null) return false;
+ } else if (!serviceName.equals(other.serviceName)) return false;
+ return true;
+ }
+ }
+
+ public static class ProviderInfo {
+ private OAuthServiceProvider provider;
+ private HttpMethod httpMethod;
+ private SignatureType signatureType;
+
+ // this can be null if we have not negotiated a consumer key and secret
+ // yet with the provider, or if we decided that we want to use a global
+ // public key
+ private ConsumerKeyAndSecret keyAndSecret;
+
+ public ConsumerKeyAndSecret getKeyAndSecret() {
+ return keyAndSecret;
+ }
+ public void setKeyAndSecret(ConsumerKeyAndSecret keyAndSecret) {
+ this.keyAndSecret = keyAndSecret;
+ }
+ public OAuthServiceProvider getProvider() {
+ return provider;
+ }
+ public void setProvider(OAuthServiceProvider provider) {
+ this.provider = provider;
+ }
+ public HttpMethod getHttpMethod() {
+ return httpMethod;
+ }
+ public void setHttpMethod(HttpMethod httpMethod) {
+ this.httpMethod = httpMethod;
+ }
+ public SignatureType getSignatureType() {
+ return signatureType;
+ }
+ public void setSignatureType(SignatureType signatureType) {
+ this.signatureType = signatureType;
+ }
+ }
+
+ public static class TokenKey {
+ private String userId;
+ private String gadgetUri;
+ private long moduleId;
+ private String tokenName;
+ private String serviceName;
+
+ public String getUserId() {
+ return userId;
+ }
+ public void setUserId(String userId) {
+ this.userId = userId;
+ }
+ public String getGadgetUri() {
+ return gadgetUri;
+ }
+ public void setGadgetUri(String gadgetUri) {
+ this.gadgetUri = gadgetUri;
+ }
+ public long getModuleId() {
+ return moduleId;
+ }
+ public void setModuleId(long moduleId) {
+ this.moduleId = moduleId;
+ }
+ public String getTokenName() {
+ return tokenName;
+ }
+ public void setTokenName(String tokenName) {
+ this.tokenName = tokenName;
+ }
+ public String getServiceName() {
+ return serviceName;
+ }
+ public void setServiceName(String serviceName) {
+ this.serviceName = serviceName;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result =
+ prime * result + ((gadgetUri == null) ? 0 : gadgetUri.hashCode());
+ result = prime * result + (int) (moduleId ^ (moduleId >>> 32));
+ result =
+ prime * result + ((serviceName == null) ? 0 : serviceName.hashCode());
+ result =
+ prime * result + ((tokenName == null) ? 0 : tokenName.hashCode());
+ result = prime * result + ((userId == null) ? 0 : userId.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (getClass() != obj.getClass()) return false;
+ final TokenKey other = (TokenKey) obj;
+ if (gadgetUri == null) {
+ if (other.gadgetUri != null) return false;
+ } else if (!gadgetUri.equals(other.gadgetUri)) return false;
+ if (moduleId != other.moduleId) return false;
+ if (serviceName == null) {
+ if (other.serviceName != null) return false;
+ } else if (!serviceName.equals(other.serviceName)) return false;
+ if (tokenName == null) {
+ if (other.tokenName != null) return false;
+ } else if (!tokenName.equals(other.tokenName)) return false;
+ if (userId == null) {
+ if (other.userId != null) return false;
+ } else if (!userId.equals(other.userId)) return false;
+ return true;
+ }
+ }
+
+ public static class TokenInfo {
+ private String accessToken;
+ private String tokenSecret;
+ public TokenInfo(String token, String secret) {
+ accessToken = token;
+ tokenSecret = secret;
+ }
+ public String getAccessToken() {
+ return accessToken;
+ }
+ public String getTokenSecret() {
+ return tokenSecret;
+ }
+ }
+}
Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthStoreException.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthStoreException.java?rev=645027&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthStoreException.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/oauth/OAuthStoreException.java Fri Apr 4 21:37:53 2008
@@ -0,0 +1,39 @@
+/*
+ * 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 org.apache.shindig.gadgets.GadgetException;
+
+/**
+ * Base class of exception that can be thrown when interacting with the
+ * OAuthStore.
+ */
+public class OAuthStoreException extends GadgetException {
+
+ public OAuthStoreException(String message) {
+ super(GadgetException.Code.OAUTH_STORAGE_ERROR, message);
+ }
+
+ public OAuthStoreException(String message, Throwable cause) {
+ super(GadgetException.Code.OAUTH_STORAGE_ERROR, message, cause);
+ }
+
+ public OAuthStoreException(Throwable cause) {
+ super(GadgetException.Code.OAUTH_STORAGE_ERROR, cause);
+ }
+}
Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/BasicBlobCrypter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/BasicBlobCrypter.java?rev=645027&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/BasicBlobCrypter.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/BasicBlobCrypter.java Fri Apr 4 21:37:53 2008
@@ -0,0 +1,186 @@
+/*
+ * 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.util;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.digest.DigestUtils;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.security.GeneralSecurityException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Simple implementation of BlobCrypter.
+ */
+public class BasicBlobCrypter implements BlobCrypter {
+
+ // Labels for key derivation
+ private static final byte CIPHER_KEY_LABEL = 0;
+ private static final byte HMAC_KEY_LABEL = 1;
+
+ /** Key used for time stamp (in seconds) of data */
+ public static final String TIMESTAMP_KEY = "t";
+
+ /** minimum length of master key */
+ public static final int MASTER_KEY_MIN_LEN = 16;
+
+ /** allow three minutes for clock skew */
+ private static final long CLOCK_SKEW_ALLOWANCE = 180;
+
+ private static final String UTF8 = "UTF-8";
+
+ public TimeSource timeSource = new TimeSource();
+ private byte[] cipherKey;
+ private byte[] hmacKey;
+
+ /**
+ * Builds a BlobCrypter from the specified master key
+ *
+ * @param masterKey
+ */
+ public BasicBlobCrypter(byte[] masterKey) {
+ if (masterKey.length < MASTER_KEY_MIN_LEN) {
+ throw new IllegalArgumentException("Master key needs at least " +
+ MASTER_KEY_MIN_LEN + " bytes");
+ }
+ cipherKey = deriveKey(CIPHER_KEY_LABEL, masterKey, Crypto.CIPHER_KEY_LEN);
+ hmacKey = deriveKey(HMAC_KEY_LABEL, masterKey, 0);
+ }
+
+ /**
+ * Generates unique keys from a master key.
+ *
+ * @param label type of key to derive
+ * @param masterKey master key
+ * @param len length of key needed, less than 20 bytes. 20 bytes are
+ * returned if len is 0.
+ *
+ * @return a derived key of the specified length
+ */
+ private byte[] deriveKey(byte label, byte[] masterKey, int len) {
+ byte[] base = Crypto.concat(new byte[] { label }, masterKey);
+ byte[] hash = DigestUtils.sha(base);
+ if (len == 0) {
+ return hash;
+ }
+ byte[] out = new byte[len];
+ System.arraycopy(hash, 0, out, 0, out.length);
+ return out;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.shindig.util.BlobCrypter#wrap(java.util.Map)
+ */
+ public String wrap(Map<String, String> in)
+ throws BlobCrypterException {
+ if (in.containsKey(TIMESTAMP_KEY)) {
+ throw new IllegalArgumentException("No 't' keys allowed for BlobCrypter");
+ }
+ try {
+ byte[] encoded = serializeAndTimestamp(in);
+ byte[] cipherText = Crypto.aes128cbcEncrypt(cipherKey, encoded);
+ byte[] hmac = Crypto.hmacSha1(hmacKey, cipherText);
+ byte[] b64 = Base64.encodeBase64(Crypto.concat(cipherText, hmac));
+ return new String(b64, UTF8);
+ } catch (UnsupportedEncodingException e) {
+ throw new BlobCrypterException(e);
+ } catch (GeneralSecurityException e) {
+ throw new BlobCrypterException(e);
+ }
+ }
+
+ /**
+ * Encode the input for transfer. We use something a lot like HTML form
+ * encodings. The time stamp is in seconds since the epoch.
+ */
+ private byte[] serializeAndTimestamp(Map<String, String> in)
+ throws UnsupportedEncodingException {
+ StringBuilder sb = new StringBuilder();
+
+ for (Map.Entry<String, String> stringStringEntry : in.entrySet()) {
+ Map.Entry<String, String> val = stringStringEntry;
+ sb.append(URLEncoder.encode(val.getKey(), UTF8));
+ sb.append('=');
+ sb.append(URLEncoder.encode(val.getValue(), UTF8));
+ sb.append('&');
+ }
+ sb.append(TIMESTAMP_KEY);
+ sb.append('=');
+ sb.append(timeSource.currentTimeMillis()/1000);
+ return sb.toString().getBytes(UTF8);
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.shindig.util.BlobCrypter#unwrap(java.lang.String, int)
+ */
+ public Map<String, String> unwrap(String in, int maxAgeSec)
+ throws BlobCrypterException {
+ try {
+ byte[] bin = Base64.decodeBase64(in.getBytes());
+ byte[] hmac = new byte[Crypto.HMAC_SHA1_LEN];
+ byte[] cipherText = new byte[bin.length-Crypto.HMAC_SHA1_LEN];
+ System.arraycopy(bin, 0, cipherText, 0, cipherText.length);
+ System.arraycopy(bin, cipherText.length, hmac, 0, hmac.length);
+ Crypto.hmacSha1Verify(hmacKey, cipherText, hmac);
+ byte[] plain = Crypto.aes128cbcDecrypt(cipherKey, cipherText);
+ Map<String, String> out = deserialize(plain);
+ checkTimestamp(out, maxAgeSec);
+ return out;
+ } catch (GeneralSecurityException e) {
+ throw new BlobCrypterException("Invalid token signature", e);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new BlobCrypterException("Invalid token format", e);
+ } catch (UnsupportedEncodingException e) {
+ throw new BlobCrypterException(e);
+ }
+
+ }
+
+ private Map<String, String> deserialize(byte[] plain)
+ throws UnsupportedEncodingException {
+ String base = new String(plain, UTF8);
+ String[] items = base.split("[&=]");
+ Map<String, String> map = new HashMap<String, String>();
+ for (int i=0; i < items.length; ) {
+ String key = URLDecoder.decode(items[i++], UTF8);
+ String val = URLDecoder.decode(items[i++], UTF8);
+ map.put(key, val);
+ }
+ return map;
+ }
+
+ /**
+ * We allow a few minutes on either side of the validity window to account
+ * for clock skew.
+ */
+ private void checkTimestamp(Map<String, String> out, int maxAge)
+ throws BlobExpiredException {
+ long origin = Long.parseLong(out.get(TIMESTAMP_KEY));
+ long minTime = origin - CLOCK_SKEW_ALLOWANCE;
+ long maxTime = origin + maxAge + CLOCK_SKEW_ALLOWANCE;
+ long now = timeSource.currentTimeMillis()/1000;
+ if (!(minTime < now && now < maxTime)) {
+ throw new BlobExpiredException(minTime, now, maxTime);
+ }
+ }
+
+}
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/BlobCrypter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/BlobCrypter.java?rev=645027&r1=645026&r2=645027&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/BlobCrypter.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/BlobCrypter.java Fri Apr 4 21:37:53 2008
@@ -18,80 +18,18 @@
*/
package org.apache.shindig.util;
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.codec.digest.DigestUtils;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.net.URLEncoder;
-import java.security.GeneralSecurityException;
-import java.util.HashMap;
import java.util.Map;
/**
- * Utility class for managing signed, encrypted, and time stamped blobs.
+ * Utility interface for managing signed, encrypted, and time stamped blobs.
* Blobs are made up of name/value pairs. Time stamps are automatically
- * included under BlobCrypter.TIMESTAMP_KEY.
+ * included and checked.
*
* Thread safe.
*/
-public class BlobCrypter {
-
- // Labels for key derivation
- private static final byte CIPHER_KEY_LABEL = 0;
- private static final byte HMAC_KEY_LABEL = 1;
-
- /** Key used for time stamp (in seconds) of data */
- public static final String TIMESTAMP_KEY = "t";
-
- /** minimum length of master key */
- public static final int MASTER_KEY_MIN_LEN = 16;
-
- /** allow three minutes for clock skew */
- private static final long CLOCK_SKEW_ALLOWANCE = 180;
-
- private static final String UTF8 = "UTF-8";
-
- public TimeSource timeSource = new TimeSource();
- private byte[] cipherKey;
- private byte[] hmacKey;
-
- /**
- * Builds a BlobCrypter from the specified master key
- *
- * @param masterKey
- */
- public BlobCrypter(byte[] masterKey) {
- if (masterKey.length < MASTER_KEY_MIN_LEN) {
- throw new IllegalArgumentException("Master key needs at least " +
- MASTER_KEY_MIN_LEN + " bytes");
- }
- cipherKey = deriveKey(CIPHER_KEY_LABEL, masterKey, Crypto.CIPHER_KEY_LEN);
- hmacKey = deriveKey(HMAC_KEY_LABEL, masterKey, 0);
- }
+public interface BlobCrypter {
/**
- * Generates unique keys from a master key.
- *
- * @param label type of key to derive
- * @param masterKey master key
- * @param len length of key needed, less than 20 bytes. 20 bytes are returned
- * if len is 0.
- *
- * @return a derived key of the specified length
- */
- private byte[] deriveKey(byte label, byte[] masterKey, int len) {
- byte[] base = Crypto.concat(new byte[] { label }, masterKey);
- byte[] hash = DigestUtils.sha(base);
- if (len == 0) {
- return hash;
- }
- byte[] out = new byte[len];
- System.arraycopy(hash, 0, out, 0, out.length);
- return out;
- }
-
- /**
* Time stamps, encrypts, and signs a blob.
*
* @param in name/value pairs to encrypt
@@ -99,44 +37,7 @@
*
* @throws BlobCrypterException
*/
- public String wrap(Map<String, String> in)
- throws BlobCrypterException {
- if (in.containsKey(TIMESTAMP_KEY)) {
- throw new IllegalArgumentException("No 't' keys allowed for BlobCrypter");
- }
- try {
- byte[] encoded = serializeAndTimestamp(in);
- byte[] cipherText = Crypto.aes128cbcEncrypt(cipherKey, encoded);
- byte[] hmac = Crypto.hmacSha1(hmacKey, cipherText);
- byte[] b64 = Base64.encodeBase64(Crypto.concat(cipherText, hmac));
- return new String(b64, UTF8);
- } catch (UnsupportedEncodingException e) {
- throw new BlobCrypterException(e);
- } catch (GeneralSecurityException e) {
- throw new BlobCrypterException(e);
- }
- }
-
- /**
- * Encode the input for transfer. We use something a lot like HTML form
- * encodings. The time stamp is in seconds since the epoch.
- */
- private byte[] serializeAndTimestamp(Map<String, String> in)
- throws UnsupportedEncodingException {
- StringBuilder sb = new StringBuilder();
-
- for (Map.Entry<String, String> stringStringEntry : in.entrySet()) {
- Map.Entry<String, String> val = stringStringEntry;
- sb.append(URLEncoder.encode(val.getKey(), UTF8));
- sb.append('=');
- sb.append(URLEncoder.encode(val.getValue(), UTF8));
- sb.append('&');
- }
- sb.append(TIMESTAMP_KEY);
- sb.append('=');
- sb.append(timeSource.currentTimeMillis()/1000);
- return sb.toString().getBytes(UTF8);
- }
+ public String wrap(Map<String, String> in) throws BlobCrypterException;
/**
* Unwraps a blob.
@@ -149,53 +50,6 @@
* @throws BlobCrypterException if the blob can't be decoded.
*/
public Map<String, String> unwrap(String in, int maxAgeSec)
- throws BlobCrypterException {
- try {
- byte[] bin = Base64.decodeBase64(in.getBytes());
- byte[] hmac = new byte[Crypto.HMAC_SHA1_LEN];
- byte[] cipherText = new byte[bin.length-Crypto.HMAC_SHA1_LEN];
- System.arraycopy(bin, 0, cipherText, 0, cipherText.length);
- System.arraycopy(bin, cipherText.length, hmac, 0, hmac.length);
- Crypto.hmacSha1Verify(hmacKey, cipherText, hmac);
- byte[] plain = Crypto.aes128cbcDecrypt(cipherKey, cipherText);
- Map<String, String> out = deserialize(plain);
- checkTimestamp(out, maxAgeSec);
- return out;
- } catch (GeneralSecurityException e) {
- throw new BlobCrypterException("Invalid token signature", e);
- } catch (ArrayIndexOutOfBoundsException e) {
- throw new BlobCrypterException("Invalid token format", e);
- } catch (UnsupportedEncodingException e) {
- throw new BlobCrypterException(e);
- }
-
- }
-
- private Map<String, String> deserialize(byte[] plain) throws UnsupportedEncodingException {
- String base = new String(plain, UTF8);
- String[] items = base.split("[&=]");
- Map<String, String> map = new HashMap<String, String>();
- for (int i=0; i < items.length; ) {
- String key = URLDecoder.decode(items[i++], UTF8);
- String val = URLDecoder.decode(items[i++], UTF8);
- map.put(key, val);
- }
- return map;
- }
-
- /**
- * We allow a few minutes on either side of the validity window to account
- * for clock skew.
- */
- private void checkTimestamp(Map<String, String> out, int maxAge)
- throws BlobExpiredException {
- long origin = Long.parseLong(out.get(TIMESTAMP_KEY));
- long minTime = origin - CLOCK_SKEW_ALLOWANCE;
- long maxTime = origin + maxAge + CLOCK_SKEW_ALLOWANCE;
- long now = timeSource.currentTimeMillis()/1000;
- if (!(minTime < now && now < maxTime)) {
- throw new BlobExpiredException(minTime, now, maxTime);
- }
- }
+ throws BlobCrypterException;
}
Added: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/FakeGadgetToken.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/FakeGadgetToken.java?rev=645027&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/FakeGadgetToken.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/FakeGadgetToken.java Fri Apr 4 21:37:53 2008
@@ -0,0 +1,52 @@
+/*
+ * 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;
+
+/**
+ * A fake GadgetToken implementation to help testing.
+ */
+public class FakeGadgetToken implements GadgetToken {
+ public String getOwnerId() {
+ return "owner";
+ }
+
+ public String getViewerId() {
+ return "viewer";
+ }
+
+ public String getAppId() {
+ return "app1234";
+ }
+
+ public String getDomain() {
+ return "domain";
+ }
+
+ public String toSerialForm() {
+ return "";
+ }
+
+ public String getAppUrl() {
+ return "http://www.example.com/app.xml";
+ }
+
+ public long getModuleId() {
+ return 0;
+ }
+}
Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetTestFixture.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetTestFixture.java?rev=645027&r1=645026&r2=645027&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetTestFixture.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetTestFixture.java Fri Apr 4 21:37:53 2008
@@ -24,7 +24,7 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-public class GadgetTestFixture extends EasyMockTestCase {
+public abstract class GadgetTestFixture extends EasyMockTestCase {
public final HttpServletRequest request = mock(HttpServletRequest.class);
public final HttpServletResponse response = mock(HttpServletResponse.class);
public final GadgetServer gadgetServer;
Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/SigningFetcherTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/SigningFetcherTest.java?rev=645027&r1=645026&r2=645027&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/SigningFetcherTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/SigningFetcherTest.java Fri Apr 4 21:37:53 2008
@@ -70,7 +70,7 @@
@Override
public void setUp() throws Exception {
interceptor = new InterceptingContentFetcher();
- authToken = new BasicGadgetToken("o", "v", "a", "d");
+ authToken = new BasicGadgetToken("o", "v", "a", "d", "u", "m");
signer = SigningFetcher.makeFromB64PrivateKey(
interceptor, authToken, "foo", PRIVATE_KEY_TEXT);
OAuthConsumer consumer = new OAuthConsumer(null, null, null, null);
Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpTestFixture.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpTestFixture.java?rev=645027&r1=645026&r2=645027&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpTestFixture.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpTestFixture.java Fri Apr 4 21:37:53 2008
@@ -23,7 +23,7 @@
import org.apache.shindig.gadgets.SigningFetcherFactory;
-public class HttpTestFixture extends GadgetTestFixture {
+public abstract class HttpTestFixture extends GadgetTestFixture {
public final ProxyHandler proxyHandler;
public final GadgetRenderer gadgetRenderer;
public final JsonRpcHandler jsonRpcHandler;
@@ -35,8 +35,11 @@
public HttpTestFixture() {
super();
- proxyHandler
- = new ProxyHandler(fetcher, gadgetTokenDecoder, signingFetcherFactory);
+ proxyHandler = new ProxyHandler(
+ fetcher,
+ gadgetTokenDecoder,
+ signingFetcherFactory,
+ null);
gadgetRenderer = new GadgetRenderer(
gadgetServer, registry, syndicatorConfig, urlGenerator);
jsonRpcHandler = new JsonRpcHandler(executor, gadgetServer, urlGenerator);
Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/ProxyHandlerTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/ProxyHandlerTest.java?rev=645027&r1=645026&r2=645027&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/ProxyHandlerTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/ProxyHandlerTest.java Fri Apr 4 21:37:53 2008
@@ -23,6 +23,7 @@
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.isA;
+import org.apache.shindig.gadgets.FakeGadgetToken;
import org.apache.shindig.gadgets.GadgetException;
import org.apache.shindig.gadgets.GadgetToken;
import org.apache.shindig.gadgets.RemoteContent;
@@ -40,27 +41,7 @@
private final static String URL_ONE = "http://www.example.com/test.html";
private final static String DATA_ONE = "hello world";
- private static final GadgetToken DUMMY_TOKEN = new GadgetToken() {
- public String getOwnerId() {
- return "owner";
- }
-
- public String getViewerId() {
- return "viewer";
- }
-
- public String getAppId() {
- return "app";
- }
-
- public String getDomain() {
- return "domain";
- }
-
- public String toSerialForm() {
- return "";
- }
- };
+ private static final GadgetToken DUMMY_TOKEN = new FakeGadgetToken();
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final PrintWriter writer = new PrintWriter(baos);
Added: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreTest.java?rev=645027&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreTest.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/BasicOAuthStoreTest.java Fri Apr 4 21:37:53 2008
@@ -0,0 +1,426 @@
+/*
+ * 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 static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.same;
+
+import junit.framework.TestCase;
+
+import net.oauth.OAuthAccessor;
+import net.oauth.OAuthServiceProvider;
+import net.oauth.signature.RSA_SHA1;
+
+import org.easymock.classextension.EasyMock;
+import org.easymock.classextension.IMocksControl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class BasicOAuthStoreTest extends TestCase {
+
+ private IMocksControl control;
+ private Map<OAuthStore.ProviderKey, BasicOAuthStore.ProviderInfo>
+ mockProviders;
+ private Map<OAuthStore.TokenKey, OAuthStore.TokenInfo> mockTokens;
+ private BasicOAuthStore noDefaultStore;
+ private BasicOAuthStore withDefaultStore;
+ private String defaultKey = "defaultkey";
+ private String defaultSecret = "defaultsecret"; // not quite a PKCS8-encoded
+ // RSA key, but that's ok
+
+ @Override
+ @SuppressWarnings("unchecked")
+ protected void setUp() throws Exception {
+ control = EasyMock.createStrictControl();
+ mockProviders = control.createMock(
+ new HashMap<OAuthStore.ProviderKey,
+ BasicOAuthStore.ProviderInfo>().getClass());
+ mockTokens = control.createMock(
+ new HashMap<OAuthStore.TokenKey, OAuthStore.TokenInfo>().getClass());
+
+ noDefaultStore = new BasicOAuthStore();
+ noDefaultStore.setHashMapsForTesting(mockProviders, mockTokens);
+
+ withDefaultStore = new BasicOAuthStore(defaultKey, defaultSecret);
+ withDefaultStore.setHashMapsForTesting(mockProviders, mockTokens);
+ }
+
+ public void testGetOAuthAccessor() throws Exception {
+ OAuthStore.TokenKey tokenKey = new OAuthStore.TokenKey();
+ tokenKey.setGadgetUri("http://foo.bar.com/gadget.xml");
+ tokenKey.setModuleId(2348709L);
+ tokenKey.setUserId("testuser");
+ tokenKey.setServiceName("testservice");
+ tokenKey.setTokenName("testtoken");
+
+ OAuthStore.TokenInfo tokenInfo = new OAuthStore.TokenInfo("accesstoken",
+ "tokensecret");
+
+ OAuthStore.ProviderKey provKey = new OAuthStore.ProviderKey();
+ provKey.setGadgetUri(tokenKey.getGadgetUri());
+ provKey.setServiceName(tokenKey.getServiceName());
+
+ OAuthServiceProvider provider = new OAuthServiceProvider(
+ "request", "authorize", "access");
+
+ BasicOAuthStore.ProviderInfo info = new BasicOAuthStore.ProviderInfo();
+
+ info.setHttpMethod(OAuthStore.HttpMethod.GET);
+ info.setSignatureType(OAuthStore.SignatureType.HMAC_SHA1);
+ info.setProvider(provider);
+
+ ////////////////////////////////////////////////////////////////////////////
+ // first, the case where we don't have a consumer key/secret
+
+ control.checkOrder(false);
+
+ expect(mockProviders.get(eq(provKey))).andReturn(info).once();
+ expect(mockTokens.get(tokenKey)).andReturn(tokenInfo);
+
+ control.replay();
+
+ OAuthStore.AccessorInfo accessorInfo =
+ withDefaultStore.getOAuthAccessor(tokenKey);
+
+ control.verify();
+
+ OAuthAccessor accessor = accessorInfo.getAccessor();
+
+ assertEquals("accesstoken", accessor.accessToken);
+ assertEquals("tokensecret", accessor.tokenSecret);
+ assertEquals(defaultKey, accessor.consumer.consumerKey);
+ assertNull(accessor.consumer.consumerSecret);
+ assertEquals(defaultSecret, accessor.consumer
+ .getProperty(RSA_SHA1.PRIVATE_KEY));
+ assertEquals("access", accessor.consumer.serviceProvider.accessTokenURL);
+ assertEquals("request", accessor.consumer.serviceProvider.requestTokenURL);
+ assertEquals("authorize",
+ accessor.consumer.serviceProvider.userAuthorizationURL);
+
+ // now for the one that doesn't have default keys set
+ control.reset();
+ control.checkOrder(false);
+
+ expect(mockProviders.get(eq(provKey))).andReturn(info).once();
+ expect(mockTokens.get(tokenKey)).andStubReturn(tokenInfo);
+
+ control.replay();
+
+ try {
+ accessorInfo = noDefaultStore.getOAuthAccessor(tokenKey);
+ fail("expected exception, but didn't get it");
+ } catch (OAuthNoDataException e) {
+ // this is expected
+ }
+
+ control.verify();
+
+ ////////////////////////////////////////////////////////////////////////////
+ // now the case where we have negotiated an HMAC consumer secret
+
+ OAuthStore.ConsumerKeyAndSecret kas =
+ new OAuthStore.ConsumerKeyAndSecret("negotiatedkey",
+ "negotiatedsecret",
+ OAuthStore.KeyType.HMAC_SYMMETRIC);
+ info.setKeyAndSecret(kas);
+
+ control.reset();
+ control.checkOrder(false);
+
+ expect(mockProviders.get(eq(provKey))).andReturn(info).once();
+ expect(mockTokens.get(tokenKey)).andReturn(tokenInfo);
+
+ control.replay();
+
+ accessorInfo = noDefaultStore.getOAuthAccessor(tokenKey);
+
+ control.verify();
+
+ accessor = accessorInfo.getAccessor();
+
+ assertEquals("accesstoken", accessor.accessToken);
+ assertEquals("tokensecret", accessor.tokenSecret);
+ assertEquals("negotiatedkey", accessor.consumer.consumerKey);
+ assertEquals("negotiatedsecret", accessor.consumer.consumerSecret);
+ assertEquals("access", accessor.consumer.serviceProvider.accessTokenURL);
+ assertEquals("request", accessor.consumer.serviceProvider.requestTokenURL);
+ assertEquals("authorize",
+ accessor.consumer.serviceProvider.userAuthorizationURL);
+
+ // the store with fallback keys should do the same thing
+
+ control.reset();
+ control.checkOrder(false);
+
+ expect(mockProviders.get(eq(provKey))).andReturn(info).once();
+ expect(mockTokens.get(tokenKey)).andReturn(tokenInfo);
+
+ control.replay();
+
+ accessorInfo = withDefaultStore.getOAuthAccessor(tokenKey);
+
+ control.verify();
+
+ accessor = accessorInfo.getAccessor();
+
+ assertEquals("accesstoken", accessor.accessToken);
+ assertEquals("tokensecret", accessor.tokenSecret);
+ assertEquals("negotiatedkey", accessor.consumer.consumerKey);
+ assertEquals("negotiatedsecret", accessor.consumer.consumerSecret);
+ assertEquals("access", accessor.consumer.serviceProvider.accessTokenURL);
+ assertEquals("request", accessor.consumer.serviceProvider.requestTokenURL);
+ assertEquals("authorize",
+ accessor.consumer.serviceProvider.userAuthorizationURL);
+
+ ////////////////////////////////////////////////////////////////////////////
+ // now the case where we have negotiated an RSA consumer key
+
+ kas = new OAuthStore.ConsumerKeyAndSecret("negotiatedkey",
+ "negotiatedsecret",
+ OAuthStore.KeyType.RSA_PRIVATE);
+ info.setKeyAndSecret(kas);
+
+ control.reset();
+ control.checkOrder(false);
+
+ expect(mockProviders.get(eq(provKey))).andReturn(info).once();
+ expect(mockTokens.get(tokenKey)).andReturn(tokenInfo);
+
+ control.replay();
+
+ accessorInfo = noDefaultStore.getOAuthAccessor(tokenKey);
+
+ control.verify();
+
+ accessor = accessorInfo.getAccessor();
+
+ assertEquals("accesstoken", accessor.accessToken);
+ assertEquals("tokensecret", accessor.tokenSecret);
+ assertEquals("negotiatedkey", accessor.consumer.consumerKey);
+ assertNull(accessor.consumer.consumerSecret);
+ assertEquals("negotiatedsecret",
+ accessor.consumer.getProperty(RSA_SHA1.PRIVATE_KEY));
+ assertEquals("access", accessor.consumer.serviceProvider.accessTokenURL);
+ assertEquals("request", accessor.consumer.serviceProvider.requestTokenURL);
+ assertEquals("authorize",
+ accessor.consumer.serviceProvider.userAuthorizationURL);
+
+ // store with fallback keys should do the same
+
+ control.reset();
+ control.checkOrder(false);
+
+ expect(mockProviders.get(eq(provKey))).andReturn(info).once();
+ expect(mockTokens.get(tokenKey)).andReturn(tokenInfo);
+
+ control.replay();
+
+ accessorInfo = noDefaultStore.getOAuthAccessor(tokenKey);
+
+ control.verify();
+
+ accessor = accessorInfo.getAccessor();
+
+ assertEquals("accesstoken", accessor.accessToken);
+ assertEquals("tokensecret", accessor.tokenSecret);
+ assertEquals("negotiatedkey", accessor.consumer.consumerKey);
+ assertNull(accessor.consumer.consumerSecret);
+ assertEquals("negotiatedsecret",
+ accessor.consumer.getProperty(RSA_SHA1.PRIVATE_KEY));
+ assertEquals("access", accessor.consumer.serviceProvider.accessTokenURL);
+ assertEquals("request", accessor.consumer.serviceProvider.requestTokenURL);
+ assertEquals("authorize",
+ accessor.consumer.serviceProvider.userAuthorizationURL);
+
+ ////////////////////////////////////////////////////////////////////////////
+ // now, test some error conditions. Fist, that no such service exists...
+
+ control.reset();
+ control.checkOrder(false);
+
+ expect(mockProviders.get(eq(provKey))).andReturn(null);
+ expect(mockTokens.get(tokenKey)).andStubReturn(tokenInfo);
+
+ control.replay();
+
+ try {
+ accessorInfo = noDefaultStore.getOAuthAccessor(tokenKey);
+ fail("expected OAuthNoDataException, but didn't get it");
+ } catch (OAuthNoDataException e) {
+ // this is expected
+ }
+
+ control.verify();
+
+ // same with the store with fallback keys
+
+ control.reset();
+ control.checkOrder(false);
+
+ expect(mockProviders.get(eq(provKey))).andReturn(null);
+ expect(mockTokens.get(tokenKey)).andStubReturn(tokenInfo);
+
+ control.replay();
+
+ try {
+ accessorInfo = noDefaultStore.getOAuthAccessor(tokenKey);
+ fail("expected OAuthNoDataException, but didn't get it");
+ } catch (OAuthNoDataException e) {
+ // this is expected
+ }
+
+ control.verify();
+
+ ////////////////////////////////////////////////////////////////////////////
+ // service info is there, but no token:
+
+ control.reset();
+ control.checkOrder(false);
+
+ expect(mockProviders.get(eq(provKey))).andStubReturn(info);
+ expect(mockTokens.get(tokenKey)).andReturn(null);
+
+ control.replay();
+
+ accessorInfo = noDefaultStore.getOAuthAccessor(tokenKey);
+
+ control.verify();
+
+ assertNull(accessorInfo.getAccessor().accessToken);
+ assertNull(accessorInfo.getAccessor().requestToken);
+
+ // same with the store with fallback keys
+
+ control.reset();
+ control.checkOrder(false);
+
+ expect(mockProviders.get(eq(provKey))).andStubReturn(info);
+ expect(mockTokens.get(tokenKey)).andReturn(null);
+
+ control.replay();
+
+ accessorInfo = withDefaultStore.getOAuthAccessor(tokenKey);
+ assertNull(accessorInfo.getAccessor().accessToken);
+ assertNull(accessorInfo.getAccessor().requestToken);
+
+ control.verify();
+
+ }
+
+ public void testSetOAuthConsumerKeyAndSecret() throws Exception {
+ OAuthStore.ProviderKey provKey = new OAuthStore.ProviderKey();
+ provKey.setGadgetUri("http://foo.bar.com/gadget.xml");
+ provKey.setServiceName("testservice");
+
+ OAuthStore.ConsumerKeyAndSecret kas =
+ new OAuthStore.ConsumerKeyAndSecret("consumerkey",
+ "consumersecret",
+ OAuthStore.KeyType.HMAC_SYMMETRIC);
+
+ OAuthServiceProvider provider = new OAuthServiceProvider(
+ "request", "authorize", "access");
+
+ OAuthStore.ProviderInfo info = new OAuthStore.ProviderInfo();
+ info.setHttpMethod(OAuthStore.HttpMethod.GET);
+ info.setSignatureType(OAuthStore.SignatureType.HMAC_SHA1);
+ info.setProvider(provider);
+
+ expect(mockProviders.get(provKey)).andReturn(info);
+
+ control.replay();
+
+ noDefaultStore.setOAuthConsumerKeyAndSecret(provKey, kas);
+
+ control.verify();
+
+ // make sure that consumer key and secret got attached
+ assertSame(info.getKeyAndSecret(), kas);
+
+ ////////////////////////////////////////////////////////////////////////////
+ // now, test some error conditions
+
+ control.reset();
+
+ expect(mockProviders.get(provKey)).andReturn(null);
+
+ control.replay();
+
+ try {
+ noDefaultStore.setOAuthConsumerKeyAndSecret(provKey, kas);
+ fail("expected OAuthNoDataException, but didn't get it");
+ } catch (OAuthNoDataException ex) {
+ // this is expected
+ }
+
+ control.verify();
+ }
+
+ public void testSetOAuthServiceProviderInfo() throws Exception {
+
+ OAuthStore.ProviderKey provKey = new OAuthStore.ProviderKey();
+ provKey.setGadgetUri("http://foo.bar.com/gadget.xml");
+ provKey.setServiceName("testservice");
+
+ OAuthStore.ConsumerKeyAndSecret kas =
+ new OAuthStore.ConsumerKeyAndSecret("consumerkey",
+ "consumersecret",
+ OAuthStore.KeyType.HMAC_SYMMETRIC);
+
+ OAuthServiceProvider provider = new OAuthServiceProvider(
+ "request", "authorize", "access");
+
+ BasicOAuthStore.ProviderInfo info = new BasicOAuthStore.ProviderInfo();
+
+ info.setHttpMethod(OAuthStore.HttpMethod.GET);
+ info.setSignatureType(OAuthStore.SignatureType.HMAC_SHA1);
+ info.setProvider(provider);
+ info.setKeyAndSecret(kas);
+
+ expect(mockProviders.put(same(provKey), same(info))).andReturn(null);
+
+ control.replay();
+
+ noDefaultStore.setOAuthServiceProviderInfo(provKey, info);
+
+ control.verify();
+ }
+
+ public void testSetTokenAndSecret() throws Exception {
+ OAuthStore.TokenKey tokenKey = new OAuthStore.TokenKey();
+ tokenKey.setGadgetUri("http://foo.bar.com/gadget.xml");
+ tokenKey.setServiceName("testservice");
+ tokenKey.setModuleId(9843243278L);
+ tokenKey.setTokenName("testtoken");
+ tokenKey.setUserId("test user");
+
+ OAuthStore.TokenInfo tokenInfo =
+ new OAuthStore.TokenInfo("token", "secret");
+
+
+ expect(mockTokens.put(tokenKey, tokenInfo)).andReturn(null);
+
+ control.replay();
+
+ noDefaultStore.setTokenAndSecret(tokenKey, tokenInfo);
+
+ control.verify();
+ }
+}
Added: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/GadgetTokenStoreTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/GadgetTokenStoreTest.java?rev=645027&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/GadgetTokenStoreTest.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/oauth/GadgetTokenStoreTest.java Fri Apr 4 21:37:53 2008
@@ -0,0 +1,344 @@
+/*
+ * 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 static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.same;
+
+import junit.framework.TestCase;
+
+import org.apache.shindig.gadgets.GadgetException;
+import org.apache.shindig.gadgets.oauth.GadgetOAuthTokenStore.GadgetInfo;
+import org.apache.shindig.gadgets.spec.GadgetSpec;
+import org.easymock.IArgumentMatcher;
+import org.easymock.classextension.EasyMock;
+import org.easymock.classextension.IMocksControl;
+
+import java.net.URI;
+import java.util.HashMap;
+
+public class GadgetTokenStoreTest extends TestCase {
+
+ private static final String specStr =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" +
+ " <Module>\n" +
+ " <ModulePrefs title=\"hello world example\">\n" +
+ " \n" +
+ " <Require feature=\"oauth\">\n" +
+ " <Param name=\"service_name\">\n" +
+ " netflix\n" +
+ " </Param>\n" +
+ " <Param name=\"access_url\">\n" +
+ " http://www.netflix.com.notreally/access\n" +
+ " </Param>\n" +
+ " <Param name=\"access_method\">\n" +
+ " GET\n" +
+ " </Param>\n" +
+ " \n" +
+ " <Param name=\"request_url\">\n" +
+ " http://www.netflix.com.notreally/request\n" +
+ " </Param>\n" +
+ " <Param name=\"request_method\">\n" +
+ " GET\n" +
+ " </Param>\n" +
+ " \n" +
+ " <Param name=\"authorize_url\">\n" +
+ " http://www.netflix.com.notreally/authorize\n" +
+ " </Param>\n" +
+ " </Require>\n" +
+ " \n" +
+ " </ModulePrefs>\n" +
+ " <Content type=\"html\">\n" +
+ " <![CDATA[\n" +
+ " Hello, world!\n" +
+ " ]]>\n" +
+ " \n" +
+ " </Content>\n" +
+ " </Module>";
+
+ private GadgetOAuthTokenStore store;
+ private GadgetSpec spec;
+ private IMocksControl control;
+ private BasicOAuthStore mockStoreImpl;
+
+ private static class ProviderInfoMatcher implements IArgumentMatcher {
+
+ private OAuthStore.ProviderInfo expectedInfo;
+
+ public ProviderInfoMatcher(OAuthStore.ProviderInfo info) {
+ expectedInfo = info;
+ }
+
+ public void appendTo(StringBuffer sb) {
+ sb.append("eqProvInfo(");
+ sb.append("access: ");
+ sb.append(expectedInfo.getProvider().accessTokenURL);
+ sb.append(", request: ");
+ sb.append(expectedInfo.getProvider().requestTokenURL);
+ sb.append(", authorize: ");
+ sb.append(expectedInfo.getProvider().userAuthorizationURL);
+ sb.append(", http_method: ");
+ sb.append(expectedInfo.getHttpMethod());
+ sb.append(", signature_type: ");
+ sb.append(expectedInfo.getSignatureType());
+ sb.append(')');
+ }
+
+ public boolean matches(Object actual) {
+ if (! (actual instanceof OAuthStore.ProviderInfo)) {
+ return false;
+ }
+
+ OAuthStore.ProviderInfo actualInfo = (OAuthStore.ProviderInfo)actual;
+
+ return (actualInfo.getHttpMethod() == expectedInfo.getHttpMethod())
+ && (actualInfo.getSignatureType()
+ == expectedInfo.getSignatureType())
+ && actualInfo.getProvider().accessTokenURL.equals(
+ expectedInfo.getProvider().accessTokenURL)
+ && actualInfo.getProvider().requestTokenURL.equals(
+ expectedInfo.getProvider().requestTokenURL)
+ && actualInfo.getProvider().userAuthorizationURL.equals(
+ expectedInfo.getProvider().userAuthorizationURL);
+ }
+ }
+
+ private static OAuthStore.ProviderInfo eqProvInfo(
+ OAuthStore.ProviderInfo info) {
+ EasyMock.reportMatcher(new ProviderInfoMatcher(info));
+ return null;
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ control = EasyMock.createStrictControl();
+ mockStoreImpl = control.createMock(BasicOAuthStore.class);
+ store = new GadgetOAuthTokenStore(mockStoreImpl);
+ spec = new GadgetSpec(new URI("http://foo.bar.com/gadget.xml"), specStr);
+ }
+
+ public void testStoreServiceInfoFromGadgetSpec() throws Exception {
+
+ String gadgetUrl = "http://foo.bar.com/gadget.xml";
+
+ // this method is tested in another test below
+ GadgetInfo gadgetInfo = GadgetOAuthTokenStore.getGadgetOAuthInfo(spec);
+
+ OAuthStore.ProviderKey providerKey = new OAuthStore.ProviderKey();
+ providerKey.setGadgetUri(gadgetUrl.toString());
+ providerKey.setServiceName(gadgetInfo.getServiceName());
+
+ mockStoreImpl.setOAuthServiceProviderInfo(
+ eq(providerKey), eqProvInfo(gadgetInfo.getProviderInfo()));
+ expectLastCall().once();
+
+ control.replay();
+
+ store.storeServiceInfoFromGadgetSpec(new URI(gadgetUrl), spec);
+
+ control.verify();
+ }
+
+ public void testStoreConsumerKeyAndSecret() throws Exception {
+
+ URI gadgetUrl = new URI("http://foo.bar.com/gadget.xml");
+ String serviceName = "testservice";
+
+ OAuthStore.ProviderKey providerKey = new OAuthStore.ProviderKey();
+ providerKey.setGadgetUri(gadgetUrl.toString());
+ providerKey.setServiceName(serviceName);
+
+ OAuthStore.ConsumerKeyAndSecret kas = new OAuthStore.ConsumerKeyAndSecret(
+ "key", "secret", OAuthStore.KeyType.HMAC_SYMMETRIC);
+
+ mockStoreImpl.setOAuthConsumerKeyAndSecret(eq(providerKey), same(kas));
+ expectLastCall().once();
+
+ control.replay();
+
+ store.storeConsumerKeyAndSecret(gadgetUrl, serviceName, kas);
+
+ control.verify();
+ }
+
+ public void testStoreTokenKeyAndSecret() throws Exception {
+
+ final String url = "http://foo.bar.com/gadget.xml";
+ final int moduleId = 42957;
+ final String userId = "testuser";
+ final String serviceName = "testservice";
+ final String tokenName = "testtoken";
+
+ OAuthStore.TokenInfo tokenInfo = new OAuthStore.TokenInfo("", "");
+
+ OAuthStore.TokenKey tokenKey = new OAuthStore.TokenKey();
+ tokenKey.setGadgetUri(url);
+ tokenKey.setModuleId(moduleId);
+ tokenKey.setServiceName(serviceName);
+ tokenKey.setTokenName(tokenName);
+ tokenKey.setUserId(userId);
+
+ mockStoreImpl.setTokenAndSecret(eq(tokenKey), same(tokenInfo));
+ expectLastCall().once();
+
+ control.replay();
+
+ store.storeTokenKeyAndSecret(tokenKey, tokenInfo);
+
+ control.verify();
+ }
+
+ public void testGetOAuthAccessor() throws Exception {
+
+ final String url = "http://foo.bar.com/gadget.xml";
+ final int moduleId = 42957;
+ final String userId = "testuser";
+ final String serviceName = "testservice";
+ final String tokenName = "testtoken";
+
+ OAuthStore.TokenKey tokenKey = new OAuthStore.TokenKey();
+ tokenKey.setGadgetUri(url);
+ tokenKey.setModuleId(moduleId);
+ tokenKey.setServiceName(serviceName);
+ tokenKey.setTokenName(tokenName);
+ tokenKey.setUserId(userId);
+
+ OAuthStore.AccessorInfo info = new OAuthStore.AccessorInfo();
+
+ expect(mockStoreImpl.getOAuthAccessor(eq(tokenKey))).andReturn(info);
+
+ control.replay();
+
+ OAuthStore.AccessorInfo compare =
+ store.getOAuthAccessor(tokenKey);
+
+ control.verify();
+
+ assertSame(info, compare);
+ }
+
+ public void testGetGadgetOAuthInfo() throws Exception {
+ GadgetOAuthTokenStore.GadgetInfo info =
+ GadgetOAuthTokenStore.getGadgetOAuthInfo(spec);
+ OAuthStore.ProviderInfo provInfo = info.getProviderInfo();
+
+ assertEquals("netflix", info.getServiceName());
+ assertEquals("http://www.netflix.com.notreally/access",
+ provInfo.getProvider().accessTokenURL);
+ assertEquals("http://www.netflix.com.notreally/request",
+ provInfo.getProvider().requestTokenURL);
+ assertEquals("http://www.netflix.com.notreally/authorize",
+ provInfo.getProvider().userAuthorizationURL);
+ assertEquals(OAuthStore.HttpMethod.GET, provInfo.getHttpMethod());
+ assertEquals(OAuthStore.SignatureType.HMAC_SHA1,
+ provInfo.getSignatureType());
+
+ // now, let's change the spec a bit
+
+ String newSpecStr = specStr.replaceAll("GET", "POST");
+ spec = new GadgetSpec(new URI("http://foo.bar.com/gadget.xml"), newSpecStr);
+
+ info = GadgetOAuthTokenStore.getGadgetOAuthInfo(spec);
+ provInfo = info.getProviderInfo();
+ assertEquals(OAuthStore.HttpMethod.POST, provInfo.getHttpMethod());
+
+ // if we only change one of the GETs, it's an error
+
+ newSpecStr = specStr.replaceFirst("GET", "POST");
+ spec = new GadgetSpec(new URI("http://foo.bar.com/gadget.xml"), newSpecStr);
+
+ try {
+ info = GadgetOAuthTokenStore.getGadgetOAuthInfo(spec);
+ fail("expected exception, but didn't get it");
+ } catch (GadgetException e) {
+ // this is expected
+ }
+
+ // let's test some other error conditions
+
+ newSpecStr = specStr.replaceAll("GET", "BLAH");
+ spec = new GadgetSpec(new URI("http://foo.bar.com/gadget.xml"), newSpecStr);
+ try {
+ info = GadgetOAuthTokenStore.getGadgetOAuthInfo(spec);
+ fail("expected exception, but didn't get it");
+ } catch (GadgetException e) {
+ // this is expected
+ }
+
+ newSpecStr = specStr.replaceFirst("request_url", "blah");
+ spec = new GadgetSpec(new URI("http://foo.bar.com/gadget.xml"), newSpecStr);
+ try {
+ info = GadgetOAuthTokenStore.getGadgetOAuthInfo(spec);
+ fail("expected exception, but didn't get it");
+ } catch (GadgetException e) {
+ // this is expected
+ }
+
+ newSpecStr = specStr.replaceFirst("access_url", "blah");
+ spec = new GadgetSpec(new URI("http://foo.bar.com/gadget.xml"), newSpecStr);
+ try {
+ info = GadgetOAuthTokenStore.getGadgetOAuthInfo(spec);
+ fail("expected exception, but didn't get it");
+ } catch (GadgetException e) {
+ // this is expected
+ }
+
+ newSpecStr = specStr.replaceFirst("authorize_url", "blah");
+ spec = new GadgetSpec(new URI("http://foo.bar.com/gadget.xml"), newSpecStr);
+ try {
+ info = GadgetOAuthTokenStore.getGadgetOAuthInfo(spec);
+ fail("expected exception, but didn't get it");
+ } catch (GadgetException e) {
+ // this is expected
+ }
+
+ // what if the gadget doesn't require oauth?
+
+ newSpecStr = specStr.replaceFirst("feature=\"oauth\"", "feature=\"blah\"");
+ spec = new GadgetSpec(
+ new URI("http://foo.bar.com/gadget.xml"),
+ newSpecStr);
+ try {
+ info = GadgetOAuthTokenStore.getGadgetOAuthInfo(spec);
+ fail("expected exception, but didn't get it");
+ } catch (GadgetException e) {
+ // this is expected
+ }
+ }
+
+ public void testGetOAuthParameter() throws Exception {
+ HashMap<String, String> params = new HashMap<String, String>();
+ params.put("foo", "bar");
+
+ assertEquals("bar",
+ GadgetOAuthTokenStore.getOAuthParameter(params, "foo", true));
+ assertEquals("bar",
+ GadgetOAuthTokenStore.getOAuthParameter(params, "foo", false));
+ assertNull(GadgetOAuthTokenStore.getOAuthParameter(params, "bla", true));
+
+ try {
+ GadgetOAuthTokenStore.getOAuthParameter(params, "bla", false);
+ fail("expected GadgetException, but didn't get it");
+ } catch (GadgetException e) {
+ // this is expected
+ }
+ }
+}
Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/util/BlobCrypterTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/util/BlobCrypterTest.java?rev=645027&r1=645026&r2=645027&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/util/BlobCrypterTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/util/BlobCrypterTest.java Fri Apr 4 21:37:53 2008
@@ -33,11 +33,11 @@
return new JUnit4TestAdapter(BlobCrypterTest.class);
}
- private BlobCrypter crypter;
+ private BasicBlobCrypter crypter;
private FakeTimeSource timeSource;
public BlobCrypterTest() {
- crypter = new BlobCrypter("0123456789abcdef".getBytes());
+ crypter = new BasicBlobCrypter("0123456789abcdef".getBytes());
timeSource = new FakeTimeSource();
crypter.timeSource = timeSource;
}
@@ -148,7 +148,7 @@
@Test
public void testFixedKey() throws Exception {
- BlobCrypter alt = new BlobCrypter("0123456789abcdef".getBytes());
+ BlobCrypter alt = new BasicBlobCrypter("0123456789abcdef".getBytes());
Map<String, String> in = new HashMap<String, String>();
in.put("a", "b");
String blob = crypter.wrap(in);
@@ -158,12 +158,12 @@
@Test
public void testBadKey() throws Exception {
- BlobCrypter alt = new BlobCrypter("1123456789abcdef".getBytes());
+ BlobCrypter alt = new BasicBlobCrypter("1123456789abcdef".getBytes());
Map<String, String> in = new HashMap<String, String>();
in.put("a", "b");
String blob = crypter.wrap(in);
try {
- Map<String, String> out = alt.unwrap(blob, 30);
+ alt.unwrap(blob, 30);
fail("Decryption should have failed");
} catch (BlobCrypterException e) {
// Good.
@@ -173,7 +173,7 @@
@Test
public void testShortKeyFails() throws Exception {
try {
- new BlobCrypter("0123456789abcde".getBytes());
+ new BasicBlobCrypter("0123456789abcde".getBytes());
fail("Short key should fail");
} catch (IllegalArgumentException e) {
// good.
Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/util/CryptoTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/util/CryptoTest.java?rev=645027&r1=645026&r2=645027&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/util/CryptoTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/util/CryptoTest.java Fri Apr 4 21:37:53 2008
@@ -31,10 +31,10 @@
return new JUnit4TestAdapter(CryptoTest.class);
}
- private BlobCrypter crypter;
+ private BasicBlobCrypter crypter;
public CryptoTest() {
- crypter = new BlobCrypter("0123456789abcdef".getBytes());
+ crypter = new BasicBlobCrypter("0123456789abcdef".getBytes());
crypter.timeSource = new FakeTimeSource();
}
Added: incubator/shindig/trunk/javascript/samplecontainer/examples/oauth.xml
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/javascript/samplecontainer/examples/oauth.xml?rev=645027&view=auto
==============================================================================
--- incubator/shindig/trunk/javascript/samplecontainer/examples/oauth.xml (added)
+++ incubator/shindig/trunk/javascript/samplecontainer/examples/oauth.xml Fri Apr 4 21:37:53 2008
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<Module>
+ <ModulePrefs title="Pankow Gadget">
+
+ <Optional feature="oauth">
+ <Param name="service_name">
+ demo
+ </Param>
+ <Param name="access_url">
+ http://localhost:9090/oauth-provider/access_token
+ </Param>
+ <Param name="access_method">
+ GET
+ </Param>
+
+ <Param name="request_url">
+ http://localhost:9090/oauth-provider/request_token
+ </Param>
+ <Param name="request_method">
+ GET
+ </Param>
+
+ <Param name="authorize_url">
+ http://localhost:9090/oauth-provider/authorize
+ </Param>
+ </Optional>
+
+ </ModulePrefs>
+ <Content type="html">
+ <![CDATA[
+
+ <style>
+ #main {
+ margin: 0px;
+ padding: 0px;
+ font-size: small;
+ }
+ </style>
+
+ <div id="main" style="display: none">
+ </div>
+
+ <div id="approval" style="display: none">
+ <img src="http://localhost:8080/gadgets/files/samplecontainer/examples/new.gif">
+ <a id="personalize"
+ onclick="javascript:showOneSection('waiting'); return true"
+ target="approve">Personalize this gadget</a>
+ </div>
+
+ <div id="waiting" style="display: none">
+ Please click
+ <a onclick="javascript:fetchData()">I've approved access</a>
+ once you've approved access to your data.
+ </div>
+
+ <script type="text/javascript">
+ function showOneSection(toshow) {
+ var sections = [ 'main', 'approval', 'waiting' ];
+ for (var i=0; i < sections.length; ++i) {
+ var s = sections[i];
+ var el = document.getElementById(s);
+ if (s === toshow) {
+ el.style.display = "block";
+ } else {
+ el.style.display = "none";
+ }
+ }
+ }
+
+ function fetchData() {
+ url = "http://localhost:9090/oauth-provider/echo";
+ var params = {};
+ params[gadgets.io.RequestParameters.CONTENT_TYPE] =
+ gadgets.io.ContentType.TEXT;
+ params[gadgets.io.RequestParameters.AUTHORIZATION] =
+ gadgets.io.AuthorizationType.AUTHENTICATED;
+ params[gadgets.io.RequestParameters.OAUTH_SERVICE] = "demo";
+ params[gadgets.io.RequestParameters.METHOD] =
+ gadgets.io.MethodType.GET;
+
+ gadgets.io.makeRequest(url, function (response) {
+ if (response.approvalUrl) {
+ var personalize = document.getElementById('personalize');
+ personalize.href = response.approvalUrl;
+ showOneSection('approval');
+ } else if (response.data) {
+ var main = document.getElementById('main');
+ var txt = document.createTextNode(response.data);
+ main.appendChild(txt);
+ showOneSection('main');
+ } else {
+ var main = document.getElementById('main');
+ var whoops = document.createTextNode('Something went wrong');
+ main.appendChild(whoops);
+ showOneSection('main');
+ }
+ }, params);
+ }
+
+ gadgets.util.registerOnLoadHandler(fetchData);
+ </script>
+ ]]>
+ </Content>
+</Module>
Modified: incubator/shindig/trunk/javascript/samplecontainer/samplecontainer.html
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/javascript/samplecontainer/samplecontainer.html?rev=645027&r1=645026&r2=645027&view=diff
==============================================================================
--- incubator/shindig/trunk/javascript/samplecontainer/samplecontainer.html (original)
+++ incubator/shindig/trunk/javascript/samplecontainer/samplecontainer.html Fri Apr 4 21:37:53 2008
@@ -85,7 +85,7 @@
// Viewer and Owner
document.getElementById("viewerId").value = viewerId;
document.getElementById("ownerId").value = ownerId;
- gadget.secureToken = generateSecureToken();
+ gadget.secureToken = escape(generateSecureToken());
gadgets.container.addGadget(gadget);
gadgets.container.layoutManager.setGadgetChromeIds(['gadget-chrome']);
@@ -107,7 +107,7 @@
viewerId = document.getElementById("viewerId").value;
ownerId = document.getElementById("ownerId").value;
- gadget.secureToken = generateSecureToken();
+ gadget.secureToken = escape(generateSecureToken());
gadgetUrl = document.getElementById("gadgetUrl").value;
gadget.specUrl = gadgetUrl;
@@ -117,8 +117,17 @@
};
function generateSecureToken() {
- // TODO: Use a real app id
- return [ownerId, viewerId, "samplecontainerapp", "shindig"].join(":");
+ // TODO: Use a less silly mechanism of mapping a gadget URL to an appid
+ var appId = 0;
+ for (var i=0; i < gadgetUrl.length; i++) {
+ appId += gadgetUrl.charCodeAt(i);
+ }
+ var fields = [ownerId, viewerId, appId, "shindig", gadgetUrl, "0"];
+ for (var i=0; i < fields.length; i++) {
+ // escape each field individually, for metachars in URL
+ fields[i] = escape(fields[i]);
+ }
+ return fields.join(":");
}
SampleContainerGadget = function(opt_params) {