Author: ivol37 at gmail.com
Date: Fri Dec 3 15:04:14 2010
New Revision: 477
Log:
[AMDATU-206] Implemented OAuth Signed Requests
Added:
trunk/integration-tests/src/test/java/org/amdatu/test/integration/base/OAuthTestBase.java
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/OAuthSignedRequestsTest.java
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/OAuthThreeLeggedTest.java
- copied, changed from r474,
/trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/OAuthClientTest.java
Removed:
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/OAuthClientTest.java
Modified:
trunk/amdatu-authentication/oauth-client/src/main/java/org/amdatu/authentication/oauth/client/OAuthResourceOwnerClient.java
trunk/amdatu-authentication/oauth-client/src/main/java/org/amdatu/authentication/oauth/client/OAuthServiceConsumerClient.java
trunk/amdatu-authentication/oauth-client/src/main/java/org/amdatu/authentication/oauth/client/internal/OAuthClientBase.java
trunk/amdatu-authentication/oauth-server/src/main/java/org/amdatu/authentication/oauth/server/OAuthRequestTokenServlet.java
trunk/integration-tests/src/test/java/org/amdatu/test/integration/mock/OAuthProtectedTestServlet.java
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/HttpServiceTest.java
Modified:
trunk/amdatu-authentication/oauth-client/src/main/java/org/amdatu/authentication/oauth/client/OAuthResourceOwnerClient.java
==============================================================================
---
trunk/amdatu-authentication/oauth-client/src/main/java/org/amdatu/authentication/oauth/client/OAuthResourceOwnerClient.java
(original)
+++
trunk/amdatu-authentication/oauth-client/src/main/java/org/amdatu/authentication/oauth/client/OAuthResourceOwnerClient.java
Fri Dec 3 15:04:14 2010
@@ -76,7 +76,7 @@
OAuthException {
Map<String, String> paramProps = new HashMap<String, String>();
paramProps.put("oauth_token", accessor.requestToken);
- OAuthMessage response = sendRequest(accessor, paramProps,
getProvider().getAuthorizeTokenURL());
+ OAuthMessage response = invoke(accessor, "GET",
getProvider().getAuthorizeTokenURL(), paramProps, null, null);
// Now the result is an authorization page containing an HTML form we
are supposed to submit
// First read the token and callback from this form
Modified:
trunk/amdatu-authentication/oauth-client/src/main/java/org/amdatu/authentication/oauth/client/OAuthServiceConsumerClient.java
==============================================================================
---
trunk/amdatu-authentication/oauth-client/src/main/java/org/amdatu/authentication/oauth/client/OAuthServiceConsumerClient.java
(original)
+++
trunk/amdatu-authentication/oauth-client/src/main/java/org/amdatu/authentication/oauth/client/OAuthServiceConsumerClient.java
Fri Dec 3 15:04:14 2010
@@ -17,6 +17,7 @@
package org.amdatu.authentication.oauth.client;
import java.io.IOException;
+import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
@@ -45,6 +46,7 @@
* Once created, using this API only tokens can be generated for this
specified service consumer
* and service provider. If you need to authorize different tokens, you
will need to construct a
* new consumer client.
+ *
* @param provider The oAuth service provider to invoke to receive the
request and access tokens
* @param consumer The oAuth service consumer for which to generate the
request and access tokens.
*/
@@ -53,9 +55,61 @@
}
/**
+ * Invokes a Signed Request, according to the "Signing Requests" oAuth 1.0
specification (chapter 9), available
+ * on http://oauth.net/core/1.0/. Signed Requests can be used to sign
requests send from service consumer
+ * to service provider, such that the service provider can verify that the
request is indeed coming from that
+ * service consumer.
+ * The oAuth parameters are send along with the request in the query part
of the URL, unless a POST request is send
+ * with an empty body in which case the oAuth parameters are send in the
body (with a content-type of
+ * application/x-www-form-urlencoded).
+ *
+ * @param httpMethod The HTTP method of the resource to invoke (i.e. GET,
POST, PUT, DELETE). May be null,
+ * in which case GET is used.
+ * @param url The URL of the resource to invoke
+ * @param oAuthParameters Additional parameters to send along with the
request (which are also included in the
+ * signature). May be null.
+ * @return The result of the request, encapsulated as OAuthMessage.
+ * @throws IOException In case a I/O exception occurred
+ * @throws URISyntaxException In case a URISyntaxException exception
occurred
+ * @throws OAuthException In case oAuth validation failed
+ */
+ public OAuthMessage invokeSignedRequest(String httpMethod, String url,
Map<String, String> oAuthParameters)
+ throws IOException, URISyntaxException, OAuthException {
+ return invokeSignedRequest(httpMethod, url, oAuthParameters, null,
null);
+ }
+
+ /**
+ * Invokes a Signed Request, according to the "Signing Requests" oAuth 1.0
specification (chapter 9), available
+ * on http://oauth.net/core/1.0/. Signed Requests can be used to sign
requests send from service consumer
+ * to service provider, such that the service provider can verify that the
request is indeed coming from that
+ * service consumer.
+ * The oAuth parameters are send along with the request in the query part
of the URL, unless a POST request is send
+ * with an empty body in which case the oAuth parameters are send in the
body (with a content-type of
+ * application/x-www-form-urlencoded).
+ *
+ * @param httpMethod The HTTP method of the resource to invoke (i.e. GET,
POST, PUT, DELETE). May be null,
+ * in which case GET is used.
+ * @param url The URL of the resource to invoke
+ * @param oAuthParameters Additional parameters to send along with the
request (which are also included in the
+ * signature). May be null.
+ * @param headers The HTTP headers to send along with the request.
+ * @param is The input stream of the body to send along with the request
+ * @return The result of the request, encapsulated as OAuthMessage.
+ * @throws IOException In case a I/O exception occurred
+ * @throws URISyntaxException In case a URISyntaxException exception
occurred
+ * @throws OAuthException In case oAuth validation failed
+ */
+ public OAuthMessage invokeSignedRequest(String httpMethod, String url,
Map<String, String> oAuthParameters,
+ Map<String, String> headers, InputStream is) throws IOException,
URISyntaxException, OAuthException {
+ OAuthAccessor accessor = createAccessor();
+ return invoke(accessor, httpMethod, url, oAuthParameters, headers, is);
+ }
+
+ /**
* Generates a new request token and returns an OAuthAccessor which
contains the generated token.
* The request token will be available in accessor.requestToken and the
corresponding token secret
* in accessor.tokenSecret.
+ *
* @return The OAuth accessor containing the request token and associated
token secret.
* @throws IOException In case a I/O exception occurred
* @throws OAuthException In case the request token could not be generated.
@@ -69,13 +123,13 @@
}
/**
- * Exchanges the request token for an access token. Note that the request
token must be authorized
- * (for example by using the resource owner client) before this method is
invoked. If the token
+ * Exchanges the request token for an access token. Note that the request
token must be authorized
+ * (for example by using the resource owner client) before this method is
invoked. If the token
* is not yet authorized, an OAuthException will be thrown.
*
* @param accessor The OAuth accessor containing the request token and
associated token secret.
- * @return The result OAut message, containing the access token
(message.getToken() and associated
- * token secret (message.getParameter("oauth_token_secret"))
+ * @return The result OAut message, containing the access token
(message.getToken() and associated
+ * token secret (message.getParameter("oauth_token_secret"))
* @throws IOException In case a I/O exception occurred
* @throws URISyntaxException In case some URL could not be parsed
* @throws OAuthException In case the request token in the accessor is
invalid or not yet authorized
@@ -83,30 +137,33 @@
public OAuthMessage getAccessToken(OAuthAccessor accessor) throws
IOException, URISyntaxException, OAuthException {
Map<String, String> paramProps = new HashMap<String, String>();
paramProps.put("oauth_token", accessor.requestToken);
- OAuthMessage response = sendRequest(accessor, paramProps,
getProvider().getAccessTokenURL());
+ OAuthMessage response = invoke(accessor, "GET",
getProvider().getAccessTokenURL(), paramProps, null, null);
return response;
}
-
+
/**
- * Access a protected resource which is hosted by the specified URL. The
accessor passed must
- * provide the access token and associated token secret received before by
performing an
- * oAuth negotiation (request token, authorize token and access token).
This method
+ * Access a protected resource which is hosted by the specified URL. The
accessor passed must
+ * provide the access token and associated token secret received before by
performing an
+ * oAuth negotiation (request token, authorize token and access token).
This method
+ *
* @param accessor The OAuth accessor holding the access token and
associated token secret to
- * use for invoking the protected resource.
+ * use for invoking the protected resource.
* @param url The URL to invoke (currently only a GET to this URL is
supported)
* @return An OAuth message encapsulating the result of the http method
call.
* @throws IOException In case a I/O exception occurred
* @throws URISyntaxException In case some URL could not be parsed
- * @throws OAuthException In case the request token in the accessor is
invalid or not yet authorized
+ * @throws OAuthException In case the request token in the accessor is
invalid or not yet authorized
*/
- public OAuthMessage accessResource(OAuthAccessor accessor, String url)
throws IOException, URISyntaxException, OAuthException {
+ public OAuthMessage accessResource(OAuthAccessor accessor, String url,
String httpMethod) throws IOException,
+ URISyntaxException, OAuthException {
Map<String, String> paramProps = new HashMap<String, String>();
paramProps.put("oauth_token", accessor.accessToken);
- return sendRequest(accessor, paramProps, url);
+ return invoke(accessor, httpMethod, url, paramProps, null, null);
}
/**
* Converts accessor attributes to a String.
+ *
* @param accessor The OAuth accessor to convert
* @return Attributes of the OAuth accessor represented as a single String
*/
Modified:
trunk/amdatu-authentication/oauth-client/src/main/java/org/amdatu/authentication/oauth/client/internal/OAuthClientBase.java
==============================================================================
---
trunk/amdatu-authentication/oauth-client/src/main/java/org/amdatu/authentication/oauth/client/internal/OAuthClientBase.java
(original)
+++
trunk/amdatu-authentication/oauth-client/src/main/java/org/amdatu/authentication/oauth/client/internal/OAuthClientBase.java
Fri Dec 3 15:04:14 2010
@@ -17,6 +17,7 @@
package org.amdatu.authentication.oauth.client.internal;
import java.io.IOException;
+import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Iterator;
@@ -28,7 +29,10 @@
import net.oauth.OAuthConsumer;
import net.oauth.OAuthException;
import net.oauth.OAuthMessage;
+import net.oauth.ParameterStyle;
+import net.oauth.client.OAuthClient;
import net.oauth.client.httpclient4.HttpClient4;
+import net.oauth.http.HttpMessage;
import org.amdatu.authentication.oauth.api.OAuthServiceConsumer;
import org.amdatu.authentication.oauth.api.OAuthServiceProvider;
@@ -70,15 +74,60 @@
return new OAuthAccessor(oAuthConsumer);
}
- protected OAuthMessage sendRequest(OAuthAccessor accessor, Map<String,
String> map, String url) throws IOException,
- URISyntaxException, OAuthException {
+ /**
+ * Invoke an oAuth request.
+ *
+ * @param accessor The OAuth accessor
+ * @param httpMethod The HTTP method to invoke
+ * @param url The URL of the resource to invoke
+ * @param oAuthParameters Optional map of additional oAuth parameters. Any
parameter may be added, which will be added
+ * to the signature. By using this option, additional (public) information
can be send which cannot be forged (since it
+ * is part of the signature). May be null.
+ * @param headers Optional map of HTTP headers to send along with the
request. May be null.
+ * @param is Optional input stream to send along with the request (i.e. in
case of a POST). May be null.
+ * @return
+ * @throws IOException
+ * @throws OAuthException
+ * @throws URISyntaxException
+ */
+ protected OAuthMessage invoke(OAuthAccessor accessor, String httpMethod,
String url, Map<String, String> oAuthParameters,
+ Map<String, String> headers, InputStream is) throws IOException,
OAuthException, URISyntaxException {
+ // Set the oAuth parameters
List<Map.Entry<String, String>> params = new
ArrayList<Map.Entry<String, String>>();
- Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry<String, String> p = it.next();
- params.add(new OAuth.Parameter((String) p.getKey(), (String)
p.getValue()));
+ if (oAuthParameters != null) {
+ Iterator<Map.Entry<String, String>> it =
oAuthParameters.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<String, String> p = it.next();
+ params.add(new OAuth.Parameter((String) p.getKey(), (String)
p.getValue()));
+ }
}
+
+ // Create the request, with or without input stream
+ OAuthMessage request;
+ if (is == null) {
+ request = accessor.newRequestMessage(httpMethod, url, params);
+ }
+ else {
+ request = accessor.newRequestMessage(httpMethod, url, params, is);
+ }
+
+ // Set the HTTP headers
+ if (headers != null) {
+ Iterator<Map.Entry<String, String>> it =
headers.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<String, String> p = it.next();
+ request.getHeaders().add(new OAuth.Parameter((String)
p.getKey(), (String) p.getValue()));
+ }
+ }
+
+ Object accepted =
accessor.consumer.getProperty(OAuthConsumer.ACCEPT_ENCODING);
+ if (accepted != null) {
+ request.getHeaders().add(new
OAuth.Parameter(HttpMessage.ACCEPT_ENCODING, accepted.toString()));
+ }
+ Object ps = accessor.consumer.getProperty(OAuthClient.PARAMETER_STYLE);
+ ParameterStyle style = (ps == null) ? ParameterStyle.BODY
+ : Enum.valueOf(ParameterStyle.class, ps.toString());
net.oauth.client.OAuthClient client = new
net.oauth.client.OAuthClient(new HttpClient4());
- return client.invoke(accessor, "GET", url, params);
+ return client.invoke(request, style);
}
}
Modified:
trunk/amdatu-authentication/oauth-server/src/main/java/org/amdatu/authentication/oauth/server/OAuthRequestTokenServlet.java
==============================================================================
---
trunk/amdatu-authentication/oauth-server/src/main/java/org/amdatu/authentication/oauth/server/OAuthRequestTokenServlet.java
(original)
+++
trunk/amdatu-authentication/oauth-server/src/main/java/org/amdatu/authentication/oauth/server/OAuthRequestTokenServlet.java
Fri Dec 3 15:04:14 2010
@@ -27,5 +27,5 @@
/**
* The servlet alias of the request token servlet.
*/
- final static String SERVLET_ALIAS = "/" +
OAuthResourceProviderImpl.RESOURCE_ID + "/requesttoken";
+ final static String SERVLET_ALIAS = "/" +
OAuthResourceProviderImpl.RESOURCE_ID + "/requesttoken";
}
Added:
trunk/integration-tests/src/test/java/org/amdatu/test/integration/base/OAuthTestBase.java
==============================================================================
--- (empty file)
+++
trunk/integration-tests/src/test/java/org/amdatu/test/integration/base/OAuthTestBase.java
Fri Dec 3 15:04:14 2010
@@ -0,0 +1,161 @@
+/*
+ Copyright (C) 2010 Amdatu.org
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.test.integration.base;
+
+import static org.ops4j.pax.exam.CoreOptions.provision;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import javax.servlet.Servlet;
+
+import net.oauth.OAuth;
+import net.oauth.OAuthConsumer;
+import net.oauth.OAuthMessage;
+import net.oauth.OAuthProblemException;
+
+import org.amdatu.authentication.oauth.api.OAuthServiceConsumer;
+import org.amdatu.authentication.oauth.api.OAuthServiceProvider;
+import org.amdatu.authentication.oauth.server.OAuthRequestTokenServlet;
+import org.amdatu.authentication.oauth.server.OAuthTokenProvider;
+import org.amdatu.test.integration.mock.OAuthProtectedTestServlet;
+import org.amdatu.test.integration.mock.OAuthTestConsumer;
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.http.HttpStatus;
+import org.junit.Assert;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.log.LogService;
+
+public class OAuthTestBase extends IntegrationTestBase {
+ protected volatile LogService m_logService;
+ protected volatile OAuthServiceProvider m_oAuthServiceProvider;
+ protected volatile ConfigurationAdmin m_configAdmin;
+ protected volatile DependencyManager m_dependencyManager;
+ protected volatile OAuthTokenProvider m_tokenProvider;
+
+ @Configuration
+ public Option[] configure() {
+ return super.configure();
+ }
+
+ protected void initConfiguration() throws IOException {
+ m_configAdmin = getService(ConfigurationAdmin.class);
+
+ // Add cassandra and templates configs
+ ConfigProvider configProvider = new ConfigProvider();
+ configProvider.addHttpServiceConfig(m_configAdmin);
+ configProvider.addOAuthConfig(m_configAdmin);
+ configProvider.addLogConfig(m_configAdmin);
+ }
+
+ protected Component[] getDependencies(DependencyManager manager) {
+ // Now register a test servlet
+ OAuthProtectedTestServlet m_testServlet = new
OAuthProtectedTestServlet();
+ Dictionary<String, String> servletProperties = new Hashtable<String,
String>();
+ servletProperties.put("alias",
OAuthProtectedTestServlet.SERVLET_ALIAS);
+ servletProperties.put("contextId",
OAuthProtectedTestServlet.SERVLET_ALIAS);
+ Component servletComponent = manager.createComponent()
+ .setImplementation(m_testServlet)
+ .setInterface(new String[] { Servlet.class.getName() },
servletProperties)
+
.add(manager.createServiceDependency().setService(LogService.class).setRequired(true))
+
.add(manager.createServiceDependency().setService(OAuthTokenProvider.class).setRequired(true));
+
+ Component testComponent = manager.createComponent()
+ .setImplementation(this)
+
.add(manager.createServiceDependency().setService(OAuthRequestTokenServlet.class).setRequired(true))
+
.add(manager.createServiceDependency().setService(OAuthTokenProvider.class).setRequired(true))
+
.add(manager.createServiceDependency().setService(OAuthServiceProvider.class).setRequired(true))
+
.add(manager.createServiceDependency().setService(ConfigurationAdmin.class).setRequired(true))
+
.add(manager.createServiceDependency().setService(LogService.class).setRequired(true));
+
+ return new Component[] { servletComponent, testComponent };
+ }
+
+ protected Option provisionBundles() {
+ return provision(
+ felixHttpServiceJetty(),
+ felixHttpServiceWhiteboard(),
+ slingMime(),
+ slingCommons(),
+ commonsCodec(),
+ commonsLogging(),
+ commonsHttpClient(),
+ paxSwissbox(),
+ ops4jBaseLang(),
+ json(),
+ amdatuHttpContext(),
+ amdatuJaxRs(),
+ amdatuOAuthAPI(),
+ amdatuOAuthClient(),
+ amdatuOAuthServer(),
+ amdatuJspSupport());
+ }
+
+ protected void waitForOAuthServlets() throws MalformedURLException,
IOException {
+ // First wait for the request servlet to become available
+ m_logService.log(LogService.LOG_DEBUG, "Waiting for '" +
m_oAuthServiceProvider.getRequestTokenURL() + "' to come available...");
+ waitForURL( m_oAuthServiceProvider.getRequestTokenURL(),
HttpStatus.SC_UNAUTHORIZED);
+ m_logService.log(LogService.LOG_DEBUG, "Waiting for '" +
m_oAuthServiceProvider.getAuthorizeTokenURL() + "' to come available...");
+ waitForURL( m_oAuthServiceProvider.getAuthorizeTokenURL(),
HttpStatus.SC_UNAUTHORIZED);
+ m_logService.log(LogService.LOG_DEBUG, "Waiting for '" +
m_oAuthServiceProvider.getAccessTokenURL() + "' to come available...");
+ waitForURL( m_oAuthServiceProvider.getAccessTokenURL(),
HttpStatus.SC_UNAUTHORIZED);
+ m_logService.log(LogService.LOG_DEBUG, "oAuth servlets available");
+ }
+
+ // Register the test service consumer
+ protected OAuthServiceConsumer registerTestServiceConsumer() throws
Exception {
+ Dictionary<String, String> properties = new Hashtable<String,
String>();
+ properties.put("consumer_key", OAuthTestConsumer.DEFAULT_CONSUMER_KEY);
+ OAuthTestConsumer testConsumer = new OAuthTestConsumer();
+ m_dependencyManager.add(
+ m_dependencyManager.createComponent()
+ .setInterface(OAuthServiceConsumer.class.getName(), properties)
+ .setImplementation(testConsumer));
+
+ // Check if it becomes available
+ Assert.assertTrue("OAuth service consumer is not begin registered",
getService(OAuthServiceConsumer.class,
+ "consumer_key=" + OAuthTestConsumer.DEFAULT_CONSUMER_KEY) != null);
+
+ // We have to wait until the service consumer is picked up by our
token provider. We retry this for a
+ // maximum amount of 5 times
+ OAuthMessage message = new OAuthMessage(null, null, null);
+ message.addParameter(OAuth.OAUTH_CONSUMER_KEY,
OAuthTestConsumer.DEFAULT_CONSUMER_KEY);
+ OAuthConsumer consumer = null;
+ int retryCount = 0;
+ while (consumer == null && retryCount < 5) {
+ try {
+ consumer = m_tokenProvider.getConsumer(message);
+ }
+ catch (IOException e) {}
+ catch (OAuthProblemException e) {}
+ if (consumer == null) {
+ m_logService.log(LogService.LOG_DEBUG,
+ "OAuth consumer not yet picked by by token provider,
retrycount=" + (retryCount + 1));
+ Thread.sleep(1000);
+ retryCount++;
+ }
+ }
+ Assert.assertTrue("OAuth service consumer seems not being picked up by
the token provider", consumer != null);
+ m_logService.log(LogService.LOG_DEBUG, "Service consumer registered
successfully");
+ return testConsumer;
+ }
+}
Modified:
trunk/integration-tests/src/test/java/org/amdatu/test/integration/mock/OAuthProtectedTestServlet.java
==============================================================================
---
trunk/integration-tests/src/test/java/org/amdatu/test/integration/mock/OAuthProtectedTestServlet.java
(original)
+++
trunk/integration-tests/src/test/java/org/amdatu/test/integration/mock/OAuthProtectedTestServlet.java
Fri Dec 3 15:04:14 2010
@@ -16,9 +16,16 @@
*/
package org.amdatu.test.integration.mock;
+import java.io.BufferedReader;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.Writer;
import java.net.URISyntaxException;
+import java.util.Enumeration;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
@@ -27,6 +34,7 @@
import javax.servlet.http.HttpServletResponse;
import net.oauth.OAuthAccessor;
+import net.oauth.OAuthConsumer;
import net.oauth.OAuthException;
import net.oauth.OAuthMessage;
import net.oauth.OAuthProblemException;
@@ -45,32 +53,56 @@
private volatile OAuthTokenProvider m_tokenProvider;
public void doGet(HttpServletRequest request, HttpServletResponse response)
- throws IOException, ServletException {
- processRequest(request, response);
+ throws IOException, ServletException {
+ processRequest("GET", request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse
response)
- throws IOException, ServletException {
- processRequest(request, response);
+ throws IOException, ServletException {
+ processRequest("POST", request, response);
}
- public void processRequest(HttpServletRequest request, HttpServletResponse
response)
- throws IOException, ServletException {
- m_logService.log(LogService.LOG_DEBUG, "Protected resource test
servlet received incoming request, validating token");
+ public void processRequest(String method, HttpServletRequest request,
HttpServletResponse response)
+ throws IOException, ServletException {
+ m_logService.log(LogService.LOG_DEBUG,
+ "Protected resource test servlet received incoming request,
validating token");
try {
- // Validate the token
- OAuthMessage requestMessage = OAuthServlet.getMessage(request,
null);
- OAuthAccessor accessor =
m_tokenProvider.getAccessor(requestMessage);
-
m_tokenProvider.getOAuthValidator().validateMessage(requestMessage, accessor);
- String userId = (String) accessor.getProperty("user");
-
+ // Validate oAuth message and get userId from it
+ String body = "";
+ String userId = validateOAuth(request);
+ if (userId == null) {
+ // In case of Signed Requests we return the received
parameters and headers and in case of a POST the body
+ if ("GET".equals(method)) {
+ body = "\ninputparameters:";
+ Enumeration<?> paramIt = request.getParameterNames();
+ while (paramIt.hasMoreElements()) {
+ String name = paramIt.nextElement().toString();
+ body += " " + name + "=" + request.getParameter(name);
+ }
+
+ body += "\nheaders:";
+ Enumeration<?> headerIt = request.getHeaderNames();
+ while (headerIt.hasMoreElements()) {
+ String name = headerIt.nextElement().toString();
+ body += " " + name + "=" + request.getHeader(name);
+ }
+ }
+ else if ("POST".equals(method)) {
+ body = "\nPOST!";
+ body += "\ncontent=" + toString(request.getInputStream());
+ }
+ }
+ else {
+ body = "userid=" + userId;
+ }
response.setContentType("text/plain");
PrintWriter out = null;
try {
out = response.getWriter();
- out.print("userid=" + userId);
- } finally {
+ out.print(body);
+ }
+ finally {
out.close();
}
}
@@ -84,4 +116,44 @@
throw new ServletException(e);
}
}
+
+ private String validateOAuth(HttpServletRequest request) throws
IOException, OAuthException, URISyntaxException {
+ OAuthMessage requestMessage = OAuthServlet.getMessage(request, null);
+
+ // In case of tow-legged or three-legged oAuth, the oAuth message
contains a request or access token
+ // A Signed request however doesn't provide a token, we first verify
the type of oAuth request
+ OAuthAccessor accessor;
+ if (requestMessage.getToken() == null ||
"".equals(requestMessage.getToken())) {
+ // This is a signed request
+ OAuthConsumer consumer =
m_tokenProvider.getConsumer(requestMessage);
+ accessor = new OAuthAccessor(consumer);
+ }
+ else {
+ // This is 2-legged or 3-legged oAuth
+ accessor = m_tokenProvider.getAccessor(requestMessage);
+ }
+ m_tokenProvider.getOAuthValidator().validateMessage(requestMessage,
accessor);
+ return (String) accessor.getProperty("user");
+ }
+
+ private String toString(InputStream is) throws IOException {
+ if (is != null) {
+ Writer writer = new StringWriter();
+ char[] buffer = new char[1024];
+ try {
+ Reader reader = new BufferedReader(new InputStreamReader(is,
"UTF-8"));
+ int size;
+ while ((size = reader.read(buffer)) != -1) {
+ writer.write(buffer, 0, size);
+ }
+ }
+ finally {
+ is.close();
+ }
+ return writer.toString();
+ }
+ else {
+ return "";
+ }
+ }
}
Modified:
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/HttpServiceTest.java
==============================================================================
---
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/HttpServiceTest.java
(original)
+++
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/HttpServiceTest.java
Fri Dec 3 15:04:14 2010
@@ -162,7 +162,6 @@
initialize();
// Wait until the test servlet is available, for a maximum of 5 seconds
-
String url = m_baseUrl + SERVLET_ALIAS;
m_logService.log(LogService.LOG_DEBUG, "Start waiting for url '" + url
+ "' to become available, timeout= " + TIMEOUT + "...");
if (!ConfigProvider.waitForURL(new URL(url), HttpStatus.SC_OK,
TIMEOUT)) {
@@ -170,7 +169,7 @@
// throws a connection refused, still listens to the default port
8080 or returns a 404. Therefore we
// retry once to connect to the default port 8080, if that fails
we skip running this integration test
// since it is likely that the reason that it fails is not caused
by any Amdatu code.
- url = "http://" + ConfigProvider.HOSTNAME + ":" +
ConfigProvider.DEFAULT_PORTNR;
+ url = "http://" + ConfigProvider.HOSTNAME + ":" +
ConfigProvider.DEFAULT_PORTNR + SERVLET_ALIAS;
if (!(ConfigProvider.checkURL(new URL(url)) == HttpStatus.SC_OK)) {
return;
}
@@ -227,7 +226,7 @@
// throws a connection refused, still listens to the default port
8080 or returns a 404. Therefore we
// retry once to connect to the default port 8080, if that fails
we skip running this integration test
// since it is likely that the reason that it fails is not caused
by any Amdatu code.
- url = "http://" + ConfigProvider.HOSTNAME + ":" +
ConfigProvider.DEFAULT_PORTNR;
+ url = "http://" + ConfigProvider.HOSTNAME + ":" +
ConfigProvider.DEFAULT_PORTNR + SERVLET_ALIAS;
if (!(ConfigProvider.checkURL(new URL(url)) == HttpStatus.SC_OK)) {
return;
}
Added:
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/OAuthSignedRequestsTest.java
==============================================================================
--- (empty file)
+++
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/OAuthSignedRequestsTest.java
Fri Dec 3 15:04:14 2010
@@ -0,0 +1,90 @@
+/*
+ Copyright (C) 2010 Amdatu.org
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.test.integration.tests;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.Hashtable;
+
+import net.oauth.OAuthMessage;
+
+import org.amdatu.authentication.oauth.api.OAuthServiceConsumer;
+import org.amdatu.authentication.oauth.client.OAuthServiceConsumerClient;
+import org.amdatu.test.integration.base.ConfigProvider;
+import org.amdatu.test.integration.base.OAuthTestBase;
+import org.amdatu.test.integration.mock.OAuthProtectedTestServlet;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.service.log.LogService;
+
+/**
+ * Test class for oAuth signed requests.
+ *
+ * @author ivol
+ */
+ at RunWith(JUnit4TestRunner.class)
+public class OAuthSignedRequestsTest extends OAuthTestBase {
+ @Test
+ public void testOAuthSignedRequests() throws Exception {
+ // First wait for the oAuth servlets to become available
+ waitForOAuthServlets();
+
+ // Step 1: Register a service consumer
+ m_logService.log(LogService.LOG_DEBUG, "*** Step 1: Register service
consumer ***");
+ OAuthServiceConsumer consumer = registerTestServiceConsumer();
+
+ // Step 2: Create an OAuthClient for our Amdatu OAuth server
+ m_logService.log(LogService.LOG_DEBUG, "*** Step 2: Create OAuth
Client ***");
+ OAuthServiceConsumerClient consumerClient = new
OAuthServiceConsumerClient(m_oAuthServiceProvider, consumer);
+
+ // Step 3a: Send a simple signed GET request and verify the result
+ m_logService.log(LogService.LOG_DEBUG, "*** Step 3a: Send simple
signed GET request ***");
+ String url = "http://" + ConfigProvider.HOSTNAME + ":" +
ConfigProvider.PORTNR + OAuthProtectedTestServlet.SERVLET_ALIAS;
+ OAuthMessage message = consumerClient.invokeSignedRequest("GET", url,
null);
+ String body = message.readBodyAsString();
+ m_logService.log(LogService.LOG_DEBUG, "Protected resource returns
response: '" + body + "'");
+ Assert.assertTrue(body.indexOf("inputparameters:") != -1);
+ Assert.assertTrue(body.indexOf("headers:") != -1);
+
+ // Step 3b: Test sending signed GET request with additional oAuth
parameters and HTTP headers
+ m_logService.log(LogService.LOG_DEBUG, "*** Step 3b: Send signed GET
request with headers and parameters ***");
+ Hashtable<String, String> params = new Hashtable<String, String>();
+ params.put("tenantid", "37");
+ params.put("testparam", "true");
+ Hashtable<String, String> headers = new Hashtable<String, String>();
+ headers.put("Accept", "application/json");
+ headers.put("Referer", "http://it_is_us.com");
+ message = consumerClient.invokeSignedRequest("GET", url, params,
headers, null);
+ body = message.readBodyAsString();
+ m_logService.log(LogService.LOG_DEBUG, "Protected resource returns
response: '" + body + "'");
+ Assert.assertTrue(body.indexOf("tenantid=37") != -1);
+ Assert.assertTrue(body.indexOf("testparam=true") != -1);
+ Assert.assertTrue(body.indexOf("Accept=application/json") != -1);
+ Assert.assertTrue(body.indexOf("Referer=http://it_is_us.com") != -1);
+
+ // Step 3c: Test sending a signed POST request with some body (not to
be confused with somebody)
+ m_logService.log(LogService.LOG_DEBUG, "*** Step 3c: Send signed POST
request ***");
+ String testSentence = "This is the contents of the test body";
+ InputStream is = new ByteArrayInputStream(testSentence.getBytes());
+ message = consumerClient.invokeSignedRequest("POST", url, null, null,
is);
+ body = message.readBodyAsString();
+ m_logService.log(LogService.LOG_DEBUG, "Protected resource returns
POST response: '" + body + "'");
+ Assert.assertTrue(body.indexOf("content=" + testSentence) != -1);
+ }
+}
Copied:
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/OAuthThreeLeggedTest.java
(from r474,
/trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/OAuthClientTest.java)
==============================================================================
---
/trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/OAuthClientTest.java
(original)
+++
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/OAuthThreeLeggedTest.java
Fri Dec 3 15:04:14 2010
@@ -16,128 +16,37 @@
*/
package org.amdatu.test.integration.tests;
-import static org.ops4j.pax.exam.CoreOptions.provision;
-
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.util.Dictionary;
-import java.util.Hashtable;
-
-import javax.servlet.Servlet;
-
-import net.oauth.OAuth;
import net.oauth.OAuthAccessor;
-import net.oauth.OAuthConsumer;
import net.oauth.OAuthMessage;
-import net.oauth.OAuthProblemException;
import org.amdatu.authentication.oauth.api.OAuthServiceConsumer;
-import org.amdatu.authentication.oauth.api.OAuthServiceProvider;
import org.amdatu.authentication.oauth.client.OAuthResourceOwnerClient;
import org.amdatu.authentication.oauth.client.OAuthServiceConsumerClient;
-import org.amdatu.authentication.oauth.server.OAuthRequestTokenServlet;
-import org.amdatu.authentication.oauth.server.OAuthTokenProvider;
import org.amdatu.test.integration.base.ConfigProvider;
-import org.amdatu.test.integration.base.IntegrationTestBase;
+import org.amdatu.test.integration.base.OAuthTestBase;
import org.amdatu.test.integration.mock.OAuthProtectedTestServlet;
import org.amdatu.test.integration.mock.OAuthTestConsumer;
-import org.apache.felix.dm.Component;
-import org.apache.felix.dm.DependencyManager;
-import org.apache.http.HttpStatus;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.ops4j.pax.exam.Option;
-import org.ops4j.pax.exam.junit.Configuration;
import org.ops4j.pax.exam.junit.JUnit4TestRunner;
-import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.log.LogService;
+/**
+ * Test class for 3-legged oAuth
+ *
+ * @author ivol
+ */
@RunWith(JUnit4TestRunner.class)
-public class OAuthClientTest extends IntegrationTestBase {
- private volatile DependencyManager m_dependencyManager;
- private volatile LogService m_logService;
- private volatile OAuthTokenProvider m_tokenProvider;
- private volatile OAuthServiceProvider m_oAuthServiceProvider;
- private volatile ConfigurationAdmin m_configAdmin;
-
- @Configuration
- public Option[] configure() {
- return super.configure();
- }
-
- protected void initConfiguration() throws IOException {
- m_configAdmin = getService(ConfigurationAdmin.class);
-
- // Add cassandra and templates configs
- ConfigProvider configProvider = new ConfigProvider();
- configProvider.addHttpServiceConfig(m_configAdmin);
- configProvider.addOAuthConfig(m_configAdmin);
- configProvider.addLogConfig(m_configAdmin);
- }
-
- protected Component[] getDependencies(DependencyManager manager) {
- // Now register a test servlet
- OAuthProtectedTestServlet m_testServlet = new
OAuthProtectedTestServlet();
- Dictionary<String, String> servletProperties = new Hashtable<String,
String>();
- servletProperties.put("alias",
OAuthProtectedTestServlet.SERVLET_ALIAS);
- servletProperties.put("contextId",
OAuthProtectedTestServlet.SERVLET_ALIAS);
- Component servletComponent = manager.createComponent()
- .setImplementation(m_testServlet)
- .setInterface(new String[] { Servlet.class.getName() },
servletProperties)
-
.add(manager.createServiceDependency().setService(LogService.class).setRequired(true))
-
.add(manager.createServiceDependency().setService(OAuthTokenProvider.class).setRequired(true));
-
- Component testComponent = manager.createComponent()
- .setImplementation(this)
-
.add(manager.createServiceDependency().setService(OAuthRequestTokenServlet.class).setRequired(true))
-
.add(manager.createServiceDependency().setService(OAuthTokenProvider.class).setRequired(true))
-
.add(manager.createServiceDependency().setService(OAuthServiceProvider.class).setRequired(true))
-
.add(manager.createServiceDependency().setService(ConfigurationAdmin.class).setRequired(true))
-
.add(manager.createServiceDependency().setService(LogService.class).setRequired(true));
-
- return new Component[] { servletComponent, testComponent };
- }
-
- protected Option provisionBundles() {
- return provision(
- felixHttpServiceJetty(),
- felixHttpServiceWhiteboard(),
- slingMime(),
- slingCommons(),
- commonsCodec(),
- commonsLogging(),
- commonsHttpClient(),
- paxSwissbox(),
- ops4jBaseLang(),
- json(),
- amdatuHttpContext(),
- amdatuJaxRs(),
- amdatuOAuthAPI(),
- amdatuOAuthClient(),
- amdatuOAuthServer(),
- amdatuJspSupport());
- }
-
- private void waitForOAuthServlets() throws MalformedURLException,
IOException {
- // First wait for the request servlet to become available
- m_logService.log(LogService.LOG_DEBUG, "Waiting for '" +
m_oAuthServiceProvider.getRequestTokenURL() + "' to come available...");
- waitForURL( m_oAuthServiceProvider.getRequestTokenURL(),
HttpStatus.SC_UNAUTHORIZED);
- m_logService.log(LogService.LOG_DEBUG, "Waiting for '" +
m_oAuthServiceProvider.getAuthorizeTokenURL() + "' to come available...");
- waitForURL( m_oAuthServiceProvider.getAuthorizeTokenURL(),
HttpStatus.SC_UNAUTHORIZED);
- m_logService.log(LogService.LOG_DEBUG, "Waiting for '" +
m_oAuthServiceProvider.getAccessTokenURL() + "' to come available...");
- waitForURL( m_oAuthServiceProvider.getAccessTokenURL(),
HttpStatus.SC_UNAUTHORIZED);
- m_logService.log(LogService.LOG_DEBUG, "oAuth servlets available");
- }
-
+public class OAuthThreeLeggedTest extends OAuthTestBase {
@Test
- // Test the three-legged oAuth dance
- public void testThreeLeggedOAuth() throws Exception {
+ public void testThreeLeggedOAuth() throws Exception {
+ // First wait for the oAuth servlets to become available
waitForOAuthServlets();
-
+
// Step 1: Register a service consumer
m_logService.log(LogService.LOG_DEBUG, "*** Step 1: Register service
consumer ***");
- OAuthServiceConsumer consumer = registerServiceConsumer();
+ OAuthServiceConsumer consumer = registerTestServiceConsumer();
// Step 2: Create an OAuthClient for our Amdatu OAuth server
m_logService.log(LogService.LOG_DEBUG, "*** Step 2: Create OAuth
Clients ***");
@@ -157,58 +66,22 @@
// Step 5: Exchange our request token for an access token
m_logService.log(LogService.LOG_DEBUG, "*** Step 5: Get access token
***");
OAuthMessage message = consumerClient.getAccessToken(accessor);
- accessor.accessToken = message.getToken();
+ accessor.accessToken = message.getToken();
accessor.tokenSecret = message.getParameter("oauth_token_secret");
accessor.requestToken = null;
- m_logService.log(LogService.LOG_DEBUG, "Access token received: " +
accessor.accessToken + ", with secret " + accessor.tokenSecret);
+ m_logService.log(LogService.LOG_DEBUG, "Access token received: " +
accessor.accessToken + ", with secret "
+ + accessor.tokenSecret);
// Step 6: Access a protected resource
m_logService.log(LogService.LOG_DEBUG, "*** Step 6: Access protected
resource ***");
- String url = "http://" + ConfigProvider.HOSTNAME + ":" +
ConfigProvider.PORTNR + OAuthProtectedTestServlet.SERVLET_ALIAS;
- message = consumerClient.accessResource(accessor, url);
+ String url =
+ "http://" + ConfigProvider.HOSTNAME + ":" + ConfigProvider.PORTNR
+ OAuthProtectedTestServlet.SERVLET_ALIAS;
+ message = consumerClient.accessResource(accessor, url, "GET");
String body = message.readBodyAsString();
m_logService.log(LogService.LOG_DEBUG, "Protected resource returns
response: '" + body + "'");
Assert.assertTrue(body.equals("userid=ivol"));
}
- // Step 1: Register a service consumer
- private OAuthServiceConsumer registerServiceConsumer() throws Exception {
- Dictionary<String, String> properties = new Hashtable<String,
String>();
- properties.put("consumer_key", OAuthTestConsumer.DEFAULT_CONSUMER_KEY);
- OAuthTestConsumer testConsumer = new OAuthTestConsumer();
- m_dependencyManager.add(
- m_dependencyManager.createComponent()
- .setInterface(OAuthServiceConsumer.class.getName(), properties)
- .setImplementation(testConsumer));
-
- // Check if it becomes available
- Assert.assertTrue("OAuth service consumer is not begin registered",
getService(OAuthServiceConsumer.class,
- "consumer_key=" + OAuthTestConsumer.DEFAULT_CONSUMER_KEY) != null);
-
- // We have to wait until the service consumer is picked up by our
token provider. We retry this for a
- // maximum amount of 5 times
- OAuthMessage message = new OAuthMessage(null, null, null);
- message.addParameter(OAuth.OAUTH_CONSUMER_KEY,
OAuthTestConsumer.DEFAULT_CONSUMER_KEY);
- OAuthConsumer consumer = null;
- int retryCount = 0;
- while (consumer == null && retryCount < 5) {
- try {
- consumer = m_tokenProvider.getConsumer(message);
- }
- catch (IOException e) {}
- catch (OAuthProblemException e) {}
- if (consumer == null) {
- m_logService.log(LogService.LOG_DEBUG,
- "OAuth consumer not yet picked by by token provider,
retrycount=" + (retryCount + 1));
- Thread.sleep(1000);
- retryCount++;
- }
- }
- Assert.assertTrue("OAuth service consumer seems not being picked up by
the token provider", consumer != null);
- m_logService.log(LogService.LOG_DEBUG, "Service consumer registered
successfully");
- return testConsumer;
- }
-
// Step 3: Generate a request token for our service consumer
private OAuthAccessor createRequestToken(OAuthServiceConsumerClient
client) throws Exception {
OAuthAccessor accessor = client.generateRequestToken();