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/03/28 23:05:31 UTC

svn commit: r642404 - in /incubator/shindig/trunk/java/gadgets/src: main/java/org/apache/shindig/gadgets/ main/java/org/apache/shindig/gadgets/http/ main/java/org/apache/shindig/social/ main/java/org/apache/shindig/social/opensocial/ main/java/org/apac...

Author: etnu
Date: Fri Mar 28 15:05:22 2008
New Revision: 642404

URL: http://svn.apache.org/viewvc?rev=642404&view=rev
Log:
Committing Brian Eaton's SHINDIG-157 patch.

This is being committed now to facilitate easier integration with SHINDIG-152.


Modified:
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicRemoteContentFetcher.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsFeatureLoader.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsLibrary.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/NullRequestSigner.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentFetcher.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentRequest.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RequestSigner.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SignedFetchRequestSigner.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/CrossServletState.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/DefaultCrossServletState.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/GadgetDataHandler.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/opensocial/ActivitiesService.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/opensocial/DataService.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/opensocial/OpenSocialDataHandler.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/opensocial/PeopleService.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/samplecontainer/BasicActivitiesService.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/samplecontainer/BasicDataService.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/samplecontainer/BasicPeopleService.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/samplecontainer/StateFileDataHandler.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/samplecontainer/XmlStateFileFetcher.java
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/BlobCrypter.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/EasyMockTestCase.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/JsLibraryTest.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/SignedFetchRequestSignerTest.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/ProxyHandlerTest.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/util/BlobCrypterTest.java

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicRemoteContentFetcher.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicRemoteContentFetcher.java?rev=642404&r1=642403&r2=642404&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicRemoteContentFetcher.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicRemoteContentFetcher.java Fri Mar 28 15:05:22 2008
@@ -30,7 +30,7 @@
  * Implementation of a {@code RemoteObjectFetcher} using standard java.net
  * classes.
  */
-public class BasicRemoteContentFetcher implements RemoteContentFetcher {
+public class BasicRemoteContentFetcher extends RemoteContentFetcher {
   private static final int CONNECT_TIMEOUT_MS = 5000;
 
   private final int maxObjSize;
@@ -41,6 +41,7 @@
    * @param maxObjSize Maximum size, in bytes, of object to fetch
    */
   public BasicRemoteContentFetcher(int maxObjSize) {
+    super(null);
     this.maxObjSize = maxObjSize;
   }
 

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsFeatureLoader.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsFeatureLoader.java?rev=642404&r1=642403&r2=642404&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsFeatureLoader.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsFeatureLoader.java Fri Mar 28 15:05:22 2008
@@ -238,7 +238,8 @@
    * @param renderingContext
    */
   private void processContext(ParsedFeature feature, Element context,
-                              RenderingContext renderingContext) {
+                              RenderingContext renderingContext) 
+  throws GadgetException {
     String syndicator = XmlUtil.getAttribute(context, "synd",
         SyndicatorConfig.DEFAULT_SYNDICATOR);
     NodeList libraries = context.getElementsByTagName("script");

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsLibrary.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsLibrary.java?rev=642404&r1=642403&r2=642404&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsLibrary.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/JsLibrary.java Fri Mar 28 15:05:22 2008
@@ -113,9 +113,10 @@
    *     kept as a url reference, otherwise the file will be fetched and treated
    *     as a FILE type.
    * @return The newly created library.
+   * @throws GadgetException 
    */
   public static JsLibrary create(Type type, String content, String feature,
-      RemoteContentFetcher fetcher) {
+      RemoteContentFetcher fetcher) throws GadgetException {
     String optimizedContent = null;
     String debugContent;
     switch (type) {
@@ -168,9 +169,10 @@
    * @param url
    * @param fetcher
    * @return The contents of the JS file, or null if it can't be fetched.
+   * @throws GadgetException 
    */
   private static String loadDataFromUrl(String url,
-      RemoteContentFetcher fetcher) {
+      RemoteContentFetcher fetcher) throws GadgetException {
     try {
       logger.info("Attempting to load js from: " + url);
       URI uri = new URI(url);

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/NullRequestSigner.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/NullRequestSigner.java?rev=642404&r1=642403&r2=642404&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/NullRequestSigner.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/NullRequestSigner.java Fri Mar 28 15:05:22 2008
@@ -1,38 +0,0 @@
-/*
- * Licensed 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;
-
-import java.net.URL;
-
-/**
- * Request signer interface that does nothing, for convenience of writing
- * code that may or may not need to sign requests.
- */
-public class NullRequestSigner implements RequestSigner {
-
-  public String getApprovalUrl() {
-    return null;
-  }
-
-  public Status getSigningStatus() {
-    return Status.OK;
-  }
-
-  @SuppressWarnings("unused")
-  public URL signRequest(String method, URL resource, String postBody) throws GadgetException {
-    return resource;
-  }
-
-}

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentFetcher.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentFetcher.java?rev=642404&r1=642403&r2=642404&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentFetcher.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentFetcher.java Fri Mar 28 15:05:22 2008
@@ -18,11 +18,29 @@
 package org.apache.shindig.gadgets;
 
 
-public interface RemoteContentFetcher {
+/**
+ * Fetches data over HTTP.
+ * 
+ * Subclasses can use a chain-of-responsibility pattern to add functionality
+ * to the fetching process.  For example, a SigningFetcher can talk to a
+ * CachingFetcher can talk to a ThrottlingFetcher that talks to a
+ * RemoteFetcher that gets the actual data.
+ */
+public abstract class RemoteContentFetcher {
+
+  /** next fetcher in the chain, may be null */
+  protected RemoteContentFetcher nextFetcher;
+
+  protected RemoteContentFetcher(RemoteContentFetcher nextFetcher) {
+    this.nextFetcher = nextFetcher;
+  }
+  
   /**
-   * Fetch content using the HTTP GET method
+   * Fetch HTTP content.
+   *
    * @param request The request to fetch.
    * @return RemoteContent
+   * @throws GadgetException 
    */
-  public RemoteContent fetch(RemoteContentRequest request);
+  public abstract RemoteContent fetch(RemoteContentRequest request) throws GadgetException;
 }

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentRequest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentRequest.java?rev=642404&r1=642403&r2=642404&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentRequest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RemoteContentRequest.java Fri Mar 28 15:05:22 2008
@@ -33,9 +33,6 @@
  * Holds request data for passing to a RemoteContentFetcher.
  * Instances of this object are immutable.
  *
- * TODO: We should probably just stick the method in here. Having separate
- * calls for POST vs. get seems unnecessary.
- *
  * TODO: This naming seems really ridiculous now. Why don't we just call it
  * what it is -- an HTTP request?
  */
@@ -47,6 +44,13 @@
    */
   public InputStream getPostBody() {
     return new ByteArrayInputStream(postBody);
+  }
+  
+  /**
+   * @return the post body bytes
+   */
+  public byte[] getPostBodyBytes() {
+    return postBody;
   }
 
   /**

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RequestSigner.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RequestSigner.java?rev=642404&r1=642403&r2=642404&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RequestSigner.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/RequestSigner.java Fri Mar 28 15:05:22 2008
@@ -1,60 +0,0 @@
-/*
- * Licensed 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;
-
-import java.net.URL;
-
-/**
- * Interface for generating signed requests and handling responses.
- * 
- * Most of the functionality here isn't used at the moment, just enough to
- * implement signed fetch.  The status and approval bits will be used for 
- * full OAuth.
- */
-public interface RequestSigner {
-
-  /**
-   * Whether the signing request succeeded.
-   */
-  public enum Status {
-    OK,
-    APPROVAL_NEEDED,
-  }
-  
-  /**
-   * Signs a URL and post body, returning a modified URL including the
-   * signature.  The post body is not modified.
-   * 
-   * @param method how the request will be sent
-   * @param resource the URL to sign
-   * @param postBody the body of the request (may be null)
-   * 
-   * @return a signed URL
-   * @throws GadgetException if an error occurs.
-   */
-  public URL signRequest(String method, URL resource, String postBody)
-  throws GadgetException;
-  
-  /**
-   * @return the status associated with the last signing request.  May return
-   * APPROVAL_NEEDED if user interaction is required.
-   */
-  public Status getSigningStatus();
-
-  /**
-   * @return the URL the user needs to visit to approve the access request.
-   */
-  public String getApprovalUrl();
-}

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SignedFetchRequestSigner.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SignedFetchRequestSigner.java?rev=642404&r1=642403&r2=642404&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SignedFetchRequestSigner.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/SignedFetchRequestSigner.java Fri Mar 28 15:05:22 2008
@@ -1,277 +0,0 @@
-/*
- * Licensed 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;
-
-import net.oauth.OAuth;
-import net.oauth.OAuthAccessor;
-import net.oauth.OAuthConsumer;
-import net.oauth.OAuthMessage;
-import net.oauth.OAuth.Parameter;
-import net.oauth.signature.RSA_SHA1;
-
-import org.apache.shindig.util.Crypto;
-import org.apache.shindig.util.TimeSource;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.security.PrivateKey;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-/**
- * Implements signed fetch based on the OAuth request signing algorithm.
- * 
- * Subclasses can override signMessage to use their own crypto if they don't
- * like the oauth.net code for some reason.
- * 
- * Instances of this class are only accessed by a single thread at a time,
- * but instances may be created by multiple threads.
- */
-public class SignedFetchRequestSigner implements RequestSigner {
-
-  protected static final String OPENSOCIAL_OWNERID = "opensocial_owner_id";
-
-  protected static final String OPENSOCIAL_VIEWERID = "opensocial_viewer_id";
-
-  protected static final String OPENSOCIAL_APPID = "opensocial_app_id";
-  
-  protected static final String XOAUTH_PUBLIC_KEY =
-    "xoauth_signature_publickey";
-
-  protected static final Pattern ALLOWED_PARAM_NAME = Pattern
-      .compile("[\\w_\\-]+");
-
-  protected final TimeSource clock = new TimeSource();
-
-  /**
-   * Authentication token for the user and gadget making the request.
-   */
-  protected GadgetToken authToken;
-
-  /**
-   * Private key we pass to the OAuth RSA_SHA1 algorithm.  This can be a 
-   * PrivateKey object, or a PEM formatted private key, or a DER encoded byte
-   * array for the private key.  (No, really, they accept any of them.)
-   */
-  protected Object privateKeyObject;
-
-  /**
-   * The name of the key, included in the fetch to help with key rotation.
-   */
-  protected String keyName;
-
-  /**
-   * Constructor for subclasses that don't want this code to use their
-   * keys.
-   */
-  protected SignedFetchRequestSigner(GadgetToken authToken) {
-    init(authToken, null, null);
-  }
-
-  /**
-   * Constructor based on signing with the given PrivateKey object.
-   * 
-   * @param authToken verified gadget security token
-   * @param keyName name of the key to include in the request
-   * @param privateKey the key to use for the signing
-   */
-  public SignedFetchRequestSigner(GadgetToken authToken, String keyName,
-      PrivateKey privateKey) {
-    init(authToken, keyName, privateKey);
-  }
-  
-  /**
-   * Constructor based on signing with the given PrivateKey object.
-   * 
-   * @param authToken verified gadget security token
-   * @param keyName name of the key to include in the request
-   * @param privateKey base64 encoded private key
-   */
-  public SignedFetchRequestSigner(GadgetToken authToken, String keyName,
-      String privateKey) {
-    init(authToken, keyName, privateKey);
-  }
- 
-  /**
-   * Constructor based on signing with the given PrivateKey object.
-   * 
-   * @param authToken verified gadget security token
-   * @param keyName name of the key to include in the request
-   * @param privateKey DER encoded private key
-   */
-  public SignedFetchRequestSigner(GadgetToken authToken, String keyName, 
-      byte[] privateKey) {
-    init(authToken, keyName, privateKey);
-  }
-  
-  protected void init(GadgetToken authToken, String keyName,
-      Object privateKeyObject) {
-    this.authToken = authToken;
-    this.keyName = keyName;
-    this.privateKeyObject = privateKeyObject;
-  }
-
-  /**
-   * Signed fetch doesn't require approvals, always returns null.
-   */
-  public String getApprovalUrl() {
-    return null;
-  }
-
-  /**
-   * Signed fetch doesn't require approvals, always returns Status.OK
-   */
-  public Status getSigningStatus() {
-    return Status.OK;
-  }
-
-  public URL signRequest(String method, URL resource, String postBody)
-  throws GadgetException {
-    try {
-      // Parse the request into parameters for OAuth signing, stripping out
-      // any OAuth or OpenSocial parameters injected by the client
-      String query = resource.getQuery();
-      resource = removeQuery(resource);
-      List<OAuth.Parameter> queryParams = sanitize(OAuth.decodeForm(query));
-      List<OAuth.Parameter> postParams = sanitize(OAuth.decodeForm(postBody));
-      List<OAuth.Parameter> msgParams = new ArrayList<OAuth.Parameter>();
-      msgParams.addAll(queryParams);
-      msgParams.addAll(postParams);
-
-      // Add the OpenSocial parameters
-      addOpenSocialParams(msgParams);
-      
-      // Add the OAuth parameters
-      addOAuthParams(msgParams);
-
-      // Build and sign the OAuthMessage; note that the resource here has
-      // no query string, the parameters are all in msgParams
-      OAuthMessage message = new OAuthMessage(method, resource.toString(),
-          msgParams);
-      
-      // Sign the message, this may jump into a subclass
-      signMessage(message);
-
-      // Rebuild the query string, including all of the parameters we added.
-      // We have to be careful not to copy POST parameters into the query.
-      // If post and query parameters share a name, they end up being removed
-      // from the query.
-      HashSet<String> forPost = new HashSet<String>();
-      for (OAuth.Parameter param : postParams) {
-        forPost.add(param.getKey());
-      }
-      List<Map.Entry<String, String>> newQuery =
-        new ArrayList<Map.Entry<String, String>>();
-      for (Map.Entry<String, String> param : message.getParameters()) {
-        if (! forPost.contains(param.getKey())) {
-          newQuery.add(param);
-        }
-      }
-      String finalQuery = OAuth.formEncode(newQuery);
-      return new URL(resource.getProtocol(), resource.getHost(),
-          resource.getPort(), resource.getPath() + '?' + finalQuery);
-    } catch (Exception e) {
-      throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR,
-          e);
-    }
-  }
-
-  private URL removeQuery(URL resource) throws MalformedURLException {
-    return new URL(resource.getProtocol(), resource.getHost(),
-        resource.getPort(), resource.getPath());
-  }
-  
-
-  private void addOpenSocialParams(List<Parameter> msgParams) {
-    String owner = authToken.getOwnerId();
-    if (owner != null) {
-      msgParams.add(new OAuth.Parameter(OPENSOCIAL_OWNERID, owner));
-    }
-    
-    String viewer = authToken.getViewerId();
-    if (viewer != null) {
-      msgParams.add(new OAuth.Parameter(OPENSOCIAL_VIEWERID, viewer));
-    }
-
-    String app = authToken.getAppId();
-    if (app != null) {
-      msgParams.add(new OAuth.Parameter(OPENSOCIAL_APPID, app));
-    }
-
-  }
-  
-  private void addOAuthParams(List<Parameter> msgParams) {
-    msgParams.add(new OAuth.Parameter(OAuth.OAUTH_TOKEN, ""));
-    
-    String domain = authToken.getDomain();
-    if (domain != null) {
-      msgParams.add(new OAuth.Parameter(OAuth.OAUTH_CONSUMER_KEY, domain));
-    }
-    
-    if (keyName != null) {
-      msgParams.add(new OAuth.Parameter(XOAUTH_PUBLIC_KEY, keyName));
-    }
-
-    String nonce = Long.toHexString(Crypto.rand.nextLong());
-    msgParams.add(new OAuth.Parameter(OAuth.OAUTH_NONCE, nonce));
-    
-    String timestamp = Long.toString(clock.currentTimeMillis()/1000L);
-    msgParams.add(new OAuth.Parameter(OAuth.OAUTH_TIMESTAMP, timestamp));
-
-    msgParams.add(new OAuth.Parameter(OAuth.OAUTH_SIGNATURE_METHOD,
-        OAuth.RSA_SHA1));
-  }
-
-  /**
-   * Sign a message and append the oauth signature parameter to the message
-   * object.
-   * 
-   * @param message the message to sign
-   * 
-   * @throws Exception because the OAuth libraries require it.
-   */
-  protected void signMessage(OAuthMessage message) throws Exception {
-    OAuthConsumer consumer = new OAuthConsumer(null, null, null, null);
-    consumer.setProperty(RSA_SHA1.PRIVATE_KEY, privateKeyObject);
-    OAuthAccessor accessor = new OAuthAccessor(consumer);
-    message.sign(accessor);
-  }
-  
-  /**
-   * Strip out any owner or viewer id passed by the client.
-   */
-  private List<Parameter> sanitize(List<Parameter> params) {
-    ArrayList<Parameter> list = new ArrayList<Parameter>();
-    for (Parameter p : params) {
-      if (allowParam(p.getKey())) {
-        list.add(p);
-      }
-    }
-    return list;
-  }
-
-  private boolean allowParam(String paramName) {
-    String canonParamName = paramName.toLowerCase();
-    return (!(canonParamName.startsWith("oauth") ||
-        canonParamName.startsWith("xoauth") ||
-        canonParamName.startsWith("opensocial")) &&
-        ALLOWED_PARAM_NAME.matcher(canonParamName).matches());
-  }
-
-
-}

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/CrossServletState.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/CrossServletState.java?rev=642404&r1=642403&r2=642404&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/CrossServletState.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/CrossServletState.java Fri Mar 28 15:05:22 2008
@@ -21,10 +21,12 @@
 
 import org.apache.shindig.gadgets.Gadget;
 import org.apache.shindig.gadgets.GadgetContext;
+import org.apache.shindig.gadgets.GadgetException;
 import org.apache.shindig.gadgets.GadgetServer;
 import org.apache.shindig.gadgets.GadgetSigner;
 import org.apache.shindig.gadgets.GadgetToken;
-import org.apache.shindig.gadgets.RequestSigner;
+import org.apache.shindig.gadgets.RemoteContentFetcher;
+import org.apache.shindig.util.BlobCrypter;
 
 import java.util.Set;
 import java.util.logging.Logger;
@@ -105,24 +107,16 @@
   public abstract String getIframeUrl(Gadget gadget);
 
   /**
-   * Constructs a RequestSigner object that can be used to sign requests from
-   * the given gadget token to implement signed fetch.
-   * 
+   * Constructs a RemoteFetcher object that signs requests and then forwards
+   * them to the next content fetcher in the chain.
+   *
+   * @param remoteFetcher 
    * @param token the decrypted, verified security token
    * @return a request signer implementing signed fetch.
    * 
-   * @see org.apache.shindig.gadgets.SignedFetchRequestSigner
-   */
-  public abstract RequestSigner makeSignedFetchRequestSigner(GadgetToken token);
-
-  /**
-   * Constructs a RequestSigner object that can be used to sign requests from
-   * the given gadget token to implement full OAuth.
-   * 
-   * @param token the decrypted, verified security token
-   * @return a request signer implementing signed fetch.
+   * @see org.apache.shindig.gadgets.SigningFetcher
    */
-  public abstract RequestSigner makeOAuthRequestSigner(GadgetToken token);
+  public abstract RemoteContentFetcher makeSigningFetcher(RemoteContentFetcher remoteFetcher, GadgetToken token);
 
   /**
    * Initializes this handler using the provided implementation.

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/DefaultCrossServletState.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/DefaultCrossServletState.java?rev=642404&r1=642403&r2=642404&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/DefaultCrossServletState.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/DefaultCrossServletState.java Fri Mar 28 15:05:22 2008
@@ -22,6 +22,7 @@
 import org.apache.shindig.gadgets.BasicGadgetBlacklist;
 import org.apache.shindig.gadgets.BasicGadgetSigner;
 import org.apache.shindig.gadgets.BasicRemoteContentFetcher;
+import org.apache.shindig.gadgets.DataFetcher;
 import org.apache.shindig.gadgets.Gadget;
 import org.apache.shindig.gadgets.GadgetContext;
 import org.apache.shindig.gadgets.GadgetException;
@@ -36,8 +37,7 @@
 import org.apache.shindig.gadgets.JsLibrary;
 import org.apache.shindig.gadgets.MessageBundleFetcher;
 import org.apache.shindig.gadgets.RemoteContentFetcher;
-import org.apache.shindig.gadgets.RequestSigner;
-import org.apache.shindig.gadgets.SignedFetchRequestSigner;
+import org.apache.shindig.gadgets.SigningFetcher;
 import org.apache.shindig.gadgets.SyndicatorConfig;
 import org.apache.shindig.gadgets.UserPrefs;
 import org.apache.shindig.gadgets.spec.GadgetSpec;
@@ -47,6 +47,8 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.net.URLEncoder;
 import java.util.Map;
 import java.util.Set;
@@ -227,12 +229,8 @@
   }
 
   @Override
-  public RequestSigner makeOAuthRequestSigner(GadgetToken token) {
-    return null;
-  }
-
-  @Override
-  public RequestSigner makeSignedFetchRequestSigner(GadgetToken token) {
+  public RemoteContentFetcher makeSigningFetcher(
+      RemoteContentFetcher fetcher, GadgetToken token) {
     // Real implementations should use their own key, probably pulled from
     // disk rather than hardcoded in the source.
     final String PRIVATE_KEY_TEXT =
@@ -251,7 +249,7 @@
       "AO/0isr/3aa6O6NLQxISLKcPDk2NOccAfS/xOtfOz4sJYM3+Bs4Io9+dZGSDCA54" +
       "Lw03eHTNQghS0A==";
     final String PRIVATE_KEY_NAME = "shindig-insecure-key";
-    return new SignedFetchRequestSigner(token, PRIVATE_KEY_NAME,
-        PRIVATE_KEY_TEXT);
+    return SigningFetcher.makeFromB64PrivateKey(
+        fetcher, token, PRIVATE_KEY_NAME, PRIVATE_KEY_TEXT);
   }
 }

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java?rev=642404&r1=642403&r2=642404&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java Fri Mar 28 15:05:22 2008
@@ -24,7 +24,6 @@
 import org.apache.shindig.gadgets.RemoteContent;
 import org.apache.shindig.gadgets.RemoteContentFetcher;
 import org.apache.shindig.gadgets.RemoteContentRequest;
-import org.apache.shindig.gadgets.RequestSigner;
 import org.apache.shindig.util.InputStreamConsumer;
 
 import org.json.JSONException;
@@ -32,15 +31,12 @@
 
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
-import java.net.MalformedURLException;
 import java.net.URI;
 import java.net.URISyntaxException;
-import java.net.URL;
 import java.net.URLDecoder;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Enumeration;
-import java.util.HashMap;
 import java.util.TreeMap;
 import java.util.HashSet;
 import java.util.List;
@@ -60,8 +56,10 @@
   private static final String NOCACHE_PARAM = "nocache";
   private static final String URL_PARAM = "url";
   private static final String AUTHZ_PARAM = "authz";
+  private static final String UNSIGNED_FETCH = "none";
+  private static final String SIGNED_FETCH = "signed";
   
-  private final RemoteContentFetcher fetcher;
+  private final RemoteContentFetcher remoteFetcher;
 
   private final static Set<String> DISALLOWED_RESPONSE_HEADERS
     = new HashSet<String>();
@@ -71,25 +69,49 @@
   }
 
   public ProxyHandler(RemoteContentFetcher fetcher) {
-    this.fetcher = fetcher;
+    this.remoteFetcher = fetcher;
   }
 
+  /**
+   * Information about our chain of RemoteContentFetchers.
+   *
+   * This class is kind of silly at the moment, but it'll be useful once
+   * we need to peek at the state of intermediate fetchers in the chain.
+   * (Which we will need to do for OAuth.)
+   */
+  private static class FetcherChain {
+    public RemoteContentFetcher fetcher;
+    
+    public FetcherChain(RemoteContentFetcher fetcher) {
+      this.fetcher = fetcher;
+    }
+  }
+  
   public void fetchJson(HttpServletRequest request,
                         HttpServletResponse response,
                         CrossServletState state)
       throws ServletException, IOException, GadgetException {
+    
+    // Build up the request to make
+    RemoteContentRequest rcr = buildRemoteContentRequest(request);
+    
+    // Figure out whether we need to sign the request
+    FetcherChain chain = buildFetcherChain(request, response, state);
+
+    // Dispatch the request and serialize the response.
+    RemoteContent results = chain.fetcher.fetch(rcr);
 
-    // Fetch the content and convert it into JSON.
-    RemoteContent results = fetchContent(request, state);
-    response.setStatus(HttpServletResponse.SC_OK);
     String output;
     try {
+      JSONObject resp = new JSONObject();
+      response.setStatus(HttpServletResponse.SC_OK);
+      if (results != null) {
+        resp.put("body", results.getResponseAsString());
+        resp.put("rc", results.getHttpStatusCode());
+      }
       // Use raw param as key as URL may have to be decoded
-      JSONObject resp = new JSONObject()
-          .put("body", results.getResponseAsString())
-          .put("rc", results.getHttpStatusCode());
-      String url = request.getParameter(URL_PARAM);
-      JSONObject json = new JSONObject().put(url, resp);
+      String originalUrl = request.getParameter(URL_PARAM);
+      JSONObject json = new JSONObject().put(originalUrl, resp);
       output = UNPARSEABLE_CRUFT + json.toString();
     } catch (JSONException e) {
       output = "";
@@ -100,67 +122,16 @@
     response.getWriter().write(output);
   }
 
-  public void fetch(HttpServletRequest request,
-                    HttpServletResponse response,
-                    CrossServletState state)
-      throws ServletException, IOException, GadgetException {
-    RemoteContent results = fetchContent(request, state);
-
-    if (request.getHeader("If-Modified-Since") != null) {
-      response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
-      return;
-    }
-
-    int status = results.getHttpStatusCode();
-    response.setStatus(status);
-    if (status == HttpServletResponse.SC_OK) {
-      Map<String, List<String>> headers = results.getAllHeaders();
-      if (headers.get("Cache-Control") == null) {
-        // Cache for 1 hour by default for images.
-        HttpUtil.setCachingHeaders(response, 60 * 60);
-      }
-      for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
-        String name = entry.getKey();
-        List<String> values = entry.getValue();
-        if (name != null && values != null
-            && !DISALLOWED_RESPONSE_HEADERS.contains(name.toLowerCase())) {
-          for (String value : values) {
-            response.addHeader(name, value);
-          }
-        }
-      }
-      response.getOutputStream().write(
-          InputStreamConsumer.readToByteArray(results.getResponse()));
-    }
-  }
-
-  /**
-   * Fetch the content for a request
-   *
-   * @param request
-   */
   @SuppressWarnings("unchecked")
-  private RemoteContent fetchContent(HttpServletRequest request,
-      CrossServletState state) throws ServletException, GadgetException {
-    String encoding = request.getCharacterEncoding();
-    if (encoding == null) {
-      encoding = "UTF-8";
-    }
-
+  private RemoteContentRequest buildRemoteContentRequest(HttpServletRequest request)
+  throws ServletException {
     try {
-      URL originalUrl = validateUrl(request.getParameter(URL_PARAM));
-      GadgetSigner signer = state.getGadgetSigner();
-      URL signedUrl;
-      if ("signed".equals(request.getParameter(AUTHZ_PARAM))) {
-        GadgetToken token = extractAndValidateToken(request, signer);
-        if (token == null) {
-          return new RemoteContent(HttpServletResponse.SC_UNAUTHORIZED,
-              "Invalid security token.".getBytes(), null);
-        }
-        signedUrl = signUrl(state, originalUrl, token, request);
-      } else {
-        signedUrl = originalUrl;
+
+      String encoding = request.getCharacterEncoding();
+      if (encoding == null) {
+        encoding = "UTF-8";
       }
+
       String method = request.getMethod();
       Map<String, List<String>> headers = null;
       byte[] postBody = null;
@@ -180,7 +151,8 @@
             String[] parts = header.split("=");
             if (parts.length != 2) {
               // Malformed headers
-              return RemoteContent.ERROR;
+              throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR,
+              "malformed header specified");
             }
             headers.put(URLDecoder.decode(parts[0], encoding),
                 Arrays.asList(URLDecoder.decode(parts[1], encoding)));
@@ -199,19 +171,93 @@
       removeUnsafeHeaders(headers);
 
       RemoteContentRequest.Options options
-          = new RemoteContentRequest.Options();
+        = new RemoteContentRequest.Options();
       options.ignoreCache = "1".equals(request.getParameter(NOCACHE_PARAM));
+      URI target = validateUrl(request.getParameter(URL_PARAM));
       RemoteContentRequest req = new RemoteContentRequest(
-          method, signedUrl.toURI(), headers, postBody, options);
-      return fetcher.fetch(req);
+          method, target, headers, postBody, options);
+
+      return req;
     } catch (UnsupportedEncodingException e) {
       throw new ServletException(e);
-    } catch (URISyntaxException e) {
+    } catch (GadgetException e) {
       throw new ServletException(e);
     }
   }
 
   /**
+   * At the moment our fetcher chain is short.  In the future we might add
+   * additional layers for things like caching or throttling.
+   */
+  private FetcherChain buildFetcherChain(HttpServletRequest request,
+      HttpServletResponse response, CrossServletState state) throws GadgetException {
+    String authzType = getParameter(request, AUTHZ_PARAM, "");
+    if (authzType.equals("") || authzType.equals(UNSIGNED_FETCH)) {
+      return new FetcherChain(remoteFetcher);
+    }
+    GadgetSigner signer = state.getGadgetSigner();
+    if (signer == null) {
+      throw new GadgetException(GadgetException.Code.UNSUPPORTED_FEATURE,
+          "authenticated makeRequest not supported");
+    } 
+    String tokenString = getParameter(request, SECURITY_TOKEN_PARAM, "");
+    GadgetToken securityToken = signer.createToken(tokenString);
+    if (securityToken == null) {
+      throw new GadgetException(GadgetException.Code.INVALID_GADGET_TOKEN);
+    }
+    RemoteContentFetcher realFetcher = null;
+    if (authzType.equals(SIGNED_FETCH)) {
+      realFetcher = state.makeSigningFetcher(remoteFetcher, securityToken);
+    }
+    if (realFetcher == null) {
+      throw new GadgetException(GadgetException.Code.UNSUPPORTED_FEATURE,
+          String.format("Unsupported auth type %s", authzType));
+    }
+    return new FetcherChain(realFetcher);
+  }
+
+  
+  /**
+   * This is called for embedding images inline in gadgets, e.g. via img src links
+   * created via IG_Embed.
+   */
+  public void fetch(HttpServletRequest request,
+                    HttpServletResponse response,
+                    CrossServletState state)
+      throws ServletException, IOException, GadgetException {
+    RemoteContentRequest rcr = buildRemoteContentRequest(request);
+    RemoteContent results = remoteFetcher.fetch(rcr);
+    
+    // TODO: why are we checking for caching headers *after* we sent the request?
+    if (request.getHeader("If-Modified-Since") != null) {
+      response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+      return;
+    }
+
+    int status = results.getHttpStatusCode();
+    response.setStatus(status);
+    if (status == HttpServletResponse.SC_OK) {
+      Map<String, List<String>> headers = results.getAllHeaders();
+      if (headers.get("Cache-Control") == null) {
+        // Cache for 1 hour by default for images.
+        HttpUtil.setCachingHeaders(response, 60 * 60);
+      }
+      for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
+        String name = entry.getKey();
+        List<String> values = entry.getValue();
+        if (name != null && values != null
+            && !DISALLOWED_RESPONSE_HEADERS.contains(name.toLowerCase())) {
+          for (String value : values) {
+            response.addHeader(name, value);
+          }
+        }
+      }
+      response.getOutputStream().write(
+          InputStreamConsumer.readToByteArray(results.getResponse()));
+    }
+  }
+
+  /**
    * Removes unsafe headers from the header set.
    * @param headers
    */
@@ -229,12 +275,14 @@
 
   /**
    * Validates that the given url is valid for this request.
+   * 
+   * non-private for testing only.
    *
    * @param urlToValidate
    * @return A URL object of the URL
    * @throws ServletException if the URL fails security checks or is malformed.
    */
-  private URL validateUrl(String urlToValidate) throws ServletException {
+   URI validateUrl(String urlToValidate) throws ServletException {
     if (urlToValidate == null) {
       throw new ServletException("url parameter is missing.");
     }
@@ -257,39 +305,10 @@
                       "/", url.getQuery(),
                       url.getFragment());
       }
-      return url.toURL();
+      return url;
     } catch (URISyntaxException use) {
       throw new ServletException("Malformed URL " + use.getMessage());
-    } catch (MalformedURLException mfe) {
-      throw new ServletException("Malformed URL " + mfe.getMessage());
     }
-  }
-
-  /**
-   * @param request
-   * @return A valid token for the given input.
-   * @throws GadgetException
-   */
-  private GadgetToken extractAndValidateToken(HttpServletRequest request,
-      GadgetSigner signer) throws GadgetException {
-    if (signer == null) {
-      return null;
-    }
-    String token = getParameter(request, SECURITY_TOKEN_PARAM, "");
-    return signer.createToken(token);
-  }
-
-  /**
-   * Sign a URL with a GadgetToken if needed
-   * @return The signed url.
-   */
-  @SuppressWarnings("unchecked")
-  private URL signUrl(CrossServletState state, URL originalUrl, GadgetToken token,
-      HttpServletRequest request) throws GadgetException {
-    String method = getParameter(request, METHOD_PARAM, "GET");
-    String body = getParameter(request, POST_DATA_PARAM, null);
-    RequestSigner signer = state.makeSignedFetchRequestSigner(token);
-    return signer.signRequest(method, originalUrl, body);
   }
 
   /**

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/GadgetDataHandler.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/GadgetDataHandler.java?rev=642404&r1=642403&r2=642404&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/GadgetDataHandler.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/GadgetDataHandler.java Fri Mar 28 15:05:22 2008
@@ -17,6 +17,8 @@
  */
 package org.apache.shindig.social;
 
+import org.apache.shindig.gadgets.GadgetException;
+
 public interface GadgetDataHandler {
   /**
    * Determines whether this handler should be used to process the request
@@ -32,6 +34,7 @@
    *
    * @param request The request from the json
    * @return The corresponding response item
+   * @throws GadgetException 
    */
-  ResponseItem handleRequest(RequestItem request);
+  ResponseItem handleRequest(RequestItem request) throws GadgetException;
 }

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/opensocial/ActivitiesService.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/opensocial/ActivitiesService.java?rev=642404&r1=642403&r2=642404&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/opensocial/ActivitiesService.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/opensocial/ActivitiesService.java Fri Mar 28 15:05:22 2008
@@ -17,6 +17,7 @@
  */
 package org.apache.shindig.social.opensocial;
 
+import org.apache.shindig.gadgets.GadgetException;
 import org.apache.shindig.gadgets.GadgetToken;
 
 import org.apache.shindig.social.ResponseItem;
@@ -30,9 +31,10 @@
    * @param ids The ids of the people to fetch activities for.
    * @param token A valid GadgetToken
    * @return a response item with the list of activities.
+   * @throws GadgetException 
    */
   public ResponseItem<List<Activity>> getActivities(List<String> ids,
-      GadgetToken token);
+      GadgetToken token) throws GadgetException;
 
   /**
    * Creates the passed in activity for the given user. Once createActivity is
@@ -41,7 +43,8 @@
    * @param activity The activity to create.
    * @param token A valid GadgetToken
    * @return a response item containing any errors
+   * @throws GadgetException 
    */
   public ResponseItem createActivity(String personId, Activity activity,
-      GadgetToken token);
+      GadgetToken token) throws GadgetException;
 }

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/opensocial/DataService.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/opensocial/DataService.java?rev=642404&r1=642403&r2=642404&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/opensocial/DataService.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/opensocial/DataService.java Fri Mar 28 15:05:22 2008
@@ -18,6 +18,7 @@
 package org.apache.shindig.social.opensocial;
 
 import org.apache.shindig.social.ResponseItem;
+import org.apache.shindig.gadgets.GadgetException;
 import org.apache.shindig.gadgets.GadgetToken;
 
 import java.util.List;
@@ -32,9 +33,10 @@
    * @param token The GadgetToken for this request
    * @return ResponseItem a response item with the error code set if
    *     there was a problem
+   * @throws GadgetException 
    */
   public ResponseItem<Map<String, Map<String, String>>> getPersonData(
-      List<String> ids, List<String> keys, GadgetToken token);
+      List<String> ids, List<String> keys, GadgetToken token) throws GadgetException;
 
   /**
    * Updates the data key for the given person with the new value.
@@ -45,7 +47,8 @@
    * @param token The GadgetToken for this request
    * @return ResponseItem a response item with the error code set if
    *     there was a problem
+   * @throws GadgetException 
    */
   public ResponseItem updatePersonData(String id, String key,
-      String value, GadgetToken token);
+      String value, GadgetToken token) throws GadgetException;
 }

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/opensocial/OpenSocialDataHandler.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/opensocial/OpenSocialDataHandler.java?rev=642404&r1=642403&r2=642404&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/opensocial/OpenSocialDataHandler.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/opensocial/OpenSocialDataHandler.java Fri Mar 28 15:05:22 2008
@@ -21,6 +21,7 @@
 import org.json.JSONObject;
 import org.json.JSONArray;
 
+import org.apache.shindig.gadgets.GadgetException;
 import org.apache.shindig.gadgets.GadgetToken;
 
 import org.apache.shindig.social.samplecontainer.BasicPeopleService;
@@ -76,7 +77,7 @@
     }
   }
 
-  public ResponseItem handleRequest(RequestItem request) {
+  public ResponseItem handleRequest(RequestItem request) throws GadgetException {
     OpenSocialDataType type = OpenSocialDataType.valueOf(request.getType());
     ResponseItem response = new ResponseItem<Object>(
         ResponseError.NOT_IMPLEMENTED,

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/opensocial/PeopleService.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/opensocial/PeopleService.java?rev=642404&r1=642403&r2=642404&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/opensocial/PeopleService.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/opensocial/PeopleService.java Fri Mar 28 15:05:22 2008
@@ -22,6 +22,7 @@
 import org.apache.shindig.social.opensocial.model.IdSpec;
 import org.apache.shindig.social.opensocial.model.ApiCollection;
 import org.apache.shindig.social.ResponseItem;
+import org.apache.shindig.gadgets.GadgetException;
 import org.apache.shindig.gadgets.GadgetToken;
 
 import java.util.List;
@@ -35,9 +36,10 @@
    * @param idSpec The idSpec to translate into ids
    * @return a list of person ids
    * @throws JSONException If the idSpec is malformed
+   * @throws GadgetException 
    */
   public List<String> getIds(IdSpec idSpec, GadgetToken token)
-      throws JSONException;
+      throws JSONException, GadgetException;
 
   public enum SortOrder {
     topFriends, name
@@ -55,8 +57,9 @@
    * @param first The index of the first person to fetch.
    * @param max The max number of people to fetch.
    * @return a list of people.
+   * @throws GadgetException 
    */
   public ResponseItem<ApiCollection<Person>> getPeople(List<String> ids,
       SortOrder sortOrder, FilterType filter, int first, int max,
-      Set<String> profileDetails, GadgetToken token);
+      Set<String> profileDetails, GadgetToken token) throws GadgetException;
 }

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/samplecontainer/BasicActivitiesService.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/samplecontainer/BasicActivitiesService.java?rev=642404&r1=642403&r2=642404&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/samplecontainer/BasicActivitiesService.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/samplecontainer/BasicActivitiesService.java Fri Mar 28 15:05:22 2008
@@ -17,6 +17,7 @@
  */
 package org.apache.shindig.social.samplecontainer;
 
+import org.apache.shindig.gadgets.GadgetException;
 import org.apache.shindig.gadgets.GadgetToken;
 
 import org.apache.shindig.social.ResponseItem;
@@ -34,7 +35,7 @@
  */
 public class BasicActivitiesService implements ActivitiesService {
   public ResponseItem<List<Activity>> getActivities(List<String> ids, 
-      GadgetToken token) {
+      GadgetToken token) throws GadgetException {
     Map<String, List<Activity>> allActivities =
         XmlStateFileFetcher.get().getActivities();
 
@@ -52,7 +53,7 @@
   }
 
   public ResponseItem createActivity(String personId, Activity activity, 
-        GadgetToken token) {
+        GadgetToken token) throws GadgetException {
     // TODO: Validate the activity and do any template expanding
     activity.setUserId(personId);
     activity.setPostedTime(new Date().getTime());

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/samplecontainer/BasicDataService.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/samplecontainer/BasicDataService.java?rev=642404&r1=642403&r2=642404&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/samplecontainer/BasicDataService.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/samplecontainer/BasicDataService.java Fri Mar 28 15:05:22 2008
@@ -17,6 +17,7 @@
  */
 package org.apache.shindig.social.samplecontainer;
 
+import org.apache.shindig.gadgets.GadgetException;
 import org.apache.shindig.gadgets.GadgetToken;
 import org.apache.shindig.social.ResponseError;
 import org.apache.shindig.social.ResponseItem;
@@ -30,7 +31,7 @@
 public class BasicDataService implements DataService {
 
   public ResponseItem<Map<String, Map<String, String>>> getPersonData(
-        List<String> ids, List<String> keys, GadgetToken token) {
+        List<String> ids, List<String> keys, GadgetToken token) throws GadgetException {
 
     Map<String, Map<String, String>> allData
         = XmlStateFileFetcher.get().getAppData();
@@ -57,7 +58,7 @@
   }
 
   public ResponseItem updatePersonData(String id, String key, String value,
-      GadgetToken token) {
+      GadgetToken token) throws GadgetException {
     if (!isValidKey(key)) {
       return new ResponseItem<Object>(ResponseError.BAD_REQUEST,
           "The person data key had invalid characters",

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/samplecontainer/BasicPeopleService.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/samplecontainer/BasicPeopleService.java?rev=642404&r1=642403&r2=642404&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/samplecontainer/BasicPeopleService.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/samplecontainer/BasicPeopleService.java Fri Mar 28 15:05:22 2008
@@ -22,6 +22,7 @@
 import org.apache.shindig.social.opensocial.model.IdSpec;
 import org.apache.shindig.social.opensocial.model.Person;
 import org.apache.shindig.social.opensocial.model.ApiCollection;
+import org.apache.shindig.gadgets.GadgetException;
 import org.apache.shindig.gadgets.GadgetToken;
 import org.json.JSONException;
 
@@ -44,7 +45,7 @@
 
   public ResponseItem<ApiCollection<Person>> getPeople(List<String> ids,
       SortOrder sortOrder, FilterType filter, int first, int max, 
-      Set<String> profileDetails, GadgetToken token) {
+      Set<String> profileDetails, GadgetToken token) throws GadgetException {
     Map<String, Person> allPeople = XmlStateFileFetcher.get().getAllPeople();
 
     List<Person> people = new ArrayList<Person>();
@@ -79,7 +80,7 @@
   }
 
   public List<String> getIds(IdSpec idSpec, GadgetToken token)
-      throws JSONException {
+      throws JSONException, GadgetException {
     Map<String, List<String>> friendIds
         = XmlStateFileFetcher.get().getFriendIds();
 

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/samplecontainer/StateFileDataHandler.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/samplecontainer/StateFileDataHandler.java?rev=642404&r1=642403&r2=642404&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/samplecontainer/StateFileDataHandler.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/samplecontainer/StateFileDataHandler.java Fri Mar 28 15:05:22 2008
@@ -19,6 +19,7 @@
 
 import org.json.JSONException;
 import org.json.JSONObject;
+import org.apache.shindig.gadgets.GadgetException;
 import org.apache.shindig.social.ResponseItem;
 import org.apache.shindig.social.ResponseError;
 import org.apache.shindig.social.GadgetDataHandler;
@@ -49,7 +50,7 @@
     }
   }
 
-  public ResponseItem handleRequest(RequestItem request) {
+  public ResponseItem handleRequest(RequestItem request) throws GadgetException {
     RequestType type = RequestType.valueOf(request.getType());
     ResponseItem response = null;
 
@@ -93,4 +94,4 @@
 
     return response;
   }
-}
\ No newline at end of file
+}

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/samplecontainer/XmlStateFileFetcher.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/samplecontainer/XmlStateFileFetcher.java?rev=642404&r1=642403&r2=642404&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/samplecontainer/XmlStateFileFetcher.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/samplecontainer/XmlStateFileFetcher.java Fri Mar 28 15:05:22 2008
@@ -1,6 +1,7 @@
 package org.apache.shindig.social.samplecontainer;
 
 import org.apache.shindig.gadgets.BasicRemoteContentFetcher;
+import org.apache.shindig.gadgets.GadgetException;
 import org.apache.shindig.gadgets.RemoteContent;
 import org.apache.shindig.gadgets.RemoteContentFetcher;
 import org.apache.shindig.gadgets.RemoteContentRequest;
@@ -94,7 +95,7 @@
     this.doEvil = doEvil;
   }
 
-  private Document fetchStateDocument() {
+  private Document fetchStateDocument() throws GadgetException {
     if (document != null) {
       return document;
     }
@@ -130,14 +131,14 @@
     }
   }
 
-  public Map<String, Map<String, String>> getAppData() {
+  public Map<String, Map<String, String>> getAppData() throws GadgetException {
     if (allData == null) {
       setupAppData();
     }
     return allData;
   }
 
-  private void setupAppData() {
+  private void setupAppData() throws GadgetException {
     allData = new HashMap<String, Map<String, String>>();
 
     Element root = fetchStateDocument().getDocumentElement();
@@ -165,7 +166,7 @@
     }
   }
 
-  public void setAppData(String id, String key, String value) {
+  public void setAppData(String id, String key, String value) throws GadgetException {
     if (allData == null) {
       setupAppData();
     }
@@ -179,21 +180,21 @@
     personData.put(key, value);
   }
 
-  public Map<String, List<String>> getFriendIds() {
+  public Map<String, List<String>> getFriendIds() throws GadgetException {
     if (friendIdMap == null) {
       setupPeopleData();
     }
     return friendIdMap;
   }
 
-  public Map<String, Person> getAllPeople() {
+  public Map<String, Person> getAllPeople() throws GadgetException {
     if (allPeople == null) {
       setupPeopleData();
     }
     return allPeople;
   }
 
-  private void setupPeopleData() {
+  private void setupPeopleData() throws GadgetException {
     Element root = fetchStateDocument().getDocumentElement();
 
     allPeople = new HashMap<String, Person>();
@@ -258,7 +259,7 @@
     return friends;
   }
 
-  public Map<String, List<Activity>> getActivities() {
+  public Map<String, List<Activity>> getActivities() throws GadgetException {
     if (allActivities == null) {
       setupActivities();
     }
@@ -266,7 +267,7 @@
     return allActivities;
   }
 
-  private void setupActivities() {
+  private void setupActivities() throws GadgetException {
     allActivities = new HashMap<String, List<Activity>>();
 
     Element root = fetchStateDocument().getDocumentElement();
@@ -290,7 +291,7 @@
   }
 
   private void createActivities(Node streamItem, String userId,
-      String streamTitle) {
+      String streamTitle) throws GadgetException {
     NodeList activityItems = streamItem.getChildNodes();
     if (activityItems != null) {
       for (int i = 0; i < activityItems.getLength(); i++) {
@@ -336,7 +337,7 @@
     return media;
   }
 
-  public void createActivity(String userId, Activity activity) {
+  public void createActivity(String userId, Activity activity) throws GadgetException {
     if (allActivities == null) {
       setupActivities();
     }

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=642404&r1=642403&r2=642404&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 Mar 28 15:05:22 2008
@@ -22,16 +22,18 @@
 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.Iterator;
 import java.util.Map;
 
 /**
  * Utility class 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.
+ * 
+ * Thread safe.
  */
 public class BlobCrypter {
 
@@ -174,8 +176,8 @@
     String[] items = base.split("[&=]");
     Map<String, String> map = new HashMap<String, String>();
     for (int i=0; i < items.length; ) {
-      String key = items[i++];
-      String val = items[i++];
+      String key = URLDecoder.decode(items[i++], UTF8);
+      String val = URLDecoder.decode(items[i++], UTF8);
       map.put(key, val);
     }
     return map;

Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/EasyMockTestCase.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/EasyMockTestCase.java?rev=642404&r1=642403&r2=642404&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/EasyMockTestCase.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/EasyMockTestCase.java Fri Mar 28 15:05:22 2008
@@ -17,7 +17,7 @@
  */
 package org.apache.shindig.gadgets;
 
-import org.easymock.EasyMock;
+import org.easymock.classextension.EasyMock;
 
 import junit.framework.TestCase;
 

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=642404&r1=642403&r2=642404&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 Mar 28 15:05:22 2008
@@ -93,12 +93,7 @@
     }
 
     @Override
-    public RequestSigner makeOAuthRequestSigner(GadgetToken token) {
-      return null;
-    }
-
-    @Override
-    public RequestSigner makeSignedFetchRequestSigner(GadgetToken token) {
+    public RemoteContentFetcher makeSigningFetcher(RemoteContentFetcher fetcher, GadgetToken token) {
       // Real implementations should use their own key, probably pulled from
       // disk rather than hardcoded in the source.
       final String PRIVATE_KEY_TEXT =
@@ -117,8 +112,8 @@
         "AO/0isr/3aa6O6NLQxISLKcPDk2NOccAfS/xOtfOz4sJYM3+Bs4Io9+dZGSDCA54" +
         "Lw03eHTNQghS0A==";
       final String PRIVATE_KEY_NAME = "shindig-insecure-key";
-      return new SignedFetchRequestSigner(token, PRIVATE_KEY_NAME,
-          PRIVATE_KEY_TEXT);
+      return SigningFetcher.makeFromB64PrivateKey(
+          fetcher, token, PRIVATE_KEY_NAME, PRIVATE_KEY_TEXT);
     }
   };
 

Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/JsLibraryTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/JsLibraryTest.java?rev=642404&r1=642403&r2=642404&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/JsLibraryTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/JsLibraryTest.java Fri Mar 28 15:05:22 2008
@@ -34,7 +34,7 @@
         "};";
   private final static String URL_JS = "while(true){alert('hello');}";
 
-  public void testInline() {
+  public void testInline() throws GadgetException {
     JsLibrary lib
         = JsLibrary.create(JsLibrary.Type.INLINE, INLINE_JS, null, null);
     assertEquals(JsLibrary.Type.INLINE, lib.getType());

Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/SignedFetchRequestSignerTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/SignedFetchRequestSignerTest.java?rev=642404&r1=642403&r2=642404&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/SignedFetchRequestSignerTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/SignedFetchRequestSignerTest.java Fri Mar 28 15:05:22 2008
@@ -1,225 +0,0 @@
-/*
- * Licensed 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;
-
-import junit.framework.Assert;
-import junit.framework.TestCase;
-
-import net.oauth.OAuth;
-import net.oauth.OAuthAccessor;
-import net.oauth.OAuthConsumer;
-import net.oauth.OAuthMessage;
-import net.oauth.OAuth.Parameter;
-import net.oauth.signature.RSA_SHA1;
-
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.List;
-
-
-/**
- * Tests the signed fetch code.
- */
-public class SignedFetchRequestSignerTest extends TestCase {
-  private static final String PRIVATE_KEY_TEXT =
-    "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALRiMLAh9iimur8V" +
-    "A7qVvdqxevEuUkW4K+2KdMXmnQbG9Aa7k7eBjK1S+0LYmVjPKlJGNXHDGuy5Fw/d" +
-    "7rjVJ0BLB+ubPK8iA/Tw3hLQgXMRRGRXXCn8ikfuQfjUS1uZSatdLB81mydBETlJ" +
-    "hI6GH4twrbDJCR2Bwy/XWXgqgGRzAgMBAAECgYBYWVtleUzavkbrPjy0T5FMou8H" +
-    "X9u2AC2ry8vD/l7cqedtwMPp9k7TubgNFo+NGvKsl2ynyprOZR1xjQ7WgrgVB+mm" +
-    "uScOM/5HVceFuGRDhYTCObE+y1kxRloNYXnx3ei1zbeYLPCHdhxRYW7T0qcynNmw" +
-    "rn05/KO2RLjgQNalsQJBANeA3Q4Nugqy4QBUCEC09SqylT2K9FrrItqL2QKc9v0Z" +
-    "zO2uwllCbg0dwpVuYPYXYvikNHHg+aCWF+VXsb9rpPsCQQDWR9TT4ORdzoj+Nccn" +
-    "qkMsDmzt0EfNaAOwHOmVJ2RVBspPcxt5iN4HI7HNeG6U5YsFBb+/GZbgfBT3kpNG" +
-    "WPTpAkBI+gFhjfJvRw38n3g/+UeAkwMI2TJQS4n8+hid0uus3/zOjDySH3XHCUno" +
-    "cn1xOJAyZODBo47E+67R4jV1/gzbAkEAklJaspRPXP877NssM5nAZMU0/O/NGCZ+" +
-    "3jPgDUno6WbJn5cqm8MqWhW1xGkImgRk+fkDBquiq4gPiT898jusgQJAd5Zrr6Q8" +
-    "AO/0isr/3aa6O6NLQxISLKcPDk2NOccAfS/xOtfOz4sJYM3+Bs4Io9+dZGSDCA54" +
-    "Lw03eHTNQghS0A==";
-
-  private static final String CERTIFICATE_TEXT =
-    "-----BEGIN CERTIFICATE-----\n" +
-    "MIIBpjCCAQ+gAwIBAgIBATANBgkqhkiG9w0BAQUFADAZMRcwFQYDVQQDDA5UZXN0\n" +
-    "IFByaW5jaXBhbDAeFw03MDAxMDEwODAwMDBaFw0zODEyMzEwODAwMDBaMBkxFzAV\n" +
-    "BgNVBAMMDlRlc3QgUHJpbmNpcGFsMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\n" +
-    "gQC0YjCwIfYoprq/FQO6lb3asXrxLlJFuCvtinTF5p0GxvQGu5O3gYytUvtC2JlY\n" +
-    "zypSRjVxwxrsuRcP3e641SdASwfrmzyvIgP08N4S0IFzEURkV1wp/IpH7kH41Etb\n" +
-    "mUmrXSwfNZsnQRE5SYSOhh+LcK2wyQkdgcMv11l4KoBkcwIDAQABMA0GCSqGSIb3\n" +
-    "DQEBBQUAA4GBAGZLPEuJ5SiJ2ryq+CmEGOXfvlTtEL2nuGtr9PewxkgnOjZpUy+d\n" +
-    "4TvuXJbNQc8f4AMWL/tO9w0Fk80rWKp9ea8/df4qMq5qlFWlx6yOLQxumNOmECKb\n" +
-    "WpkUQDIDJEoFUzKMVuJf4KO/FJ345+BNLGgbJ6WujreoM1X/gYfdnJ/J\n" +
-    "-----END CERTIFICATE-----";
-
-  private SignedFetchRequestSigner signer;
-  private BasicGadgetToken authToken;
-  private OAuthAccessor accessor;
-  
-  @Override
-  public void setUp() throws Exception {
-    authToken = new BasicGadgetToken("o", "v", "a", "d");
-    signer = new SignedFetchRequestSigner(authToken, "foo", PRIVATE_KEY_TEXT);
-    OAuthConsumer consumer = new OAuthConsumer(null, null, null, null);
-    consumer.setProperty(RSA_SHA1.X509_CERTIFICATE, CERTIFICATE_TEXT);
-    accessor = new OAuthAccessor(consumer);
-  }
-  
-  public void testParametersSet() throws Exception {
-    URL unsigned = new URL("http://test");
-    URL out = signer.signRequest("GET", unsigned, null);
-    List<OAuth.Parameter> queryParams = OAuth.decodeForm(out.getQuery());
-    Assert.assertTrue(contains(queryParams, "opensocial_owner_id", "o"));
-    Assert.assertTrue(contains(queryParams, "opensocial_viewer_id", "v"));
-    Assert.assertTrue(contains(queryParams, "opensocial_app_id", "a"));
-    Assert.assertTrue(contains(queryParams, OAuth.OAUTH_CONSUMER_KEY, "d"));
-    Assert.assertTrue(
-        contains(queryParams, "xoauth_signature_publickey", "foo"));
-  }
-  
-  public void testTrickyParametersInQuery() throws Exception {
-    String tricky = "%6fpensocial_owner_id=gotcha";
-    URL unsigned = new URL("http://test?" + tricky);
-    URL out = signer.signRequest("GET", unsigned, null);
-    Assert.assertFalse(out.getQuery().contains("gotcha"));
-    assertSignatureOK("GET", out.toString(), null);
-  }
-  
-  public void testTrickyParametersInBody() throws Exception {
-    URL unsigned = new URL("http://test");
-    String tricky = "%6fpensocial_owner_id=gotcha";
-    URL out = signer.signRequest("POST", unsigned, tricky);
-    assertSignatureInvalid("POST", out.toString(), tricky);       
-  }
-  
-  public void testGetNoQuery() throws Exception {
-    URL unsigned = new URL("http://test");
-    URL out = signer.signRequest("GET", unsigned, null);
-    assertSignatureOK("GET", out.toString(), null);
-  }
-  
-  public void testGetWithQuery() throws Exception {
-    URL unsigned = new URL("http://test?a=b");
-    URL out = signer.signRequest("GET", unsigned, null);
-    List<OAuth.Parameter> queryParams = OAuth.decodeForm(out.getQuery());
-    Assert.assertTrue(contains(queryParams, "a", "b"));
-    assertSignatureOK("GET", out.toString(), null);
-  }
-
-
-  public void testGetWithQueryMultiParam() throws Exception {
-    URL unsigned = new URL("http://test?a=b&a=c");
-    URL out = signer.signRequest("GET", unsigned, null);
-    List<OAuth.Parameter> queryParams = OAuth.decodeForm(out.getQuery());
-    Assert.assertTrue(contains(queryParams, "a", "b"));
-    Assert.assertTrue(contains(queryParams, "a", "c"));
-    assertSignatureOK("GET", out.toString(), null);
-  }
-  
-  public void testPostNoQueryNoData() throws Exception {
-    URL unsigned = new URL("http://test");
-    URL out = signer.signRequest("POST", unsigned, null);
-    assertSignatureOK("POST", out.toString(), null);    
-  }
-  
-  public void testPostWithQueryNoData() throws Exception {
-    URL unsigned =  new URL("http://test?name=value");
-    URL out = signer.signRequest("POST", unsigned, null);
-    List<OAuth.Parameter> queryParams = OAuth.decodeForm(out.getQuery());
-    Assert.assertTrue(contains(queryParams, "name", "value"));
-    assertSignatureOK("POST", out.toString(), null);    
-  }
-  
-  public void testPostNoQueryWithData() throws Exception {
-    URL unsigned =  new URL("http://test");
-    URL out = signer.signRequest("POST", unsigned, "name=value");
-    List<OAuth.Parameter> queryParams = OAuth.decodeForm(out.getQuery());
-    Assert.assertFalse(contains(queryParams, "name", "value"));
-    assertSignatureOK("POST", out.toString(), "name=value");    
-  }
-  
-  public void testPostWithQueryWithData() throws Exception {
-    URL unsigned =  new URL("http://test?queryName=queryValue");
-    URL out = signer.signRequest("POST", unsigned, "name=value");
-    List<OAuth.Parameter> queryParams = OAuth.decodeForm(out.getQuery());
-    Assert.assertTrue(contains(queryParams, "queryName", "queryValue"));
-    assertSignatureOK("POST", out.toString(), "name=value");    
-  }
-  
-  public void testStripOpenSocialParamsFromQuery() throws Exception {
-    URL unsigned =  new URL("http://test?opensocial_foo=bar");
-    URL out = signer.signRequest("POST", unsigned, "name=value");
-    List<OAuth.Parameter> queryParams = OAuth.decodeForm(out.getQuery());
-    Assert.assertFalse(contains(queryParams, "opensocial_foo", "bar"));
-    assertSignatureOK("POST", out.toString(), "name=value");       
-  }
-  
-  public void testStripOAuthParamsFromQuery() throws Exception {
-    URL unsigned =  new URL("http://test?oauth_foo=bar");
-    URL out = signer.signRequest("POST", unsigned, "name=value");
-    List<OAuth.Parameter> queryParams = OAuth.decodeForm(out.getQuery());
-    Assert.assertFalse(contains(queryParams, "oauth_foo", "bar"));
-    assertSignatureOK("POST", out.toString(), "name=value");       
-  }
-
-  public void testStripOpenSocialParamsFromBody() throws Exception {
-    URL unsigned =  new URL("http://test");
-    URL out = signer.signRequest("POST", unsigned, "opensocial_foo=bar");
-    assertSignatureInvalid("POST", out.toString(), "opensocial_foo=bar");       
-  }
-  
-  public void testStripOAuthParamsFromBody() throws Exception {
-    URL unsigned =  new URL("http://test");
-    URL out = signer.signRequest("POST", unsigned, "oauth_foo=bar");
-    assertSignatureInvalid("POST", out.toString(), "oauth_foo=bar");       
-  }
-  
-  private void assertSignatureOK(String method, String urlStr, String body)
-  throws Exception {
-    URL url = new URL(urlStr);
-    URL noQuery = new URL(url.getProtocol(), url.getHost(), url.getPort(),
-        url.getPath());
-    List<OAuth.Parameter> queryParams = OAuth.decodeForm(url.getQuery());
-    List<OAuth.Parameter> postParams = OAuth.decodeForm(body);
-    
-    ArrayList<OAuth.Parameter> msgParams = new ArrayList<OAuth.Parameter>();
-    msgParams.addAll(queryParams);
-    msgParams.addAll(postParams);
-    
-    OAuthMessage message = new OAuthMessage(method, noQuery.toString(),
-        msgParams);
-
-    // Throws on failure
-    message.validateSignature(accessor);
-  }
-  
-  private void assertSignatureInvalid(String method, String urlStr, String body) {
-    try {
-      assertSignatureOK(method, urlStr, body);
-      fail("Signature verification should have failed");
-    } catch (Exception e) {
-      // good
-    }
-  }
-  
-  // Checks whether the given parameter list contains the specified
-  // key/value pair
-  private boolean contains(List<Parameter> params, String key, String value) {
-    for (Parameter p : params) {
-      if (p.getKey().equals(key) && p.getValue().equals(value)) {
-        return true;
-      }
-    }
-    return false;
-  }
-}

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=642404&r1=642403&r2=642404&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 Mar 28 15:05:22 2008
@@ -25,6 +25,7 @@
 import java.io.PrintWriter;
 import java.net.URI;
 
+import org.apache.shindig.gadgets.GadgetException;
 import org.apache.shindig.gadgets.GadgetTestFixture;
 import org.apache.shindig.gadgets.RemoteContent;
 import org.apache.shindig.gadgets.RemoteContentRequest;
@@ -142,17 +143,54 @@
     writer.close();
   }
 
+  public void testSignedPostRequest() throws Exception {
+    String postBody = "foo=bar%20baz";
+    setupPostRequestMock(URL_ONE, postBody);
+    expect(request.getParameter("st")).andReturn("fake-token").atLeastOnce();
+    expect(request.getParameter("authz")).andReturn("signed").atLeastOnce();
+    RemoteContent resp = new RemoteContent(200, DATA_ONE.getBytes(), null);
+    expect(fetcher.fetch(
+        looksLikeSignedFetch(URL_ONE, postBody.getBytes()))).andReturn(resp);
+    replay();
+    proxyHandler.fetchJson(request, response, state);
+    verify();
+    writer.close();
+  }
+  
+  public void testInvalidSigningType() throws Exception {
+    setupGetRequestMock(URL_ONE);
+    expect(request.getParameter("st")).andReturn("fake-token").atLeastOnce();
+    expect(request.getParameter("authz")).andReturn("garbage").atLeastOnce();
+    replay();
+    try {
+      proxyHandler.fetchJson(request, response, state);
+      fail("proxyHandler accepted invalid authz type");
+    } catch (GadgetException e) {
+      assertEquals(GadgetException.Code.UNSUPPORTED_FEATURE, e.getCode());
+    }
+  }
+  
   private RemoteContentRequest looksLikeSignedFetch(String url) {
-    EasyMock.reportMatcher(new SignedFetchArgumentMatcher(url));
+    return looksLikeSignedFetch(url, null);
+  }
+  
+  private RemoteContentRequest looksLikeSignedFetch(String url, byte[] postBody) {
+    EasyMock.reportMatcher(new SignedFetchArgumentMatcher(url, postBody));
     return null;
   }
 
   private class SignedFetchArgumentMatcher implements IArgumentMatcher {
 
     private String expectedUrl;
+    private byte[] postBody;
 
     public SignedFetchArgumentMatcher(String expectedUrl) {
+      this(expectedUrl, null);
+    }
+    
+    public SignedFetchArgumentMatcher(String expectedUrl, byte[] postBody) {
       this.expectedUrl = expectedUrl;
+      this.postBody = postBody;
     }
 
     public void appendTo(StringBuffer sb) {
@@ -164,11 +202,95 @@
     public boolean matches(Object arg0) {
       RemoteContentRequest request = (RemoteContentRequest)arg0;
       String url = request.getUri().toASCIIString();
-      return (url.startsWith(expectedUrl) &&
-          url.contains("opensocial_owner_id") &&
+      if (url.startsWith(expectedUrl) &&
+          url.contains("opensocial_owner_id") && 
           url.contains("opensocial_viewer_id") &&
-          url.contains("opensocial_app_id"));
+          url.contains("opensocial_app_id") &&
+          byteArrayEquals(postBody, request.getPostBodyBytes())) {
+        return true;
+      }
+      return false;
     }
 
+    private boolean byteArrayEquals(byte[] expected, byte[] actual) {
+      if (expected == null) {
+        expected = new byte[0];
+      }
+      if (actual == null) {
+        actual = new byte[0];
+      }
+      if (expected.length != actual.length) {
+        return false;
+      }
+      for (int i=0; i < expected.length; i++) {
+        if (expected[i] != actual[i]) {
+          return false;
+        }
+      }
+      return true;
+    }
+  }
+  
+  public void testValidateUrlNoPath() throws Exception {
+    URI url = proxyHandler.validateUrl("http://www.example.com");
+    assertEquals("http", url.getScheme());
+    assertEquals("www.example.com", url.getHost());
+    assertEquals(-1, url.getPort());
+    assertEquals("/", url.getPath());
+    assertNull(url.getQuery());
+    assertNull(url.getFragment());
+  }
+  
+  public void testValidateUrlWithPath() throws Exception {
+    URI url = proxyHandler.validateUrl("http://www.example.com/foo");
+    assertEquals("http", url.getScheme());
+    assertEquals("www.example.com", url.getHost());
+    assertEquals(-1, url.getPort());
+    assertEquals("/foo", url.getPath());
+    assertNull(url.getQuery());
+    assertNull(url.getFragment());
+  }
+  
+  public void testValidateUrlWithPort() throws Exception {
+    URI url = proxyHandler.validateUrl("http://www.example.com:8080/foo");
+    assertEquals("http", url.getScheme());
+    assertEquals("www.example.com", url.getHost());
+    assertEquals(8080, url.getPort());
+    assertEquals("/foo", url.getPath());
+    assertNull(url.getQuery());
+    assertNull(url.getFragment());
+  }
+  
+  public void testValidateUrlWithEncodedPath() throws Exception {
+    URI url = proxyHandler.validateUrl("http://www.example.com:8080/foo%20bar");
+    assertEquals("http", url.getScheme());
+    assertEquals("www.example.com", url.getHost());
+    assertEquals(8080, url.getPort());
+    assertEquals("/foo%20bar", url.getRawPath());
+    assertEquals("/foo bar", url.getPath());
+    assertNull(url.getQuery());
+    assertNull(url.getFragment());    
+  }
+  
+  public void testValidateUrlWithEncodedQuery() throws Exception {
+    URI url = proxyHandler.validateUrl("http://www.example.com:8080/foo?q=with%20space");
+    assertEquals("http", url.getScheme());
+    assertEquals("www.example.com", url.getHost());
+    assertEquals(8080, url.getPort());
+    assertEquals("/foo", url.getPath());
+    assertEquals("q=with%20space", url.getRawQuery());
+    assertEquals("q=with space", url.getQuery());
+    assertNull(url.getFragment());    
+  }
+  
+  public void testValidateUrlWithNoPathAndEncodedQuery() throws Exception {
+    URI url = proxyHandler.validateUrl("http://www.example.com?q=with%20space");
+    assertEquals("http", url.getScheme());
+    assertEquals("www.example.com", url.getHost());
+    assertEquals(-1, url.getPort());
+    assertEquals("/", url.getPath());
+    assertEquals("q=with%20space", url.getRawQuery());
+    assertEquals("q=with space", url.getQuery());
+    assertNull(url.getFragment());        
   }
 }

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=642404&r1=642403&r2=642404&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 Mar 28 15:05:22 2008
@@ -49,6 +49,8 @@
     checkString("ab");
     checkString("dfkljdasklsdfklasdjfklajsdfkljasdklfjasdkljfaskldjf");
     checkString(Crypto.getRandomString(500));
+    checkString("foo bar baz");
+    checkString("foo\nbar\nbaz");
   }
 
   private void checkString(String string) throws Exception {