You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@shindig.apache.org by li...@apache.org on 2008/03/17 16:00:26 UTC

svn commit: r637925 - in /incubator/shindig/trunk/java/gadgets/src: main/java/org/apache/shindig/gadgets/http/ProxyHandler.java test/java/org/apache/shindig/gadgets/GadgetTestFixture.java test/java/org/apache/shindig/gadgets/http/ProxyHandlerTest.java

Author: lindner
Date: Mon Mar 17 08:00:22 2008
New Revision: 637925

URL: http://svn.apache.org/viewvc?rev=637925&view=rev
Log:
Apply Brian Eaton's test cases patch from SHINDIG-134

Added:
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/ProxyHandlerTest.java
Modified:
    incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyHandler.java
    incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetTestFixture.java

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=637925&r1=637924&r2=637925&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 Mon Mar 17 08:00:22 2008
@@ -52,7 +52,14 @@
 
 public class ProxyHandler {
   private static final String UNPARSEABLE_CRUFT = "throw 1; < don't be evil' >";
-
+  private static final String POST_DATA_PARAM = "postData";
+  private static final String METHOD_PARAM = "httpMethod";
+  private static final String SECURITY_TOKEN_PARAM = "st";
+  private static final String HEADERS_PARAM = "headers";
+  private static final String NOCACHE_PARAM = "nocache";
+  private static final String URL_PARAM = "url";
+  private static final String AUTHZ_PARAM = "authz";
+  
   private final RemoteContentFetcher fetcher;
 
   private final static Set<String> DISALLOWED_RESPONSE_HEADERS
@@ -80,7 +87,7 @@
       JSONObject resp = new JSONObject()
           .put("body", results.getResponseAsString())
           .put("rc", results.getHttpStatusCode());
-      String url = request.getParameter("url");
+      String url = request.getParameter(URL_PARAM);
       JSONObject json = new JSONObject().put(url, resp);
       output = UNPARSEABLE_CRUFT + json.toString();
     } catch (JSONException e) {
@@ -140,10 +147,10 @@
     }
 
     try {
-      URL originalUrl = validateUrl(request.getParameter("url"));
+      URL originalUrl = validateUrl(request.getParameter(URL_PARAM));
       GadgetSigner signer = state.getGadgetSigner();
       URL signedUrl;
-      if ("signed".equals(request.getParameter("authz"))) {
+      if ("signed".equals(request.getParameter(AUTHZ_PARAM))) {
         GadgetToken token = extractAndValidateToken(request, signer);
         if (token == null) {
           return new RemoteContent(HttpServletResponse.SC_UNAUTHORIZED,
@@ -158,11 +165,11 @@
       byte[] postBody = null;
 
       if ("POST".equals(method)) {
-        method = getParameter(request, "httpMethod", "GET");
+        method = getParameter(request, METHOD_PARAM, "GET");
         postBody = URLDecoder.decode(
-            getParameter(request, "postData", ""), encoding).getBytes();
+            getParameter(request, POST_DATA_PARAM, ""), encoding).getBytes();
 
-        String headerData = request.getParameter("headers");
+        String headerData = request.getParameter(HEADERS_PARAM);
         if (headerData == null || headerData.length() == 0) {
           headers = Collections.emptyMap();
         } else {
@@ -193,7 +200,7 @@
 
       RemoteContentRequest.Options options
           = new RemoteContentRequest.Options();
-      options.ignoreCache = "1".equals(request.getParameter("nocache"));
+      options.ignoreCache = "1".equals(request.getParameter(NOCACHE_PARAM));
       RemoteContentRequest req = new RemoteContentRequest(
           method, signedUrl.toURI(), headers, postBody, options);
       return fetcher.fetch(req);
@@ -268,7 +275,7 @@
     if (signer == null) {
       return null;
     }
-    String token = getParameter(request, "st", "");
+    String token = getParameter(request, SECURITY_TOKEN_PARAM, "");
     return signer.createToken(token);
   }
 
@@ -279,8 +286,8 @@
   @SuppressWarnings("unchecked")
   private URL signUrl(CrossServletState state, URL originalUrl, GadgetToken token,
       HttpServletRequest request) throws GadgetException {
-    String method = getParameter(request, "httpMethod", "GET");
-    String body = getParameter(request, "postData", null);
+    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/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=637925&r1=637924&r2=637925&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 Mon Mar 17 08:00:22 2008
@@ -21,8 +21,10 @@
 
 
 import org.apache.shindig.gadgets.http.CrossServletState;
+import org.apache.shindig.gadgets.http.ProxyHandler;
 import org.apache.shindig.gadgets.spec.GadgetSpec;
 import org.apache.shindig.gadgets.spec.MessageBundle;
+import org.apache.shindig.util.BlobCrypterException;
 
 import java.util.Set;
 import java.util.concurrent.Executors;
@@ -35,6 +37,7 @@
   public final HttpServletRequest request = mock(HttpServletRequest.class, true);
   public final HttpServletResponse response = mock(HttpServletResponse.class, true);
   public final GadgetServer gadgetServer;
+  public final ProxyHandler proxyHandler;
   public final RemoteContentFetcher fetcher = mock(RemoteContentFetcher.class, true);
   @SuppressWarnings(value="unchecked")
   public final DataFetcher<GadgetSpec> specFetcher = mock(DataFetcher.class, true);
@@ -51,7 +54,17 @@
 
     @Override
     public GadgetSigner getGadgetSigner() {
-      return null;
+      return new GadgetSigner() {
+        @Override
+        public GadgetToken createToken(String tokenString)
+            throws GadgetException {
+          try {
+            return new BasicGadgetToken("owner", "viewer", "app", "domain");
+          } catch (BlobCrypterException e) {
+            throw new GadgetException(GadgetException.Code.INVALID_GADGET_TOKEN, e);
+          }
+        }
+      };
     }
 
     @Override
@@ -86,7 +99,26 @@
 
     @Override
     public RequestSigner makeSignedFetchRequestSigner(GadgetToken token) {
-      return null;
+      // Real implementations should use their own key, probably pulled from
+      // disk rather than hardcoded in the source.
+      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==";
+      final String PRIVATE_KEY_NAME = "shindig-insecure-key";
+      return new SignedFetchRequestSigner(token, PRIVATE_KEY_NAME,
+          PRIVATE_KEY_TEXT);
     }
   };
 
@@ -107,5 +139,6 @@
     config.setFeatureRegistry(registry);
     config.setGadgetBlacklist(blacklist);
     gadgetServer = new GadgetServer(config);
+    proxyHandler = new ProxyHandler(fetcher);
   }
 }

Added: 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=637925&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/ProxyHandlerTest.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/ProxyHandlerTest.java Mon Mar 17 08:00:22 2008
@@ -0,0 +1,175 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.shindig.gadgets.http;
+
+import static org.easymock.EasyMock.expect;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintWriter;
+import java.net.URI;
+
+import org.apache.shindig.gadgets.GadgetTestFixture;
+import org.apache.shindig.gadgets.RemoteContent;
+import org.apache.shindig.gadgets.RemoteContentRequest;
+import org.easymock.EasyMock;
+import org.easymock.IArgumentMatcher;
+import org.json.JSONObject;
+
+public class ProxyHandlerTest extends GadgetTestFixture {
+
+  private final static String URL_ONE = "http://www.example.com/test.html";
+  private final static String DATA_ONE = "hello world";
+      
+  final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+  final PrintWriter writer = new PrintWriter(baos);
+  
+  private void expectGetAndReturnData(String url, byte[] data) throws Exception {
+    RemoteContentRequest req = new RemoteContentRequest(
+        "GET", new URI(url), null, null, new RemoteContentRequest.Options());
+    RemoteContent resp = new RemoteContent(200, data, null);
+    expect(fetcher.fetch(req)).andReturn(resp);
+  }
+  
+  private void expectPostAndReturnData(String url, byte[] body, byte[] data) throws Exception {
+    RemoteContentRequest req = new RemoteContentRequest(
+        "POST", new URI(url), null, body, new RemoteContentRequest.Options());
+    RemoteContent resp = new RemoteContent(200, data, null);
+    expect(fetcher.fetch(req)).andReturn(resp);
+  }
+  
+  private void setupPostRequestMock(String url, String body) throws Exception {
+    setupGenericRequestMock("POST", url);
+    expect(request.getParameter("postData")).andReturn(body).atLeastOnce();
+  }
+  
+  private void setupGetRequestMock(String url) throws Exception {
+    setupGenericRequestMock("GET", url);    
+  }
+  
+  private void setupGenericRequestMock(String method, String url) throws Exception {
+    expect(request.getMethod()).andReturn("POST").atLeastOnce();
+    expect(request.getParameter("httpMethod")).andReturn(method).atLeastOnce();
+    expect(request.getParameter("url")).andReturn(url).atLeastOnce();
+    expect(response.getWriter()).andReturn(writer).atLeastOnce(); 
+  }
+  
+  private JSONObject readJSONResponse(String body) throws Exception {
+    String json = body.substring("throw 1; < don't be evil' >".length(), body.length());  
+    return new JSONObject(json);
+  }
+  
+  public void testFetchJson() throws Exception {
+    setupGetRequestMock(URL_ONE);
+    expectGetAndReturnData(URL_ONE, DATA_ONE.getBytes());
+    replay();
+    proxyHandler.fetchJson(request, response, state);
+    verify();
+    writer.close();
+    JSONObject json = readJSONResponse(baos.toString());
+    JSONObject info = json.getJSONObject(URL_ONE);
+    assertEquals(200, info.getInt("rc"));
+    assertEquals(DATA_ONE, info.get("body"));
+  }
+  
+  public void testFetchDecodedUrl() throws Exception {
+    String origUrl = "http://www.example.com";
+    String cleanedUrl = "http://www.example.com/";
+    setupGetRequestMock(origUrl);
+    expectGetAndReturnData(cleanedUrl, DATA_ONE.getBytes());
+    replay();
+    proxyHandler.fetchJson(request, response, state);
+    verify();
+    writer.close();
+    JSONObject json = readJSONResponse(baos.toString());
+    JSONObject info = json.getJSONObject(origUrl);
+    assertEquals(200, info.getInt("rc"));
+    assertEquals(DATA_ONE, info.get("body"));
+  }
+  
+  public void testEmptyDocument() throws Exception {
+    setupGetRequestMock(URL_ONE);
+    expectGetAndReturnData(URL_ONE, "".getBytes());
+    replay();
+    proxyHandler.fetchJson(request, response, state);
+    verify();
+    writer.close();
+    JSONObject json = readJSONResponse(baos.toString());
+    JSONObject info = json.getJSONObject(URL_ONE);
+    assertEquals(200, info.getInt("rc"));
+    assertEquals("", info.get("body"));
+  }
+  
+  public void testPostRequest() throws Exception {
+    String body = "abc";
+    setupPostRequestMock(URL_ONE, body);
+    expectPostAndReturnData(URL_ONE, body.getBytes(), DATA_ONE.getBytes());
+    replay();
+    proxyHandler.fetchJson(request, response, state);
+    verify();
+    writer.close();
+    JSONObject json = readJSONResponse(baos.toString());
+    JSONObject info = json.getJSONObject(URL_ONE);
+    assertEquals(200, info.getInt("rc"));
+    assertEquals(DATA_ONE, info.get("body"));      
+  }
+  
+  public void testSignedGetRequest() throws Exception {
+    setupGetRequestMock(URL_ONE);
+    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))).andReturn(resp);
+    replay();
+    proxyHandler.fetchJson(request, response, state);
+    verify();
+    writer.close();
+  }
+  
+  private RemoteContentRequest looksLikeSignedFetch(String url) {
+    EasyMock.reportMatcher(new SignedFetchArgumentMatcher(url));
+    return null;
+  }
+
+  private class SignedFetchArgumentMatcher implements IArgumentMatcher {
+
+    private String expectedUrl;
+
+    public SignedFetchArgumentMatcher(String expectedUrl) {
+      this.expectedUrl = expectedUrl;
+    }
+    
+    @Override
+    public void appendTo(StringBuffer sb) {
+      sb.append("SignedFetchArgumentMatcher(");
+      sb.append(expectedUrl);
+      sb.append(")");
+    }
+
+    @Override
+    public boolean matches(Object arg0) {
+      RemoteContentRequest request = (RemoteContentRequest)arg0;
+      String url = request.getUri().toASCIIString();
+      return (url.startsWith(expectedUrl) &&
+          url.contains("opensocial_ownerid") && url.contains("opensocial_viewerid") &&
+          url.contains("opensocial_appid") && url.contains("opensocial_appid"));
+    }
+    
+  }
+}