Author: lryan
Date: Fri Feb  1 13:39:37 2008
New Revision: 617660

URL: http://svn.apache.org/viewvc?rev=617660&view=rev
Log:
Initial support for request signing including
 - GadgetTokens used to sign requests
 - POST request fetching
 - Setting security token (st) and authorization (authz) params
 - encoding form post into postData param
 - JsFeature loader supports '//' path prefixes to mean host relative URLs

Modified:
    incubator/shindig/trunk/features/core/io.js
    
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetToken.java
    
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/GadgetToken.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/RemoteContentFetcher.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/gadgets/http/ProxyServlet.java

Modified: incubator/shindig/trunk/features/core/io.js
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/features/core/io.js?rev=617660&r1=617659&r2=617660&view=diff
==============================================================================
--- incubator/shindig/trunk/features/core/io.js (original)
+++ incubator/shindig/trunk/features/core/io.js Fri Feb  1 13:39:37 2008
@@ -126,12 +126,25 @@
       var params = opt_params || {};
       var newUrl = config.jsonProxyUrl.replace("%url%",
           encodeURIComponent(url));
+
+      // Check if authorization is requested
+      if (opt_params.AUTHORIZATION &&
+          gadgets.io.AuthorizationType[opt_params.AUTHORIZATION.toUpperCase()]
+              != gadgets.io.AuthorizationType.NONE) {
+        newUrl += "&authz=" + opt_params.AUTHORIZATION.toLowerCase();
+        // Add the security-token if available
+        if (gadgets.util.getUrlParameters()["st"]) {
+          newUrl += "&st=" + gadgets.util.getUrlParameters()["st"];
+        }
+      }
+      // TODO: Fetcher cannot distinguish between GET & POST yet.
       xhr.open(params.METHOD || "GET", newUrl, true);
       if (callback) {
         xhr.onreadystatechange = gadgets.util.makeClosure(null,
             processResponse, url, callback, params, xhr);
       }
-      xhr.send(params.postData);
+      xhr.setRequestHeader('Content-Type', 
'application/x-www-form-urlencoded');
+      xhr.send("postData=" + encodeURIComponent(params.postData));
     },
 
     /**

Modified: 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetToken.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetToken.java?rev=617660&r1=617659&r2=617660&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetToken.java
 (original)
+++ 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/BasicGadgetToken.java
 Fri Feb  1 13:39:37 2008
@@ -18,6 +18,9 @@
  */
 package org.apache.shindig.gadgets;
 
+import java.net.URL;
+import java.util.Map;
+
 /**
  * Primitive token implementation that uses stings as tokens.
  */
@@ -31,11 +34,21 @@
     return token;
   }
 
+
   /**
    * Generates a token from an input string
-   * @param token
+   * @param token String form of token
    */
   public BasicGadgetToken(String token) {
     this.token = token;
+  }
+
+  /**
+   * [EMAIL PROTECTED]
+   * Signer that does not sign.
+   */
+  public URL signUrl(URL uri, String httpMethod, Map parameters)
+      throws GadgetException {
+    return uri;
   }
 }

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=617660&r1=617659&r2=617660&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 Feb  1 13:39:37 2008
@@ -13,9 +13,6 @@
  */
 package org.apache.shindig.gadgets;
 
-import org.apache.shindig.gadgets.RemoteContentFetcher;
-import org.apache.shindig.gadgets.RemoteContent;
-
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -54,6 +51,41 @@
       fetcher = (HttpURLConnection) url.openConnection();
       fetcher.setInstanceFollowRedirects(true);
       fetcher.setConnectTimeout(CONNECT_TIMEOUT_MS);
+
+      responseCode = fetcher.getResponseCode();
+      headers = fetcher.getHeaderFields();
+
+      byte chunk[] = new byte[8192];
+      int chunkSize;
+      InputStream in = fetcher.getInputStream();
+      while (out.size() < maxObjSize && (chunkSize = in.read(chunk)) != -1) {
+        out.write(chunk, 0, chunkSize);
+      }
+    } catch (IOException e) {
+      responseCode = 500;
+    }
+
+    return new RemoteContent(responseCode, out.toByteArray(), headers);
+  }
+
+  public RemoteContent fetchByPost(URL url, byte[] postData,
+      ProcessingOptions options) {
+    ByteArrayOutputStream out = new ByteArrayOutputStream();
+    
+    int responseCode;
+    HttpURLConnection fetcher;
+    Map<String, List<String>> headers = null;
+
+    try {
+      fetcher = (HttpURLConnection) url.openConnection();
+      fetcher.setRequestMethod("POST");
+      fetcher.setInstanceFollowRedirects(true);
+      fetcher.setConnectTimeout(CONNECT_TIMEOUT_MS);
+      fetcher.setRequestProperty("Content-Length", "" + postData.length);
+      fetcher.setUseCaches(false);
+      fetcher.setDoInput(true);
+      fetcher.setDoOutput(true);
+      fetcher.getOutputStream().write(postData);
 
       responseCode = fetcher.getResponseCode();
       headers = fetcher.getHeaderFields();

Modified: 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetToken.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetToken.java?rev=617660&r1=617659&r2=617660&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetToken.java
 (original)
+++ 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/GadgetToken.java
 Fri Feb  1 13:39:37 2008
@@ -18,6 +18,9 @@
  */
 package org.apache.shindig.gadgets;
 
+import java.net.URL;
+import java.util.Map;
+
 /**
  * An abstract representation of a signing token.
  * Use in conjuction with @code GadgetSigner.
@@ -32,4 +35,16 @@
    * @return A string representation of the token.
    */
   public String toSerialForm();
+
+
+  /**
+   * Sign a URL using this token
+   * @param uri The URL to sign
+   * @param httpMethod The HTTP method used
+   * @param parameters associated with the signing request
+   * @return The signed URL
+   * @throws GadgetException
+   */
+  public URL signUrl(URL uri, String httpMethod, Map parameters)
+      throws GadgetException;
 }

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=617660&r1=617659&r2=617660&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 Feb  1 13:39:37 2008
@@ -367,6 +367,9 @@
           content = srcNode.getTextContent();
           if (content.startsWith("http://";)) {
             type = JsLibrary.Type.URL;
+          } else if (content.startsWith("//")) {
+            type = JsLibrary.Type.URL;
+            content = content.substring(1);
           } else if (content.startsWith("res://")) {
             content = content.substring(6);
             type = JsLibrary.Type.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=617660&r1=617659&r2=617660&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 Feb  1 13:39:37 2008
@@ -16,5 +16,22 @@
 import java.net.URL;
 
 public interface RemoteContentFetcher {
+
+  /**
+   * Fetch content using the HTTP GET method
+   * @param url Location of content to fetch
+   * @param options Additioanl options
+   * @return RemoteContent
+   */
   public RemoteContent fetch(URL url, ProcessingOptions options);
+
+  /**
+   * Fetch content using the HTTP POST method
+   * @param url Location of content to fetch
+   * @param postData The data to post
+   * @param options Additioanl options
+   * @return RemoteContent
+   */
+  public RemoteContent fetchByPost(URL url, byte[] postData,
+      ProcessingOptions options);
 }

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=617660&r1=617659&r2=617660&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 Feb  1 13:39:37 2008
@@ -24,13 +24,16 @@
 import org.apache.shindig.gadgets.GadgetToken;
 import org.apache.shindig.gadgets.ProcessingOptions;
 import org.apache.shindig.gadgets.RemoteContent;
+import org.apache.shindig.gadgets.RemoteContentFetcher;
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.net.URLDecoder;
 import java.util.List;
 import java.util.Map;
 
@@ -43,27 +46,34 @@
   private static final int TWO_HOURS_IN_MS = 7200000;
   private static final int ONE_HOUR_IN_SECS = 3600;
   private static final int MAX_PROXY_SIZE = 1024 * 1024;
-  private static final BasicRemoteContentFetcher fetcher =
-      new BasicRemoteContentFetcher(MAX_PROXY_SIZE);
+  
+  private final RemoteContentFetcher fetcher;
+
+  public ProxyHandler() {
+    this(new BasicRemoteContentFetcher(MAX_PROXY_SIZE));
+  }
+  
+  public ProxyHandler(RemoteContentFetcher fetcher) {
+    this.fetcher = fetcher;
+  }
 
   public void fetchJson(HttpServletRequest request,
                         HttpServletResponse response,
                         GadgetSigner signer)
       throws ServletException, IOException {
 
-    if (signer != null) {
-      // We're just going to toss away the token, but it should exist.
-      extractAndValidateToken(request, signer);
-    }
-
-    // Validate url= parameter
-    URL origin = extractAndValidateUrl(request);
+    GadgetToken token = extractAndValidateToken(request, signer);
+    URL originalUrl = extractAndValidateUrl(request);
+    URL signedUrl = signUrl(originalUrl, token, request);
 
     // Fetch the content and convert it into JSON.
-    RemoteContent results = fetcher.fetch(origin, new ProcessingOptions());
+    // TODO: Fetcher needs to handle variety of HTTP methods.
+    RemoteContent results = fetchContent(signedUrl, request,
+        new ProcessingOptions());
+
     String output;
     try {
-      String json = new JSONObject().put(origin.toString(), new JSONObject()
+      String json = new JSONObject().put(originalUrl.toString(), new 
JSONObject()
           .put("body", new String(results.getByteArray()))
           .put("rc", results.getHttpStatusCode())
           ).toString();
@@ -84,14 +94,14 @@
                     GadgetSigner signer)
       throws ServletException, IOException {
 
-    if (signer != null) {
-      // We're just going to toss away the token, but it should exist.
-      extractAndValidateToken(request, signer);
-    }
+    GadgetToken token = extractAndValidateToken(request, signer);
+    URL originalUrl = extractAndValidateUrl(request);
+    URL signedUrl = signUrl(originalUrl, token, request);
+
+    // TODO: Fetcher needs to handle variety of HTTP methods.
+    RemoteContent results = fetchContent(signedUrl, request,
+        new ProcessingOptions());
 
-    // Validate url= parameter
-    URL origin = extractAndValidateUrl(request);
-    RemoteContent results = fetcher.fetch(origin, new ProcessingOptions());
     int status = results.getHttpStatusCode();
     response.setStatus(status);
     if (status == HttpServletResponse.SC_OK) {
@@ -116,6 +126,25 @@
   }
 
   /**
+   * Fetch the content for a request
+   */
+  private RemoteContent fetchContent(URL signedUrl, HttpServletRequest request,
+      ProcessingOptions procOptions) throws ServletException {
+    try {
+      if (request.getMethod().equals("POST")) {
+        String data = request.getParameter("postData");
+        return fetcher.fetchByPost(signedUrl,
+            URLDecoder.decode(data, request.getCharacterEncoding()).getBytes(),
+            procOptions);
+      } else {
+        return fetcher.fetch(signedUrl, new ProcessingOptions());
+      }
+    } catch (UnsupportedEncodingException uee) {
+      throw new ServletException(uee);
+    }
+  }
+
+  /**
    * Gets the url= parameter from the request and applies some basic sanity
    * checking.
    *
@@ -147,17 +176,19 @@
 
   /**
    * @return A valid token for the given input.
+   * @throws ServletException
    */
   private GadgetToken extractAndValidateToken(HttpServletRequest request,
       GadgetSigner signer) throws ServletException {
-    String token = request.getParameter("t");
-    if (token == null) {
-      token = "";
-    }
     try {
+      if (signer == null) return null;
+      String token = request.getParameter("st");
+      if (token == null) {
+        token = "";
+      }
       return signer.createToken(token);
-    } catch (GadgetException e) {
-      throw new ServletException(e);
+    } catch (GadgetException ge) {
+      throw new ServletException(ge);
     }
   }
 
@@ -173,4 +204,23 @@
     response.setDateHeader("Expires", System.currentTimeMillis()
                                      + TWO_HOURS_IN_MS);
   }
+
+  /**
+   * Sign a URL with a GadgetToken if needed
+   * @return 
+   */
+  private URL signUrl(URL originalUrl, GadgetToken token,
+      HttpServletRequest request) throws ServletException {
+    try {
+      if (token == null ||
+          !"signed".equals(request.getParameter("authz"))) {
+        return originalUrl;
+      }
+      return token.signUrl(originalUrl, "GET", // TODO: request.getMethod() 
+          request.getParameterMap());
+    } catch (GadgetException ge) {
+      throw new ServletException(ge);
+    }
+  }
+
 }

Modified: 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyServlet.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyServlet.java?rev=617660&r1=617659&r2=617660&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyServlet.java
 (original)
+++ 
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ProxyServlet.java
 Fri Feb  1 13:39:37 2008
@@ -29,8 +29,8 @@
 import javax.servlet.http.HttpServletResponse;
 
 public class ProxyServlet extends HttpServlet {
-  private final static ProxyHandler handler = new ProxyHandler();
   private final GadgetSigner signer;
+  private final ProxyHandler handler;
 
   @Override
   protected void doGet(HttpServletRequest request, HttpServletResponse 
response)
@@ -43,19 +43,27 @@
     }
   }
 
+  @Override
+  protected void doPost(HttpServletRequest request, HttpServletResponse 
response)
+      throws ServletException, IOException {
+    // Currently they are identical
+    doGet(request, response);
+  }
+
   /**
    * Constructs a ProxyServlet with the default (non-secure) GadgetSigner.
    */
   public ProxyServlet() {
-    this(new BasicGadgetSigner());
+    this(new BasicGadgetSigner(), new ProxyHandler());
   }
 
   /**
    * Creates a ProxyServlet using the specified GadgetSigner.
-   *
-   * @param signer
+   * @param signer Used to sign and verify requests
+   * @param handler Used to fetch proxied content
    */
-  public ProxyServlet(GadgetSigner signer) {
+  public ProxyServlet(GadgetSigner signer, ProxyHandler handler) {
     this.signer = signer;
+    this.handler = handler;
   }
 }


Reply via email to