You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by li...@apache.org on 2010/12/02 03:28:17 UTC
svn commit: r1041256 - in /shindig/trunk:
features/src/main/javascript/features/core.io/
features/src/main/javascript/features/opensocial-jsonrpc/
features/src/main/javascript/features/osapi/
features/src/main/javascript/features/rpc/ features/src/main...
Author: lindner
Date: Thu Dec 2 02:28:16 2010
New Revision: 1041256
URL: http://svn.apache.org/viewvc?rev=1041256&view=rev
Log:
SHINDIG-606 | add OAuth 2 Draft 10 support, use it for rpc calls
Added:
shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/UrlParameterAuthenticationHandlerTest.java
Modified:
shindig/trunk/features/src/main/javascript/features/core.io/io.js
shindig/trunk/features/src/main/javascript/features/opensocial-jsonrpc/jsonrpccontainer.js
shindig/trunk/features/src/main/javascript/features/osapi/jsonrpctransport.js
shindig/trunk/features/src/main/javascript/features/rpc/rpc.js
shindig/trunk/features/src/main/javascript/features/shindig.container/shindig-container.js
shindig/trunk/features/src/test/javascript/features/osapi/batchtest.js
shindig/trunk/features/src/test/javascript/features/osapi/jsonrpctransporttest.js
shindig/trunk/features/src/test/javascript/lib/testutils.js
shindig/trunk/java/common/conf/shindig.properties
shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/UrlParameterAuthenticationHandler.java
shindig/trunk/php/src/gadgets/GadgetContext.php
Modified: shindig/trunk/features/src/main/javascript/features/core.io/io.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/core.io/io.js?rev=1041256&r1=1041255&r2=1041256&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/core.io/io.js (original)
+++ shindig/trunk/features/src/main/javascript/features/core.io/io.js Thu Dec 2 02:28:16 2010
@@ -243,7 +243,7 @@ gadgets.io = function() {
* 'application/x-www-form-urlencoded'.
*/
function makeXhrRequest(realUrl, proxyUrl, callback, paramData, method,
- params, processResponseFunction, opt_contentType) {
+ params, processResponseFunction, opt_headers) {
var xhr = makeXhr();
if (proxyUrl.indexOf('//') == 0) {
@@ -256,11 +256,15 @@ gadgets.io = function() {
null, processResponseFunction, realUrl, callback, params, xhr);
}
if (paramData !== null) {
- xhr.setRequestHeader('Content-Type', opt_contentType || 'application/x-www-form-urlencoded');
- xhr.send(paramData);
- } else {
- xhr.send(null);
+ var contentTypeHeader = 'Content-Type';
+ var headers = opt_headers || {};
+ if (!headers[contentTypeHeader]) headers[contentTypeHeader] = 'application/x-www-form-urlencoded';
+
+ for (var headerName in headers) {
+ xhr.setRequestHeader(headerName, headers[headerName]);
+ }
}
+ xhr.send(paramData);
}
@@ -441,12 +445,16 @@ gadgets.io = function() {
},
/**
- * @private
+ * @param {string} relativeUrl url to fetch via xhr
+ * @param callback callback to call when response is received or for error
+ * @param {Object=} opt_params
+ * @param {Object=} opt_headers
+ *
*/
- makeNonProxiedRequest: function(relativeUrl, callback, opt_params, opt_contentType) {
+ makeNonProxiedRequest: function(relativeUrl, callback, opt_params, opt_headers) {
var params = opt_params || {};
makeXhrRequest(relativeUrl, relativeUrl, callback, params.POST_DATA,
- params.METHOD, params, processNonProxiedResponse, opt_contentType);
+ params.METHOD, params, processNonProxiedResponse, opt_headers);
},
/**
Modified: shindig/trunk/features/src/main/javascript/features/opensocial-jsonrpc/jsonrpccontainer.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/opensocial-jsonrpc/jsonrpccontainer.js?rev=1041256&r1=1041255&r2=1041256&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/opensocial-jsonrpc/jsonrpccontainer.js (original)
+++ shindig/trunk/features/src/main/javascript/features/opensocial-jsonrpc/jsonrpccontainer.js Thu Dec 2 02:28:16 2010
@@ -217,18 +217,18 @@ var JsonRpcRequestItem = function(rpc, o
'POST_DATA' : gadgets.json.stringify(jsonBatchData)
};
- var url = [this.path_];
+ var headers = {'Content-Type':'application/json'};
+
var token = shindig.auth.getSecurityToken();
if (token) {
- url.push('?st=', encodeURIComponent(token));
+ headers['Authorization'] = 'OAuth ' + token;
}
- this.sendRequest(url.join(''), sendResponse, makeRequestParams,
- 'application/json');
+ this.sendRequest(this.path_, sendResponse, makeRequestParams, headers);
};
- JsonRpcContainer.prototype.sendRequest = function(relativeUrl, callback, params, contentType) {
- gadgets.io.makeNonProxiedRequest(relativeUrl, callback, params, contentType);
+ JsonRpcContainer.prototype.sendRequest = function(relativeUrl, callback, params, headers) {
+ gadgets.io.makeNonProxiedRequest(relativeUrl, callback, params, headers);
};
JsonRpcContainer.generateErrorResponse = function(result, requestObjects,
@@ -456,14 +456,13 @@ var JsonRpcRequestItem = function(rpc, o
'POST_DATA' : gadgets.json.stringify(rpc)
};
- var url = [this.invalidatePath_];
+ var headers = {'Content-Type': 'application/json'};
var token = shindig.auth.getSecurityToken();
if (token) {
- url.push('?st=', encodeURIComponent(token));
+ headers['Authorization'] = 'OAuth ' + token;
}
- this.sendRequest(url.join(''), null, makeRequestParams,
- 'application/json');
+ this.sendRequest(this.invalidatePath_, null, makeRequestParams, headers);
};
})();
Modified: shindig/trunk/features/src/main/javascript/features/osapi/jsonrpctransport.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/osapi/jsonrpctransport.js?rev=1041256&r1=1041255&r2=1041256&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/osapi/jsonrpctransport.js (original)
+++ shindig/trunk/features/src/main/javascript/features/osapi/jsonrpctransport.js Thu Dec 2 02:28:16 2010
@@ -58,14 +58,14 @@
'METHOD' : 'POST',
'AUTHORIZATION' : 'SIGNED'
};
+ var headers = {'Content-Type': 'application/json'};
var url = this.name;
var token = shindig.auth.getSecurityToken();
if (token) {
- url += '?st=';
- url += encodeURIComponent(token);
+ headers['Authorization'] = 'OAuth ' + token;
}
- gadgets.io.makeNonProxiedRequest(url, processResponse, request, 'application/json');
+ gadgets.io.makeNonProxiedRequest(url, processResponse, request, headers);
}
function init(config) {
Modified: shindig/trunk/features/src/main/javascript/features/rpc/rpc.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/rpc/rpc.js?rev=1041256&r1=1041255&r2=1041256&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/rpc/rpc.js (original)
+++ shindig/trunk/features/src/main/javascript/features/rpc/rpc.js Thu Dec 2 02:28:16 2010
@@ -296,7 +296,7 @@ if (!gadgets.rpc) { // make lib resilien
// }, 1000);
// }
if (rpc.c) {
- rpc.callback = function(result) {
+ rpc['callback'] = function(result) {
gadgets.rpc.call(rpc.f, CALLBACK_NAME, null, rpc.c, result);
};
}
Modified: shindig/trunk/features/src/main/javascript/features/shindig.container/shindig-container.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/shindig.container/shindig-container.js?rev=1041256&r1=1041255&r2=1041256&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/shindig.container/shindig-container.js (original)
+++ shindig/trunk/features/src/main/javascript/features/shindig.container/shindig-container.js Thu Dec 2 02:28:16 2010
@@ -671,7 +671,7 @@ shindig.BaseIfrGadget.prototype.queryIfr
gadgets.io.makeNonProxiedRequest(url,
handleJSONResponse,
makeRequestParams,
- 'application/javascript'
+ {'Content-Type':'application/javascript'}
);
var gadget = this;
Modified: shindig/trunk/features/src/test/javascript/features/osapi/batchtest.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/test/javascript/features/osapi/batchtest.js?rev=1041256&r1=1041255&r2=1041256&view=diff
==============================================================================
--- shindig/trunk/features/src/test/javascript/features/osapi/batchtest.js (original)
+++ shindig/trunk/features/src/test/javascript/features/osapi/batchtest.js Thu Dec 2 02:28:16 2010
@@ -55,9 +55,9 @@ BatchTest.prototype.testAddAndExecuteOne
var argsInCallToMakeNonProxiedRequest;
var oldMakeRequest = gadgets.io.makeNonProxiedRequest;
try {
- gadgets.io.makeNonProxiedRequest = function(url, callback, params, contentType) {
+ gadgets.io.makeNonProxiedRequest = function(url, callback, params, headers) {
argsInCallToMakeNonProxiedRequest = { url : url, callback : callback, params : params,
- contentType : contentType};
+ headers : headers};
};
batch.execute(function() {});
@@ -86,9 +86,9 @@ BatchTest.prototype.testAddAndExecuteTwo
var argsInCallToMakeNonProxiedRequest;
var oldMakeRequest = gadgets.io.makeNonProxiedRequest;
try {
- gadgets.io.makeNonProxiedRequest = function(url, callback, params, contentType) {
+ gadgets.io.makeNonProxiedRequest = function(url, callback, params, headers) {
argsInCallToMakeNonProxiedRequest = { url : url, callback : callback, params : params,
- contentType : contentType};
+ headers : headers};
};
batch.execute(function() {});
this.assertArgsToMakeNonProxiedRequest(argsInCallToMakeNonProxiedRequest, expectedJson);
Modified: shindig/trunk/features/src/test/javascript/features/osapi/jsonrpctransporttest.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/test/javascript/features/osapi/jsonrpctransporttest.js?rev=1041256&r1=1041255&r2=1041256&view=diff
==============================================================================
--- shindig/trunk/features/src/test/javascript/features/osapi/jsonrpctransporttest.js (original)
+++ shindig/trunk/features/src/test/javascript/features/osapi/jsonrpctransporttest.js Thu Dec 2 02:28:16 2010
@@ -24,11 +24,11 @@ JsonRpcTransportTest.inherits(TestCase);
var lastXhr = {};
-JsonRpcTransportTest.prototype.dummyXhr = function(url, callback, params, contentType) {
+JsonRpcTransportTest.prototype.dummyXhr = function(url, callback, params, headers) {
lastXhr.url = url;
lastXhr.callback = callback;
lastXhr.params = params;
- lastXhr.contentType = contentType;
+ lastXhr.headers = headers;
callback(lastXhr.result);
};
@@ -235,11 +235,11 @@ JsonRpcTransportTest.inherits(TestCase);
var lastXhr = {};
-JsonRpcTransportTest.prototype.dummyXhr = function(url, callback, params, contentType) {
+JsonRpcTransportTest.prototype.dummyXhr = function(url, callback, params, headers) {
lastXhr.url = url;
lastXhr.callback = callback;
lastXhr.params = params;
- lastXhr.contentType = contentType;
+ lastXhr.headers = headers;
callback(lastXhr.result);
};
Modified: shindig/trunk/features/src/test/javascript/lib/testutils.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/test/javascript/lib/testutils.js?rev=1041256&r1=1041255&r2=1041256&view=diff
==============================================================================
--- shindig/trunk/features/src/test/javascript/lib/testutils.js (original)
+++ shindig/trunk/features/src/test/javascript/lib/testutils.js Thu Dec 2 02:28:16 2010
@@ -42,7 +42,7 @@ TestCase.prototype.assertArgsToMakeNonPr
this.assertTrue('params should be passed to makeNonProxiedRequest',
argsInCall.params);
this.assertEquals('Content type should match', 'application/json',
- argsInCall.contentType);
+ argsInCall.headers['Content-Type']);
this.assertEquals('Json for batch should match', expectedJson,
gadgets.json.parse(argsInCall.params.POST_DATA));
Modified: shindig/trunk/java/common/conf/shindig.properties
URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/conf/shindig.properties?rev=1041256&r1=1041255&r2=1041256&view=diff
==============================================================================
--- shindig/trunk/java/common/conf/shindig.properties (original)
+++ shindig/trunk/java/common/conf/shindig.properties Thu Dec 2 02:28:16 2010
@@ -155,3 +155,7 @@ shindig.proxy.remapInternalServerError=t
# Add debug data when using VanillaCajaHtmlParser.
vanillaCajaParser.needsDebugData=true
+
+# Allow non-SSL OAuth 2.0 bearer tokens
+org.apache.shindig.auth.oauth2-require-ssl=false
+
Modified: shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/UrlParameterAuthenticationHandler.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/UrlParameterAuthenticationHandler.java?rev=1041256&r1=1041255&r2=1041256&view=diff
==============================================================================
--- shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/UrlParameterAuthenticationHandler.java (original)
+++ shindig/trunk/java/common/src/main/java/org/apache/shindig/auth/UrlParameterAuthenticationHandler.java Thu Dec 2 02:28:16 2010
@@ -19,6 +19,7 @@ package org.apache.shindig.auth;
import com.google.common.collect.Maps;
import com.google.inject.Inject;
+import com.google.inject.name.Named;
import net.oauth.OAuth;
import java.util.Enumeration;
@@ -35,11 +36,14 @@ public class UrlParameterAuthenticationH
private static final String SECURITY_TOKEN_PARAM = "st";
private final SecurityTokenCodec securityTokenCodec;
- private static final Pattern COMMAWHITESPACE = Pattern.compile("\\s*,\\s*");
+ private final Boolean oauthSSLrequired;
@Inject
- public UrlParameterAuthenticationHandler(SecurityTokenCodec securityTokenCodec) {
+ public UrlParameterAuthenticationHandler(SecurityTokenCodec securityTokenCodec,
+ @Named("org.apache.shindig.auth.oauth2-require-ssl")
+ Boolean oauthSSLrequired) {
this.securityTokenCodec = securityTokenCodec;
+ this.oauthSSLrequired = oauthSSLrequired;
}
public String getName() {
@@ -68,32 +72,31 @@ public class UrlParameterAuthenticationH
return this.securityTokenCodec;
}
- // From OAuthMessage
- private static final Pattern AUTHORIZATION = Pattern.compile("\\s*(\\w*)\\s+(.*)");
- private static final Pattern NVP = Pattern.compile("(\\S*)\\s*\\=\\s*\"([^\"]*)\"");
+ private static final Pattern AUTHORIZATION_REGEX = Pattern.compile("\\s*OAuth\\s+(\\S*)\\s*.*");
protected Map<String, String> getMappedParameters(final HttpServletRequest request) {
Map<String, String> params = Maps.newHashMap();
+ boolean isSecure = this.oauthSSLrequired ? request.isSecure() : true;
// old style security token
String token = request.getParameter(SECURITY_TOKEN_PARAM);
// OAuth2 token as a param
// NOTE: if oauth_signature_method is present then we have a OAuth 1.0 request
- if (token == null && request.isSecure() && request.getParameter(OAuth.OAUTH_SIGNATURE_METHOD) == null) {
+ // See OAuth 2.0 Draft 10 -- 5.1.2 URI Query Parameter
+ if (token == null && isSecure && request.getParameter(OAuth.OAUTH_SIGNATURE_METHOD) == null) {
token = request.getParameter(OAuth.OAUTH_TOKEN);
}
// token in authorization header
- if (token == null) {
+ // See OAuth 2.0 Draft 10 -- 5.1.1 The Authorization Request Header Field
+ if (token == null && isSecure) {
for (Enumeration<String> headers = request.getHeaders("Authorization"); headers != null && headers.hasMoreElements();) {
- Matcher m = AUTHORIZATION.matcher(headers.nextElement());
- if (m.matches() && "Token".equalsIgnoreCase(m.group(1))) {
- for (String nvp : COMMAWHITESPACE.split(m.group(2))) {
- m = NVP.matcher(nvp);
- if (m.matches() && "token".equals(m.group(1))) {
- token = OAuth.decodePercent(m.group(2));
- }
+ String authorization = headers.nextElement();
+ if (authorization != null && !authorization.contains("oauth_signature_method=")) {
+ Matcher m = AUTHORIZATION_REGEX.matcher(authorization);
+ if (m.matches()) {
+ token = m.group(1);
}
}
}
Added: shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/UrlParameterAuthenticationHandlerTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/UrlParameterAuthenticationHandlerTest.java?rev=1041256&view=auto
==============================================================================
--- shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/UrlParameterAuthenticationHandlerTest.java (added)
+++ shindig/trunk/java/common/src/test/java/org/apache/shindig/auth/UrlParameterAuthenticationHandlerTest.java Thu Dec 2 02:28:16 2010
@@ -0,0 +1,103 @@
+package org.apache.shindig.auth;
+
+import com.google.common.collect.ImmutableMap;
+import org.apache.shindig.common.testing.FakeHttpServletRequest;
+import org.easymock.EasyMock;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Map;
+
+public class UrlParameterAuthenticationHandlerTest {
+ SecurityToken expectedToken;
+ UrlParameterAuthenticationHandler authHandler;
+ SecurityTokenCodec codec;
+ HttpServletRequest req;
+
+ @Before
+ public void setup() throws Exception {
+ expectedToken = new BasicSecurityToken(
+ "owner", "viewer", "app",
+ "domain", "appUrl", "moduleId", "container", "activeUrl", 1000L);
+ // Mock token codec
+ codec = new SecurityTokenCodec() {
+ public SecurityToken createToken(Map<String, String> tokenParameters) throws SecurityTokenException {
+ return tokenParameters == null ? null :
+ "1234".equals(tokenParameters.get(SecurityTokenCodec.SECURITY_TOKEN_NAME)) ? expectedToken : null;
+ }
+
+ public String encodeToken(SecurityToken token) throws SecurityTokenException {
+ return null;
+ }
+
+ public Long getTokenExpiration(SecurityToken token) throws SecurityTokenException {
+ return null;
+ }
+ };
+
+ authHandler = new UrlParameterAuthenticationHandler(codec, true);
+ }
+
+ @Test
+ public void testGetSecurityTokenFromRequest() throws Exception {
+ Assert.assertEquals(authHandler.getName(), AuthenticationMode.SECURITY_TOKEN_URL_PARAMETER.name());
+ }
+
+ @Test
+ public void testInvalidRequests() throws Exception {
+ // Empty request
+ req = new FakeHttpServletRequest();
+ Assert.assertNull(authHandler.getSecurityTokenFromRequest(req));
+
+ // Old behavior, no longer supported
+ req = new FakeHttpServletRequest().setHeader("Authorization", "Token token=\"1234\"");
+ Assert.assertNull(authHandler.getSecurityTokenFromRequest(req));
+ }
+
+ @Test
+ public void testSecurityToken() throws Exception {
+ // security token in request
+ req = new FakeHttpServletRequest("http://example.org/rpc?st=1234");
+ Assert.assertEquals(expectedToken, authHandler.getSecurityTokenFromRequest(req));
+ }
+
+ @Test
+ public void testOAuth1() throws Exception {
+ // An OAuth 1.0 request, we should not process this.
+ req = new FakeHttpServletRequest()
+ .setHeader("Authorization", "OAuth oauth_signature_method=\"RSA-SHA1\"");
+ SecurityToken token = authHandler.getSecurityTokenFromRequest(req);
+ Assert.assertNull(token);
+ }
+
+ @Test
+ public void testOAuth2Header() throws Exception {
+ req = new FakeHttpServletRequest("https://www.example.org/")
+ .setHeader("Authorization", "OAuth 1234");
+ Assert.assertEquals(expectedToken, authHandler.getSecurityTokenFromRequest(req));
+
+ req = new FakeHttpServletRequest("https://www.example.org/")
+ .setHeader("Authorization", " OAuth 1234 ");
+ Assert.assertEquals(expectedToken, authHandler.getSecurityTokenFromRequest(req));
+
+ req = new FakeHttpServletRequest("https://www.example.org/")
+ .setHeader("Authorization", "OAuth 1234 x=1,y=\"2 2 2\"");
+ Assert.assertEquals(expectedToken, authHandler.getSecurityTokenFromRequest(req));
+
+ req = new FakeHttpServletRequest("http://www.example.org/")
+ .setHeader("Authorization", "OAuth 1234");
+ Assert.assertNull(authHandler.getSecurityTokenFromRequest(req));
+ }
+
+ @Test
+ public void testOAuth2Param() throws Exception
+ {
+ req = new FakeHttpServletRequest("https://www.example.com?oauth_token=1234");
+ Assert.assertEquals(expectedToken, authHandler.getSecurityTokenFromRequest(req));
+
+ req = new FakeHttpServletRequest("https://www.example.com?oauth_token=1234&oauth_signature_method=RSA-SHA1");
+ Assert.assertNull(authHandler.getSecurityTokenFromRequest(req));
+ }
+}
Modified: shindig/trunk/php/src/gadgets/GadgetContext.php
URL: http://svn.apache.org/viewvc/shindig/trunk/php/src/gadgets/GadgetContext.php?rev=1041256&r1=1041255&r2=1041256&view=diff
==============================================================================
--- shindig/trunk/php/src/gadgets/GadgetContext.php (original)
+++ shindig/trunk/php/src/gadgets/GadgetContext.php Thu Dec 2 02:28:16 2010
@@ -267,16 +267,29 @@ class GadgetContext {
* @return string
*/
public function getRawToken() {
- if (! $this->rawToken) {
- $this->rawToken = isset($_GET["st"]) ? $_GET["st"] : '';
- }
- if (! $this->rawToken) {
- $this->rawToken = isset($_POST['st']) ? $_POST['st'] : '';
+ if ($this->rawToken) {
+ return $this->rawToken;
}
+ $this->rawToken = isset($_GET['st']) ? $_GET['st'] :
+ isset($_POST['st']) ? $_POST['st'] :
+ $this->parseAuthorization($_SERVER['AUTHORIZATION']);
+
+
return $this->rawToken;
}
+ private function parseAuthorization($authHeader) {
+ if (substr($authHeader, 0, 5) != 'OAuth') {
+ return '';
+ }
+ // Ignore OAuth 1.0a
+ if (strpos($authHeader, "oauth_signature_method")) {
+ return '';
+ }
+ return trim(substr($authHeader, 6));
+ }
+
/**
* Extracts the 'st' token from the GET or POST params and calls the
* signer to validate the token