Author: ivol37 at gmail.com
Date: Mon Dec 6 16:21:52 2010
New Revision: 479
Log:
[AMDATU-182] Implemented 2-legged oAuth by supporting persistent storage of
userids that granted access to service consumers by a 3-legged oAuth
negotiation once before.
Added:
trunk/amdatu-authentication/oauth-consumerregistry-fs/src/main/java/org/amdatu/authentication/oauth/consumerregistry/fs/internal/FSOAuthServiceConsumer.java
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/OAuthTwoLeggedTest.java
Modified:
trunk/amdatu-authentication/oauth-api/src/main/java/org/amdatu/authentication/oauth/api/OAuthServiceConsumerRegistry.java
trunk/amdatu-authentication/oauth-consumerregistry-fs/src/main/java/org/amdatu/authentication/oauth/consumerregistry/fs/internal/FSConsumerStore.java
trunk/amdatu-authentication/oauth-consumerregistry-fs/src/main/java/org/amdatu/authentication/oauth/consumerregistry/fs/service/FSConsumerRegistryImpl.java
trunk/amdatu-authentication/oauth-server/src/main/java/org/amdatu/authentication/oauth/server/osgi/Activator.java
trunk/amdatu-authentication/oauth-server/src/main/java/org/amdatu/authentication/oauth/server/service/OAuthTokenProviderImpl.java
trunk/amdatu-libraries/utilities/src/main/java/org/amdatu/libraries/utilities/FSUtil.java
trunk/integration-tests/src/test/java/org/amdatu/test/integration/base/OAuthTestBase.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/OAuthSignedRequestsTest.java
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/OAuthThreeLeggedTest.java
Modified:
trunk/amdatu-authentication/oauth-api/src/main/java/org/amdatu/authentication/oauth/api/OAuthServiceConsumerRegistry.java
==============================================================================
---
trunk/amdatu-authentication/oauth-api/src/main/java/org/amdatu/authentication/oauth/api/OAuthServiceConsumerRegistry.java
(original)
+++
trunk/amdatu-authentication/oauth-api/src/main/java/org/amdatu/authentication/oauth/api/OAuthServiceConsumerRegistry.java
Mon Dec 6 16:21:52 2010
@@ -69,4 +69,37 @@
* @throws ConsumerRegistryStorageException If an internal error occurred
in the consumer registry storage
*/
void updateConsumer(OAuthServiceConsumer consumer) throws
ConsumerNotFoundException, ConsumerRegistryStorageException;
+
+ /**
+ * Adds the id of a user that allowed this service consumer to access
protected resources on its behalf.
+ * This information can be used to support a 2-legged oAuth scenario. In
this scenario the user grants access
+ * to this consumer using a 3-legged oAuth dance once. This information is
then persisted in the consumer registry
+ * and so the service provider can verify if the user granted this access
before, preventing the need of another
+ * explicit approval the next time.
+ * @param consumer The service consumer to which access is granted
+ * @param userId the id of the user that granted the access
+ * @throws ConsumerRegistryStorageException If an internal error occurred
in the consumer registry storage
+ */
+ void grantResourceAccess(OAuthServiceConsumer consumer, String userId)
throws ConsumerRegistryStorageException;
+
+ /**
+ * Removes the id of a user that allowed this service consumer to access
protected resources on its behalf.
+ * This method can be used to support a kind of 'unsubscribe'
functionality; a user that wants to withdraw
+ * the rights of a service consumer to access its resources on its behalf.
+ * @param consumer The service consumer for which the access should be
withdrawn
+ * @param userId the id of the user that withdraws the access
+ * @throws ConsumerRegistryStorageException If an internal error occurred
in the consumer registry storage
+ */
+ void withdrawResourceAccess(OAuthServiceConsumer consumer, String userId)
throws ConsumerRegistryStorageException;
+
+ /**
+ * Returns if the specified user id granted access to the specified
consumer to access its protected resource
+ * (using a 3-legged oAuth dance) on its behalf before.
+ * @param consumer The service consumer to validate for
+ * @param userId The user id to check
+ * @return <code>true</code> if the user with this id granted access to
the specified service consumer
+ * to access its resources on its behalf.
+ * @throws ConsumerRegistryStorageException If an internal error occurred
in the consumer registry storage
+ */
+ boolean hasResourceAccess(OAuthServiceConsumer consumer, String userId)
throws ConsumerRegistryStorageException;
}
Modified:
trunk/amdatu-authentication/oauth-consumerregistry-fs/src/main/java/org/amdatu/authentication/oauth/consumerregistry/fs/internal/FSConsumerStore.java
==============================================================================
---
trunk/amdatu-authentication/oauth-consumerregistry-fs/src/main/java/org/amdatu/authentication/oauth/consumerregistry/fs/internal/FSConsumerStore.java
(original)
+++
trunk/amdatu-authentication/oauth-consumerregistry-fs/src/main/java/org/amdatu/authentication/oauth/consumerregistry/fs/internal/FSConsumerStore.java
Mon Dec 6 16:21:52 2010
@@ -24,6 +24,7 @@
import java.io.ObjectOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import org.amdatu.authentication.oauth.api.ConsumerRegistryStorageException;
@@ -32,11 +33,11 @@
public class FSConsumerStore {
private final File m_file;
- private final Map<String, OAuthServiceConsumer> m_consumers;
+ private final Map<String, FSOAuthServiceConsumer> m_consumers;
public FSConsumerStore(File file) throws ConsumerRegistryStorageException {
m_file = file;
- m_consumers = new HashMap<String, OAuthServiceConsumer>();
+ m_consumers = new HashMap<String, FSOAuthServiceConsumer>();
try {
readConsumers();
}
@@ -50,7 +51,7 @@
}
public OAuthServiceConsumer addConsumer(final OAuthServiceConsumer
consumer) {
- return m_consumers.put(consumer.getConsumerKey(), consumer);
+ return m_consumers.put(consumer.getConsumerKey(), new
FSOAuthServiceConsumer(consumer));
}
public OAuthServiceConsumer removeConsumer(final String consumerId) {
@@ -78,7 +79,7 @@
ois = new ObjectInputStream(fis);
final int numberOfConsumers = ois.readInt();
for (int i = 0; i < numberOfConsumers; i++) {
- final OAuthServiceConsumer consumer = readConsumer(ois);
+ final FSOAuthServiceConsumer consumer = readConsumer(ois);
m_consumers.put(consumer.getConsumerKey(), consumer);
}
}
@@ -87,33 +88,21 @@
}
}
- private OAuthServiceConsumer readConsumer(ObjectInputStream ois) throws
IOException, UnsupportedEncodingException {
+ private FSOAuthServiceConsumer readConsumer(ObjectInputStream ois) throws
IOException, UnsupportedEncodingException {
final String name = FSUtil.readString(ois);
final String key = FSUtil.readString(ois);
final String secret = FSUtil.readString(ois);
final String callbackUrl = FSUtil.readString(ois);
+ final List<String> allowedUserids = FSUtil.readList(ois);
final Map<String, String> properties = FSUtil.readProperties(ois);
- return new OAuthServiceConsumer() {
- public String getName() {
- return name;
- }
-
- public String getConsumerKey() {
- return key;
- }
-
- public String getConsumerSecret() {
- return secret;
- }
-
- public String getCallbackUrl() {
- return callbackUrl;
- }
-
- public Map<String, String> getProperties() {
- return properties;
- }
- };
+ FSOAuthServiceConsumer consumer = new FSOAuthServiceConsumer();
+ consumer.setName(name);
+ consumer.setConsumerKey(key);
+ consumer.setConsumerSecret(secret);
+ consumer.setCallbackUrl(callbackUrl);
+ consumer.setAllowedUserIds(allowedUserids);
+ consumer.setProperties(properties);
+ return consumer;
}
private void writeConsumers() throws IOException {
@@ -127,7 +116,7 @@
fos = new FileOutputStream(m_file);
oos = new ObjectOutputStream(fos);
oos.writeInt(m_consumers.size());
- for (OAuthServiceConsumer consumer : m_consumers.values()) {
+ for (FSOAuthServiceConsumer consumer : m_consumers.values()) {
writeConsumer(oos, consumer);
}
oos.flush();
@@ -137,12 +126,13 @@
}
}
- private void writeConsumer(ObjectOutputStream oos, OAuthServiceConsumer
consumer)
+ private void writeConsumer(ObjectOutputStream oos, FSOAuthServiceConsumer
consumer)
throws UnsupportedEncodingException, IOException {
FSUtil.writeString(oos, consumer.getName());
FSUtil.writeString(oos, consumer.getConsumerKey());
FSUtil.writeString(oos, consumer.getConsumerSecret());
FSUtil.writeString(oos, consumer.getCallbackUrl());
+ FSUtil.writeList(oos, consumer.getAllowedUserIds());
FSUtil.writeProperties(oos, consumer.getProperties());
}
}
Added:
trunk/amdatu-authentication/oauth-consumerregistry-fs/src/main/java/org/amdatu/authentication/oauth/consumerregistry/fs/internal/FSOAuthServiceConsumer.java
==============================================================================
--- (empty file)
+++
trunk/amdatu-authentication/oauth-consumerregistry-fs/src/main/java/org/amdatu/authentication/oauth/consumerregistry/fs/internal/FSOAuthServiceConsumer.java
Mon Dec 6 16:21:52 2010
@@ -0,0 +1,97 @@
+/*
+ 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.authentication.oauth.consumerregistry.fs.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.amdatu.authentication.oauth.api.OAuthServiceConsumer;
+
+/**
+ * Internal class to store OAuth service consumer properties, including a list
of userids that granted access
+ * to this service consumer to invoke the provider on its behalf.
+ *
+ * @author ivol
+ */
+public class FSOAuthServiceConsumer implements OAuthServiceConsumer {
+ private String m_consumerKey;
+ private String m_consumerSecret;
+ private String m_name;
+ private String m_callbackUrl;
+ private List<String> m_allowedUserIds = new ArrayList<String>();
+ private Map<String, String> m_properties;
+
+ public FSOAuthServiceConsumer() {
+ }
+
+ public FSOAuthServiceConsumer(OAuthServiceConsumer consumer) {
+ setName(consumer.getName());
+ setConsumerKey(consumer.getConsumerKey());
+ setConsumerSecret(consumer.getConsumerSecret());
+ setCallbackUrl(consumer.getCallbackUrl());
+ setProperties(consumer.getProperties());
+ }
+
+ public String getConsumerKey() {
+ return m_consumerKey;
+ }
+
+ public void setConsumerKey(String consumerKey) {
+ m_consumerKey = consumerKey;
+ }
+
+ public String getConsumerSecret() {
+ return m_consumerSecret;
+ }
+
+ public void setConsumerSecret(String consumerSecret) {
+ m_consumerSecret = consumerSecret;
+ }
+
+ public String getName() {
+ return m_name;
+ }
+
+ public void setName(String name) {
+ m_name = name;
+ }
+
+ public String getCallbackUrl() {
+ return m_callbackUrl;
+ }
+
+ public void setCallbackUrl(String callbackUrl) {
+ m_callbackUrl = callbackUrl;
+ }
+
+ public Map<String, String> getProperties() {
+ return m_properties;
+ }
+
+ public void setAllowedUserIds(List<String> allowedUserIds) {
+ m_allowedUserIds = allowedUserIds;
+ }
+
+ public List<String> getAllowedUserIds() {
+ return m_allowedUserIds;
+ }
+
+ public void setProperties(Map<String, String> properties) {
+ m_properties = properties;
+ }
+}
Modified:
trunk/amdatu-authentication/oauth-consumerregistry-fs/src/main/java/org/amdatu/authentication/oauth/consumerregistry/fs/service/FSConsumerRegistryImpl.java
==============================================================================
---
trunk/amdatu-authentication/oauth-consumerregistry-fs/src/main/java/org/amdatu/authentication/oauth/consumerregistry/fs/service/FSConsumerRegistryImpl.java
(original)
+++
trunk/amdatu-authentication/oauth-consumerregistry-fs/src/main/java/org/amdatu/authentication/oauth/consumerregistry/fs/service/FSConsumerRegistryImpl.java
Mon Dec 6 16:21:52 2010
@@ -17,7 +17,9 @@
package org.amdatu.authentication.oauth.consumerregistry.fs.service;
import java.io.File;
+import java.util.ArrayList;
import java.util.Dictionary;
+import java.util.List;
import org.amdatu.authentication.oauth.api.ConsumerAlreadyExistsException;
import org.amdatu.authentication.oauth.api.ConsumerNotFoundException;
@@ -26,6 +28,7 @@
import org.amdatu.authentication.oauth.api.OAuthServiceConsumerRegistry;
import
org.amdatu.authentication.oauth.consumerregistry.fs.internal.ConsumerKeyList;
import
org.amdatu.authentication.oauth.consumerregistry.fs.internal.FSConsumerStore;
+import
org.amdatu.authentication.oauth.consumerregistry.fs.internal.FSOAuthServiceConsumer;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedService;
import org.osgi.service.log.LogService;
@@ -144,6 +147,33 @@
consumerStorageFile.save();
m_logService.log(LogService.LOG_DEBUG, "Removed consumer with key '" +
consumer.getConsumerKey() + "' from the oAuth service consumer registry");
}
+
+ public void grantResourceAccess(OAuthServiceConsumer consumer, String
userId) throws ConsumerRegistryStorageException {
+ FSConsumerStore consumerStorageFile =
getStorageFile(consumer.getConsumerKey());
+ FSOAuthServiceConsumer fsConsumer = (FSOAuthServiceConsumer)
consumerStorageFile.getConsumer(consumer.getConsumerKey());
+ List<String> allowedUserIds = fsConsumer.getAllowedUserIds();
+ if (allowedUserIds == null) {
+ allowedUserIds = new ArrayList<String>();
+ }
+ allowedUserIds.add(userId);
+ consumerStorageFile.save();
+ }
+
+ public void withdrawResourceAccess(OAuthServiceConsumer consumer, String
userId) throws ConsumerRegistryStorageException {
+ FSConsumerStore consumerStorageFile =
getStorageFile(consumer.getConsumerKey());
+ FSOAuthServiceConsumer fsConsumer = (FSOAuthServiceConsumer)
consumerStorageFile.getConsumer(consumer.getConsumerKey());
+ List<String> allowedUserIds = fsConsumer.getAllowedUserIds();
+ if (allowedUserIds == null) {
+ allowedUserIds = new ArrayList<String>();
+ }
+ allowedUserIds.remove(userId);
+ consumerStorageFile.save();
+ }
+
+ public boolean hasResourceAccess(OAuthServiceConsumer consumer, String
userId) throws ConsumerRegistryStorageException {
+ FSOAuthServiceConsumer fsConsumer = (FSOAuthServiceConsumer)
getConsumer(consumer.getConsumerKey());
+ return fsConsumer.getAllowedUserIds().contains(userId);
+ }
private FSConsumerStore getStorageFile(final String entityId) throws
ConsumerRegistryStorageException {
final int hash = Math.abs(entityId.hashCode());
Modified:
trunk/amdatu-authentication/oauth-server/src/main/java/org/amdatu/authentication/oauth/server/osgi/Activator.java
==============================================================================
---
trunk/amdatu-authentication/oauth-server/src/main/java/org/amdatu/authentication/oauth/server/osgi/Activator.java
(original)
+++
trunk/amdatu-authentication/oauth-server/src/main/java/org/amdatu/authentication/oauth/server/osgi/Activator.java
Mon Dec 6 16:21:52 2010
@@ -21,7 +21,6 @@
import javax.servlet.Servlet;
-import org.amdatu.authentication.oauth.api.OAuthServiceConsumer;
import org.amdatu.authentication.oauth.api.OAuthServiceConsumerRegistry;
import org.amdatu.authentication.oauth.api.OAuthServiceProvider;
import org.amdatu.authentication.oauth.server.OAuthAccessTokenServlet;
@@ -59,7 +58,8 @@
.setInterface(OAuthTokenProvider.class.getName(), null)
.setImplementation(OAuthTokenProviderImpl.class)
.add(createServiceDependency().setService(LogService.class).setRequired(true))
-
.add(createServiceDependency().setService(OAuthServiceConsumer.class).setCallbacks("onAdded",
"onRemoved")));
+
.add(createServiceDependency().setService(OAuthServiceProvider.class).setRequired(true))
+
.add(createServiceDependency().setService(OAuthServiceConsumerRegistry.class).setRequired(true)));
// Create and register the resource provider
manager.add(
Modified:
trunk/amdatu-authentication/oauth-server/src/main/java/org/amdatu/authentication/oauth/server/service/OAuthTokenProviderImpl.java
==============================================================================
---
trunk/amdatu-authentication/oauth-server/src/main/java/org/amdatu/authentication/oauth/server/service/OAuthTokenProviderImpl.java
(original)
+++
trunk/amdatu-authentication/oauth-server/src/main/java/org/amdatu/authentication/oauth/server/service/OAuthTokenProviderImpl.java
Mon Dec 6 16:21:52 2010
@@ -18,10 +18,7 @@
import java.io.IOException;
import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
import java.util.HashSet;
-import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@@ -36,7 +33,10 @@
import net.oauth.SimpleOAuthValidator;
import net.oauth.server.OAuthServlet;
+import org.amdatu.authentication.oauth.api.ConsumerRegistryStorageException;
import org.amdatu.authentication.oauth.api.OAuthServiceConsumer;
+import org.amdatu.authentication.oauth.api.OAuthServiceConsumerRegistry;
+import org.amdatu.authentication.oauth.api.OAuthServiceProvider;
import org.amdatu.authentication.oauth.server.OAuthTokenProvider;
import org.apache.commons.codec.digest.DigestUtils;
import org.osgi.service.log.LogService;
@@ -44,52 +44,40 @@
public class OAuthTokenProviderImpl implements OAuthTokenProvider {
// Service dependencies injected by the dependency manager
private volatile LogService m_logService;
-
+ private volatile OAuthServiceProvider m_serviceProvider;
+ private volatile OAuthServiceConsumerRegistry m_consumerRegistry;
+
+ // The oAuth validator
public OAuthValidator m_oAuthValidator = new SimpleOAuthValidator();
- private Map<String, OAuthConsumer> m_oAuthConsumers =
- Collections.synchronizedMap(new HashMap<String, OAuthConsumer>(10));
-
+ // Distributed tokens
private Collection<OAuthAccessor> m_tokens = new HashSet<OAuthAccessor>();
public void start() {
m_logService.log(LogService.LOG_DEBUG, "OAuthTokenProvider service
started");
}
- public void onAdded(OAuthServiceConsumer oAuthService) {
- OAuthConsumer consumer = new OAuthConsumer(
- oAuthService.getCallbackUrl(),
- oAuthService.getConsumerKey(),
- oAuthService.getConsumerSecret(),
- null);
- consumer.setProperty("description", oAuthService.getName());
- m_oAuthConsumers.put(oAuthService.getConsumerKey(), consumer);
- m_logService.log(LogService.LOG_DEBUG, "New OAuthServiceConsumer
registered with key "
- + oAuthService.getConsumerKey());
- }
-
- public void onRemoved(OAuthServiceConsumer oAuthService) {
- m_oAuthConsumers.remove(oAuthService.getConsumerKey());
- m_logService.log(LogService.LOG_DEBUG, "OAuthServiceConsumer with key
" + oAuthService.getConsumerKey()
- + " was removed");
- }
-
public synchronized OAuthConsumer getConsumer(OAuthMessage requestMessage)
throws IOException,
OAuthProblemException {
- OAuthConsumer consumer = null;
-
- // try to load from local cache if not throw exception
- String consumer_key = requestMessage.getConsumerKey();
- consumer = m_oAuthConsumers.get(consumer_key);
- if (consumer == null) {
- OAuthProblemException problem = new
OAuthProblemException("token_rejected");
- throw problem;
+ try {
+ // try to load from local cache if not throw exception
+ String consumer_key = requestMessage.getConsumerKey();
+ if (consumer_key == null || "".equals(consumer_key)) {
+ throw new OAuthProblemException("token_rejected");
+ }
+ OAuthServiceConsumer serviceConsumer =
m_consumerRegistry.getConsumer(consumer_key);
+ if (serviceConsumer == null) {
+ throw new OAuthProblemException("token_rejected");
+ }
+ return copy(serviceConsumer);
+ }
+ catch (ConsumerRegistryStorageException e) {
+ throw new OAuthProblemException(e.toString());
}
- return consumer;
}
public OAuthValidator getOAuthValidator() {
- // TODO: We need to provide an external REST service to validate OAuth
messages and
+ // TODO: We need to provide an external REST service to validate OAuth
messages and
// retrieve context information like userid and consumer key
return m_oAuthValidator;
}
@@ -160,6 +148,19 @@
accessor.setProperty("user", userId);
accessor.setProperty("authorized", Boolean.TRUE);
+ // In the consumer registry we store that this end-user allowed this
consumer to access its
+ // procted resources on its behalf. Its up to the service provider to
do something with this
+ // information. Storage of this information facilitates the 2-leggged
oAuth scenario.
+ String consumerKey = accessor.consumer.consumerKey;
+ try {
+ OAuthServiceConsumer consumer =
m_consumerRegistry.getConsumer(consumerKey);
+ m_consumerRegistry.grantResourceAccess(consumer, userId);
+ }
+ catch (ConsumerRegistryStorageException e) {
+ m_logService.log(LogService.LOG_ERROR, "Could not find consumer
with key '" + consumerKey
+ + "', userid could not be persisted in the consumer registry
for 2-legged oAuth support.", e);
+ }
+
// update token in local cache
m_tokens.add(accessor);
}
@@ -189,8 +190,19 @@
public synchronized void handleException(Exception e, HttpServletRequest
request, HttpServletResponse response,
boolean sendBody) throws IOException, ServletException {
- String realm = (request.isSecure())?"https://":"http://";
+ String realm = (request.isSecure()) ? "https://" : "http://";
realm += request.getLocalName();
OAuthServlet.handleException(response, e, realm, sendBody);
}
+
+ private OAuthConsumer copy(OAuthServiceConsumer serviceConsumer) {
+ String callbackUrl = serviceConsumer.getCallbackUrl();
+ String key = serviceConsumer.getConsumerKey();
+ String secret = serviceConsumer.getConsumerSecret();
+ String request = m_serviceProvider.getRequestTokenURL();
+ String authorize = m_serviceProvider.getAuthorizeTokenURL();
+ String access = m_serviceProvider.getAccessTokenURL();
+ net.oauth.OAuthServiceProvider provider = new
net.oauth.OAuthServiceProvider(request, authorize, access);
+ return new OAuthConsumer(callbackUrl, key, secret, provider);
+ }
}
Modified:
trunk/amdatu-libraries/utilities/src/main/java/org/amdatu/libraries/utilities/FSUtil.java
==============================================================================
---
trunk/amdatu-libraries/utilities/src/main/java/org/amdatu/libraries/utilities/FSUtil.java
(original)
+++
trunk/amdatu-libraries/utilities/src/main/java/org/amdatu/libraries/utilities/FSUtil.java
Mon Dec 6 16:21:52 2010
@@ -21,7 +21,9 @@
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
/**
@@ -35,6 +37,15 @@
ois.readFully(keyBytes);
return new String(keyBytes, "utf-8");
}
+
+ public static List<String> readList(final ObjectInputStream ois) throws
IOException {
+ final int listLength = ois.readInt();
+ List<String> list = new ArrayList<String>(listLength);
+ for (int i=0; i<listLength; i++) {
+ list.add(readString(ois));
+ }
+ return list;
+ }
public static Map<String, String> readProperties(final ObjectInputStream
ois) throws IOException {
final int numberOfProperties = ois.readInt();
@@ -59,6 +70,13 @@
oos.writeInt(bytes.length);
oos.write(bytes);
}
+
+ public static void writeList(final ObjectOutputStream oos, final
List<String> values) throws IOException {
+ oos.writeInt(values.size());
+ for (String value : values) {
+ writeString(oos, value);
+ }
+ }
public static void writeProperties(final ObjectOutputStream oos, final
Map<String, String> properties)
throws IOException {
Modified:
trunk/integration-tests/src/test/java/org/amdatu/test/integration/base/OAuthTestBase.java
==============================================================================
---
trunk/integration-tests/src/test/java/org/amdatu/test/integration/base/OAuthTestBase.java
(original)
+++
trunk/integration-tests/src/test/java/org/amdatu/test/integration/base/OAuthTestBase.java
Mon Dec 6 16:21:52 2010
@@ -25,11 +25,6 @@
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.OAuthServiceConsumerRegistry;
import org.amdatu.authentication.oauth.api.OAuthServiceProvider;
@@ -40,7 +35,6 @@
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;
@@ -48,11 +42,14 @@
import org.osgi.service.log.LogService;
public class OAuthTestBase extends IntegrationTestBase {
+ protected final String TEST_USERID = "ivol";
+
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;
+ protected volatile OAuthServiceConsumerRegistry m_consumerRegistry;
@Configuration
public Option[] configure() {
@@ -80,6 +77,7 @@
.setImplementation(m_testServlet)
.setInterface(new String[] { Servlet.class.getName() },
servletProperties)
.add(manager.createServiceDependency().setService(LogService.class).setRequired(true))
+
.add(manager.createServiceDependency().setService(OAuthServiceConsumerRegistry.class).setRequired(true))
.add(manager.createServiceDependency().setService(OAuthTokenProvider.class).setRequired(true));
Component testComponent = manager.createComponent()
@@ -127,42 +125,4 @@
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
Mon Dec 6 16:21:52 2010
@@ -40,6 +40,8 @@
import net.oauth.OAuthProblemException;
import net.oauth.server.OAuthServlet;
+import org.amdatu.authentication.oauth.api.ConsumerRegistryStorageException;
+import org.amdatu.authentication.oauth.api.OAuthServiceConsumerRegistry;
import org.amdatu.authentication.oauth.server.OAuthTokenProvider;
import org.osgi.service.log.LogService;
@@ -48,9 +50,15 @@
private static final long serialVersionUID = 8834974378869705614L;
public static final String SERVLET_ALIAS = "/test/oauth/protectedresource";
-
+ public static final String OAUTH_TYPE_PARAM = "oauthtype";
+ public static final String OAUTH_TYPE_SIGNED_REQUEST = "signedrequest";
+ public static final String OAUTH_TYPE_TWO_LEGGED = "2legged";
+ public static final String OAUTH_TYPE_THREE_LEGGED = "3legged";
+
+
private volatile LogService m_logService;
private volatile OAuthTokenProvider m_tokenProvider;
+ private volatile OAuthServiceConsumerRegistry m_consumerRegistry;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
@@ -62,16 +70,18 @@
processRequest("POST", request, response);
}
- 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");
-
+ public void processRequest(String method, HttpServletRequest request,
HttpServletResponse response) throws IOException, ServletException {
try {
+ // Get the oAuth scenario type
+ String oAuthType = request.getParameter(OAUTH_TYPE_PARAM);
+ m_logService.log(LogService.LOG_DEBUG, "Protected resource test
servlet received incoming request, oAuth type=" + oAuthType);
+
// Validate oAuth message and get userId from it
String body = "";
- String userId = validateOAuth(request);
- if (userId == null) {
+ OAuthAccessor accessor = validateOAuth(request);
+ String consumerKey = accessor.consumer.consumerKey;
+ String userId = (String) accessor.getProperty("user");
+ if (oAuthType.equals(OAUTH_TYPE_SIGNED_REQUEST)) {
// 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:";
@@ -93,7 +103,15 @@
body += "\ncontent=" + toString(request.getInputStream());
}
}
- else {
+ else if (oAuthType.equals(OAUTH_TYPE_TWO_LEGGED)) {
+ // Validate if the userid did allow access to access this
protected resource before
+ if
(m_consumerRegistry.hasResourceAccess(m_consumerRegistry.getConsumer(consumerKey),
userId)) {
+ body = "userid=" + userId;
+ } else {
+ body = "access denied";
+ }
+ }
+ else if (oAuthType.equals(OAUTH_TYPE_THREE_LEGGED)) {
body = "userid=" + userId;
}
response.setContentType("text/plain");
@@ -115,9 +133,12 @@
catch (URISyntaxException e) {
throw new ServletException(e);
}
+ catch (ConsumerRegistryStorageException e) {
+ throw new ServletException(e);
+ }
}
- private String validateOAuth(HttpServletRequest request) throws
IOException, OAuthException, URISyntaxException {
+ private OAuthAccessor 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
@@ -133,7 +154,7 @@
accessor = m_tokenProvider.getAccessor(requestMessage);
}
m_tokenProvider.getOAuthValidator().validateMessage(requestMessage,
accessor);
- return (String) accessor.getProperty("user");
+ return accessor;
}
private String toString(InputStream is) throws IOException {
Modified:
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/OAuthSignedRequestsTest.java
==============================================================================
---
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/OAuthSignedRequestsTest.java
(original)
+++
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/OAuthSignedRequestsTest.java
Mon Dec 6 16:21:52 2010
@@ -16,6 +16,10 @@
*/
package org.amdatu.test.integration.tests;
+import static
org.amdatu.test.integration.mock.OAuthProtectedTestServlet.OAUTH_TYPE_PARAM;
+import static
org.amdatu.test.integration.mock.OAuthProtectedTestServlet.OAUTH_TYPE_SIGNED_REQUEST;
+import static
org.amdatu.test.integration.mock.OAuthProtectedTestServlet.SERVLET_ALIAS;
+
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.Hashtable;
@@ -26,7 +30,7 @@
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.amdatu.test.integration.mock.OAuthTestConsumer;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -47,7 +51,8 @@
// Step 1: Register a service consumer
m_logService.log(LogService.LOG_DEBUG, "*** Step 1: Register service
consumer ***");
- OAuthServiceConsumer consumer = registerTestServiceConsumer();
+ OAuthServiceConsumer consumer = new OAuthTestConsumer();
+ m_consumerRegistry.addConsumer(consumer);
// Step 2: Create an OAuthClient for our Amdatu OAuth server
m_logService.log(LogService.LOG_DEBUG, "*** Step 2: Create OAuth
Client ***");
@@ -55,7 +60,8 @@
// 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;
+ String url = "http://" + ConfigProvider.HOSTNAME + ":" +
ConfigProvider.PORTNR + SERVLET_ALIAS;
+ url += "?" + OAUTH_TYPE_PARAM + "=" + OAUTH_TYPE_SIGNED_REQUEST;
OAuthMessage message = consumerClient.invokeSignedRequest("GET", url,
null);
String body = message.readBodyAsString();
m_logService.log(LogService.LOG_DEBUG, "Protected resource returns
response: '" + body + "'");
@@ -86,5 +92,8 @@
body = message.readBodyAsString();
m_logService.log(LogService.LOG_DEBUG, "Protected resource returns
POST response: '" + body + "'");
Assert.assertTrue(body.indexOf("content=" + testSentence) != -1);
+
+ // Step 4: Remove the consumer
+ m_consumerRegistry.removeConsumer(consumer);
}
}
Modified:
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/OAuthThreeLeggedTest.java
==============================================================================
---
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/OAuthThreeLeggedTest.java
(original)
+++
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/OAuthThreeLeggedTest.java
Mon Dec 6 16:21:52 2010
@@ -16,6 +16,8 @@
*/
package org.amdatu.test.integration.tests;
+import static
org.amdatu.test.integration.mock.OAuthProtectedTestServlet.OAUTH_TYPE_PARAM;
+import static
org.amdatu.test.integration.mock.OAuthProtectedTestServlet.OAUTH_TYPE_THREE_LEGGED;
import net.oauth.OAuthAccessor;
import net.oauth.OAuthMessage;
@@ -46,7 +48,8 @@
// Step 1: Register a service consumer
m_logService.log(LogService.LOG_DEBUG, "*** Step 1: Register service
consumer ***");
- OAuthServiceConsumer consumer = registerTestServiceConsumer();
+ OAuthServiceConsumer consumer = new OAuthTestConsumer();
+ m_consumerRegistry.addConsumer(consumer);
// Step 2: Create an OAuthClient for our Amdatu OAuth server
m_logService.log(LogService.LOG_DEBUG, "*** Step 2: Create OAuth
Clients ***");
@@ -59,7 +62,7 @@
// Step 4: Authorize the request token for a user we define
m_logService.log(LogService.LOG_DEBUG, "*** Step 4: Authorize the
request token ***");
- String callback = userClient.authorizeToken(accessor, "ivol");
+ String callback = userClient.authorizeToken(accessor, TEST_USERID);
Assert.assertTrue(callback.startsWith(OAuthTestConsumer.DEFAULT_CALLBACK_URL +
"?oauth_token="));
m_logService.log(LogService.LOG_DEBUG, "Callback URL received: " +
callback);
@@ -76,10 +79,14 @@
m_logService.log(LogService.LOG_DEBUG, "*** Step 6: Access protected
resource ***");
String url =
"http://" + ConfigProvider.HOSTNAME + ":" + ConfigProvider.PORTNR
+ OAuthProtectedTestServlet.SERVLET_ALIAS;
+ url += "?" + OAUTH_TYPE_PARAM + "=" + OAUTH_TYPE_THREE_LEGGED;
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"));
+ Assert.assertTrue(body.equals("userid=" + TEST_USERID));
+
+ // Step 7: Remove the consumer
+ m_consumerRegistry.removeConsumer(consumer);
}
// Step 3: Generate a request token for our service consumer
Added:
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/OAuthTwoLeggedTest.java
==============================================================================
--- (empty file)
+++
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/OAuthTwoLeggedTest.java
Mon Dec 6 16:21:52 2010
@@ -0,0 +1,108 @@
+/*
+ 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 static
org.amdatu.test.integration.mock.OAuthProtectedTestServlet.OAUTH_TYPE_PARAM;
+import static
org.amdatu.test.integration.mock.OAuthProtectedTestServlet.OAUTH_TYPE_TWO_LEGGED;
+import static
org.amdatu.test.integration.mock.OAuthProtectedTestServlet.SERVLET_ALIAS;
+import net.oauth.OAuthAccessor;
+import net.oauth.OAuthMessage;
+
+import org.amdatu.authentication.oauth.api.OAuthServiceConsumer;
+import org.amdatu.authentication.oauth.client.OAuthResourceOwnerClient;
+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.OAuthTestConsumer;
+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;
+
+ at RunWith(JUnit4TestRunner.class)
+public class OAuthTwoLeggedTest extends OAuthTestBase {
+ @Test
+ 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 1a: Register service
consumer ***");
+ OAuthServiceConsumer consumer = new OAuthTestConsumer();
+ m_consumerRegistry.addConsumer(consumer);
+
+ // Step 2: validate that the user id has not yet been added to the
consumer registry
+ Assert.assertFalse(
+ "Userid '" + TEST_USERID + "' already added to allowed userids in
the service consumer registry",
+ m_consumerRegistry.hasResourceAccess(consumer, TEST_USERID));
+
+ // Step 3: perform a 3-legged oAuth dance for user 'ivol'
+ // Step 3a: Create an OAuthClient for our Amdatu OAuth server
+ m_logService.log(LogService.LOG_DEBUG, "*** Step 3a: Create OAuth
Clients ***");
+ OAuthServiceConsumerClient consumerClient = new
OAuthServiceConsumerClient(m_oAuthServiceProvider, consumer);
+ OAuthResourceOwnerClient userClient = new
OAuthResourceOwnerClient(m_oAuthServiceProvider, consumer);
+
+ // Step 3b: Generate a request token for our service consumer
+ m_logService.log(LogService.LOG_DEBUG, "*** Step 3b: Generate request
token ***");
+ OAuthAccessor accessor = createRequestToken(consumerClient);
+
+ // Step 3c: Authorize the request token for a user we define
+ m_logService.log(LogService.LOG_DEBUG, "*** Step 3c: Authorize the
request token ***");
+ userClient.authorizeToken(accessor, TEST_USERID);
+
+ // Step 3d: Exchange our request token for an access token
+ m_logService.log(LogService.LOG_DEBUG, "*** Step 3d: Get access token
***");
+ OAuthMessage message = consumerClient.getAccessToken(accessor);
+ accessor.accessToken = message.getToken();
+ accessor.tokenSecret = message.getParameter("oauth_token_secret");
+ accessor.requestToken = null;
+
+ // Step 4: validate if the user id has been added to the consumer
registry
+ Assert.assertTrue(
+ "Userid '" + TEST_USERID + "', not added to allowed userids in the
service consumer registry",
+ m_consumerRegistry.hasResourceAccess(consumer, TEST_USERID));
+
+ // Step 5: Now access a 2-legged protected resource
+ String url = "http://" + ConfigProvider.HOSTNAME + ":" +
ConfigProvider.PORTNR + SERVLET_ALIAS;
+ url += "?" + OAUTH_TYPE_PARAM + "=" + OAUTH_TYPE_TWO_LEGGED;
+ 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=" + TEST_USERID));
+
+ // Step 7: Withdraw the access, then try to access the protected
resource again
+ m_consumerRegistry.withdrawResourceAccess(consumer, TEST_USERID);
+ message = consumerClient.accessResource(accessor, url, "GET");
+ body = message.readBodyAsString();
+ m_logService.log(LogService.LOG_DEBUG, "Protected resource returns
response: '" + body + "'");
+ Assert.assertTrue(body.equals("access denied"));
+
+ // Step 8: Remove the consumer
+ m_consumerRegistry.removeConsumer(consumer);
+ }
+
+ // Step 1c: Generate a request token for our service consumer
+ private OAuthAccessor createRequestToken(OAuthServiceConsumerClient
client) throws Exception {
+ OAuthAccessor accessor = client.generateRequestToken();
+ String requestToken = accessor.requestToken;
+ String tokenSecret = accessor.tokenSecret;
+ m_logService.log(LogService.LOG_DEBUG, "Request token received: " +
requestToken + ", token secret="
+ + tokenSecret);
+ return accessor;
+ }
+}