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/29 01:43:13 UTC

svn commit: r642460 - 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 17:43:10 2008
New Revision: 642460

URL: http://svn.apache.org/viewvc?rev=642460&view=rev
Log:
Reverting SHINDIG-157.


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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -30,7 +30,7 @@
  * Implementation of a {@code RemoteObjectFetcher} using standard java.net
  * classes.
  */
-public class BasicRemoteContentFetcher extends RemoteContentFetcher {
+public class BasicRemoteContentFetcher implements RemoteContentFetcher {
   private static final int CONNECT_TIMEOUT_MS = 5000;
 
   private final int maxObjSize;
@@ -41,7 +41,6 @@
    * @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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -238,8 +238,7 @@
    * @param renderingContext
    */
   private void processContext(ParsedFeature feature, Element context,
-                              RenderingContext renderingContext) 
-  throws GadgetException {
+                              RenderingContext renderingContext) {
     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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -113,10 +113,9 @@
    *     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) throws GadgetException {
+      RemoteContentFetcher fetcher) {
     String optimizedContent = null;
     String debugContent;
     switch (type) {
@@ -169,10 +168,9 @@
    * @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) throws GadgetException {
+      RemoteContentFetcher fetcher) {
     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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -0,0 +1,38 @@
+/*
+ * 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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -18,29 +18,11 @@
 package org.apache.shindig.gadgets;
 
 
-/**
- * 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;
-  }
-  
+public interface RemoteContentFetcher {
   /**
-   * Fetch HTTP content.
-   *
+   * Fetch content using the HTTP GET method
    * @param request The request to fetch.
    * @return RemoteContent
-   * @throws GadgetException 
    */
-  public abstract RemoteContent fetch(RemoteContentRequest request) throws GadgetException;
+  public RemoteContent fetch(RemoteContentRequest request);
 }

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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -33,6 +33,9 @@
  * 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?
  */
@@ -44,13 +47,6 @@
    */
   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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -0,0 +1,60 @@
+/*
+ * 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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -0,0 +1,277 @@
+/*
+ * 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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -21,12 +21,10 @@
 
 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.RemoteContentFetcher;
-import org.apache.shindig.util.BlobCrypter;
+import org.apache.shindig.gadgets.RequestSigner;
 
 import java.util.Set;
 import java.util.logging.Logger;
@@ -107,16 +105,24 @@
   public abstract String getIframeUrl(Gadget gadget);
 
   /**
-   * Constructs a RemoteFetcher object that signs requests and then forwards
-   * them to the next content fetcher in the chain.
-   *
-   * @param remoteFetcher 
+   * Constructs a RequestSigner object that can be used to sign requests from
+   * the given gadget token to implement signed fetch.
+   * 
    * @param token the decrypted, verified security token
    * @return a request signer implementing signed fetch.
    * 
-   * @see org.apache.shindig.gadgets.SigningFetcher
+   * @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.
    */
-  public abstract RemoteContentFetcher makeSigningFetcher(RemoteContentFetcher remoteFetcher, GadgetToken token);
+  public abstract RequestSigner makeOAuthRequestSigner(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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -22,7 +22,6 @@
 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;
@@ -37,7 +36,8 @@
 import org.apache.shindig.gadgets.JsLibrary;
 import org.apache.shindig.gadgets.MessageBundleFetcher;
 import org.apache.shindig.gadgets.RemoteContentFetcher;
-import org.apache.shindig.gadgets.SigningFetcher;
+import org.apache.shindig.gadgets.RequestSigner;
+import org.apache.shindig.gadgets.SignedFetchRequestSigner;
 import org.apache.shindig.gadgets.SyndicatorConfig;
 import org.apache.shindig.gadgets.UserPrefs;
 import org.apache.shindig.gadgets.spec.GadgetSpec;
@@ -47,8 +47,6 @@
 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;
@@ -229,8 +227,12 @@
   }
 
   @Override
-  public RemoteContentFetcher makeSigningFetcher(
-      RemoteContentFetcher fetcher, GadgetToken token) {
+  public RequestSigner makeOAuthRequestSigner(GadgetToken token) {
+    return null;
+  }
+
+  @Override
+  public RequestSigner makeSignedFetchRequestSigner(GadgetToken token) {
     // Real implementations should use their own key, probably pulled from
     // disk rather than hardcoded in the source.
     final String PRIVATE_KEY_TEXT =
@@ -249,7 +251,7 @@
       "AO/0isr/3aa6O6NLQxISLKcPDk2NOccAfS/xOtfOz4sJYM3+Bs4Io9+dZGSDCA54" +
       "Lw03eHTNQghS0A==";
     final String PRIVATE_KEY_NAME = "shindig-insecure-key";
-    return SigningFetcher.makeFromB64PrivateKey(
-        fetcher, token, PRIVATE_KEY_NAME, PRIVATE_KEY_TEXT);
+    return new SignedFetchRequestSigner(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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -24,6 +24,7 @@
 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;
@@ -31,12 +32,15 @@
 
 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;
@@ -56,10 +60,8 @@
   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 remoteFetcher;
+  private final RemoteContentFetcher fetcher;
 
   private final static Set<String> DISALLOWED_RESPONSE_HEADERS
     = new HashSet<String>();
@@ -69,49 +71,25 @@
   }
 
   public ProxyHandler(RemoteContentFetcher fetcher) {
-    this.remoteFetcher = fetcher;
+    this.fetcher = 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
-      String originalUrl = request.getParameter(URL_PARAM);
-      JSONObject json = new JSONObject().put(originalUrl, resp);
+      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);
       output = UNPARSEABLE_CRUFT + json.toString();
     } catch (JSONException e) {
       output = "";
@@ -122,16 +100,67 @@
     response.getWriter().write(output);
   }
 
-  @SuppressWarnings("unchecked")
-  private RemoteContentRequest buildRemoteContentRequest(HttpServletRequest request)
-  throws ServletException {
-    try {
+  public void fetch(HttpServletRequest request,
+                    HttpServletResponse response,
+                    CrossServletState state)
+      throws ServletException, IOException, GadgetException {
+    RemoteContent results = fetchContent(request, state);
 
-      String encoding = request.getCharacterEncoding();
-      if (encoding == null) {
-        encoding = "UTF-8";
+    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";
+    }
+
+    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 method = request.getMethod();
       Map<String, List<String>> headers = null;
       byte[] postBody = null;
@@ -151,8 +180,7 @@
             String[] parts = header.split("=");
             if (parts.length != 2) {
               // Malformed headers
-              throw new GadgetException(GadgetException.Code.INTERNAL_SERVER_ERROR,
-              "malformed header specified");
+              return RemoteContent.ERROR;
             }
             headers.put(URLDecoder.decode(parts[0], encoding),
                 Arrays.asList(URLDecoder.decode(parts[1], encoding)));
@@ -171,93 +199,19 @@
       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, target, headers, postBody, options);
-
-      return req;
+          method, signedUrl.toURI(), headers, postBody, options);
+      return fetcher.fetch(req);
     } catch (UnsupportedEncodingException e) {
       throw new ServletException(e);
-    } catch (GadgetException e) {
+    } catch (URISyntaxException 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
    */
@@ -275,14 +229,12 @@
 
   /**
    * 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.
    */
-   URI validateUrl(String urlToValidate) throws ServletException {
+  private URL validateUrl(String urlToValidate) throws ServletException {
     if (urlToValidate == null) {
       throw new ServletException("url parameter is missing.");
     }
@@ -305,10 +257,39 @@
                       "/", url.getQuery(),
                       url.getFragment());
       }
-      return url;
+      return url.toURL();
     } 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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -17,8 +17,6 @@
  */
 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
@@ -34,7 +32,6 @@
    *
    * @param request The request from the json
    * @return The corresponding response item
-   * @throws GadgetException 
    */
-  ResponseItem handleRequest(RequestItem request) throws GadgetException;
+  ResponseItem handleRequest(RequestItem request);
 }

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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -17,7 +17,6 @@
  */
 package org.apache.shindig.social.opensocial;
 
-import org.apache.shindig.gadgets.GadgetException;
 import org.apache.shindig.gadgets.GadgetToken;
 
 import org.apache.shindig.social.ResponseItem;
@@ -31,10 +30,9 @@
    * @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) throws GadgetException;
+      GadgetToken token);
 
   /**
    * Creates the passed in activity for the given user. Once createActivity is
@@ -43,8 +41,7 @@
    * @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) throws GadgetException;
+      GadgetToken token);
 }

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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -18,7 +18,6 @@
 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;
@@ -33,10 +32,9 @@
    * @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) throws GadgetException;
+      List<String> ids, List<String> keys, GadgetToken token);
 
   /**
    * Updates the data key for the given person with the new value.
@@ -47,8 +45,7 @@
    * @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) throws GadgetException;
+      String value, GadgetToken token);
 }

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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -21,7 +21,6 @@
 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;
@@ -77,7 +76,7 @@
     }
   }
 
-  public ResponseItem handleRequest(RequestItem request) throws GadgetException {
+  public ResponseItem handleRequest(RequestItem request) {
     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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -22,7 +22,6 @@
 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;
@@ -36,10 +35,9 @@
    * @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, GadgetException;
+      throws JSONException;
 
   public enum SortOrder {
     topFriends, name
@@ -57,9 +55,8 @@
    * @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) throws GadgetException;
+      Set<String> profileDetails, GadgetToken token);
 }

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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -17,7 +17,6 @@
  */
 package org.apache.shindig.social.samplecontainer;
 
-import org.apache.shindig.gadgets.GadgetException;
 import org.apache.shindig.gadgets.GadgetToken;
 
 import org.apache.shindig.social.ResponseItem;
@@ -35,7 +34,7 @@
  */
 public class BasicActivitiesService implements ActivitiesService {
   public ResponseItem<List<Activity>> getActivities(List<String> ids, 
-      GadgetToken token) throws GadgetException {
+      GadgetToken token) {
     Map<String, List<Activity>> allActivities =
         XmlStateFileFetcher.get().getActivities();
 
@@ -53,7 +52,7 @@
   }
 
   public ResponseItem createActivity(String personId, Activity activity, 
-        GadgetToken token) throws GadgetException {
+        GadgetToken token) {
     // 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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -17,7 +17,6 @@
  */
 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;
@@ -31,7 +30,7 @@
 public class BasicDataService implements DataService {
 
   public ResponseItem<Map<String, Map<String, String>>> getPersonData(
-        List<String> ids, List<String> keys, GadgetToken token) throws GadgetException {
+        List<String> ids, List<String> keys, GadgetToken token) {
 
     Map<String, Map<String, String>> allData
         = XmlStateFileFetcher.get().getAppData();
@@ -58,7 +57,7 @@
   }
 
   public ResponseItem updatePersonData(String id, String key, String value,
-      GadgetToken token) throws GadgetException {
+      GadgetToken token) {
     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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -22,7 +22,6 @@
 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;
 
@@ -45,7 +44,7 @@
 
   public ResponseItem<ApiCollection<Person>> getPeople(List<String> ids,
       SortOrder sortOrder, FilterType filter, int first, int max, 
-      Set<String> profileDetails, GadgetToken token) throws GadgetException {
+      Set<String> profileDetails, GadgetToken token) {
     Map<String, Person> allPeople = XmlStateFileFetcher.get().getAllPeople();
 
     List<Person> people = new ArrayList<Person>();
@@ -80,7 +79,7 @@
   }
 
   public List<String> getIds(IdSpec idSpec, GadgetToken token)
-      throws JSONException, GadgetException {
+      throws JSONException {
     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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -19,7 +19,6 @@
 
 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;
@@ -50,7 +49,7 @@
     }
   }
 
-  public ResponseItem handleRequest(RequestItem request) throws GadgetException {
+  public ResponseItem handleRequest(RequestItem request) {
     RequestType type = RequestType.valueOf(request.getType());
     ResponseItem response = null;
 
@@ -94,4 +93,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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -1,7 +1,6 @@
 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;
@@ -95,7 +94,7 @@
     this.doEvil = doEvil;
   }
 
-  private Document fetchStateDocument() throws GadgetException {
+  private Document fetchStateDocument() {
     if (document != null) {
       return document;
     }
@@ -131,14 +130,14 @@
     }
   }
 
-  public Map<String, Map<String, String>> getAppData() throws GadgetException {
+  public Map<String, Map<String, String>> getAppData() {
     if (allData == null) {
       setupAppData();
     }
     return allData;
   }
 
-  private void setupAppData() throws GadgetException {
+  private void setupAppData() {
     allData = new HashMap<String, Map<String, String>>();
 
     Element root = fetchStateDocument().getDocumentElement();
@@ -166,7 +165,7 @@
     }
   }
 
-  public void setAppData(String id, String key, String value) throws GadgetException {
+  public void setAppData(String id, String key, String value) {
     if (allData == null) {
       setupAppData();
     }
@@ -180,21 +179,21 @@
     personData.put(key, value);
   }
 
-  public Map<String, List<String>> getFriendIds() throws GadgetException {
+  public Map<String, List<String>> getFriendIds() {
     if (friendIdMap == null) {
       setupPeopleData();
     }
     return friendIdMap;
   }
 
-  public Map<String, Person> getAllPeople() throws GadgetException {
+  public Map<String, Person> getAllPeople() {
     if (allPeople == null) {
       setupPeopleData();
     }
     return allPeople;
   }
 
-  private void setupPeopleData() throws GadgetException {
+  private void setupPeopleData() {
     Element root = fetchStateDocument().getDocumentElement();
 
     allPeople = new HashMap<String, Person>();
@@ -259,7 +258,7 @@
     return friends;
   }
 
-  public Map<String, List<Activity>> getActivities() throws GadgetException {
+  public Map<String, List<Activity>> getActivities() {
     if (allActivities == null) {
       setupActivities();
     }
@@ -267,7 +266,7 @@
     return allActivities;
   }
 
-  private void setupActivities() throws GadgetException {
+  private void setupActivities() {
     allActivities = new HashMap<String, List<Activity>>();
 
     Element root = fetchStateDocument().getDocumentElement();
@@ -291,7 +290,7 @@
   }
 
   private void createActivities(Node streamItem, String userId,
-      String streamTitle) throws GadgetException {
+      String streamTitle) {
     NodeList activityItems = streamItem.getChildNodes();
     if (activityItems != null) {
       for (int i = 0; i < activityItems.getLength(); i++) {
@@ -337,7 +336,7 @@
     return media;
   }
 
-  public void createActivity(String userId, Activity activity) throws GadgetException {
+  public void createActivity(String userId, Activity activity) {
     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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -22,18 +22,16 @@
 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 {
 
@@ -176,8 +174,8 @@
     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);
+      String key = items[i++];
+      String val = items[i++];
       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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -17,7 +17,7 @@
  */
 package org.apache.shindig.gadgets;
 
-import org.easymock.classextension.EasyMock;
+import org.easymock.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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -93,7 +93,12 @@
     }
 
     @Override
-    public RemoteContentFetcher makeSigningFetcher(RemoteContentFetcher fetcher, GadgetToken token) {
+    public RequestSigner makeOAuthRequestSigner(GadgetToken token) {
+      return null;
+    }
+
+    @Override
+    public RequestSigner makeSignedFetchRequestSigner(GadgetToken token) {
       // Real implementations should use their own key, probably pulled from
       // disk rather than hardcoded in the source.
       final String PRIVATE_KEY_TEXT =
@@ -112,8 +117,8 @@
         "AO/0isr/3aa6O6NLQxISLKcPDk2NOccAfS/xOtfOz4sJYM3+Bs4Io9+dZGSDCA54" +
         "Lw03eHTNQghS0A==";
       final String PRIVATE_KEY_NAME = "shindig-insecure-key";
-      return SigningFetcher.makeFromB64PrivateKey(
-          fetcher, token, PRIVATE_KEY_NAME, PRIVATE_KEY_TEXT);
+      return new SignedFetchRequestSigner(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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -34,7 +34,7 @@
         "};";
   private final static String URL_JS = "while(true){alert('hello');}";
 
-  public void testInline() throws GadgetException {
+  public void testInline() {
     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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -0,0 +1,225 @@
+/*
+ * 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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -25,7 +25,6 @@
 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;
@@ -143,54 +142,17 @@
     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) {
-    return looksLikeSignedFetch(url, null);
-  }
-  
-  private RemoteContentRequest looksLikeSignedFetch(String url, byte[] postBody) {
-    EasyMock.reportMatcher(new SignedFetchArgumentMatcher(url, postBody));
+    EasyMock.reportMatcher(new SignedFetchArgumentMatcher(url));
     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) {
@@ -202,95 +164,11 @@
     public boolean matches(Object arg0) {
       RemoteContentRequest request = (RemoteContentRequest)arg0;
       String url = request.getUri().toASCIIString();
-      if (url.startsWith(expectedUrl) &&
-          url.contains("opensocial_owner_id") && 
+      return (url.startsWith(expectedUrl) &&
+          url.contains("opensocial_owner_id") &&
           url.contains("opensocial_viewer_id") &&
-          url.contains("opensocial_app_id") &&
-          byteArrayEquals(postBody, request.getPostBodyBytes())) {
-        return true;
-      }
-      return false;
+          url.contains("opensocial_app_id"));
     }
 
-    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=642460&r1=642459&r2=642460&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 17:43:10 2008
@@ -49,8 +49,6 @@
     checkString("ab");
     checkString("dfkljdasklsdfklasdjfklajsdfkljasdklfjasdkljfaskldjf");
     checkString(Crypto.getRandomString(500));
-    checkString("foo bar baz");
-    checkString("foo\nbar\nbaz");
   }
 
   private void checkString(String string) throws Exception {