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();

Reply via email to