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;
}
}