Author: ivol37 at gmail.com
Date: Wed Dec 15 12:19:44 2010
New Revision: 495
Log:
[AMDATU-165] Added a token provider bundle that is now responsible for
generating and validating tokens used by oAuth and site authentication. The use
of the BasicHttpSession is now replaced by this token. Information like IP
address and username can be stored in this token facilitating authorization
checks.
Added:
trunk/amdatu-authentication/tokenprovider/
trunk/amdatu-authentication/tokenprovider/src/
trunk/amdatu-authentication/tokenprovider/src/main/
trunk/amdatu-authentication/tokenprovider/src/main/java/
trunk/amdatu-authentication/tokenprovider/src/main/java/org/
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/InvalidTokenException.java
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/TokenProvider.java
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/TokenProviderException.java
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/TokenRESTResource.java
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/TokenStorageProvider.java
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/osgi/
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/osgi/Activator.java
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/service/
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/service/TokenProviderImpl.java
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/service/TokenRESTResourceImpl.java
trunk/amdatu-authentication/tokenstore-mem/
trunk/amdatu-authentication/tokenstore-mem/pom.xml
trunk/amdatu-authentication/tokenstore-mem/src/
trunk/amdatu-authentication/tokenstore-mem/src/main/
trunk/amdatu-authentication/tokenstore-mem/src/main/java/
trunk/amdatu-authentication/tokenstore-mem/src/main/java/org/
trunk/amdatu-authentication/tokenstore-mem/src/main/java/org/amdatu/
trunk/amdatu-authentication/tokenstore-mem/src/main/java/org/amdatu/authentication/
trunk/amdatu-authentication/tokenstore-mem/src/main/java/org/amdatu/authentication/tokenstore/
trunk/amdatu-authentication/tokenstore-mem/src/main/java/org/amdatu/authentication/tokenstore/mem/
trunk/amdatu-authentication/tokenstore-mem/src/main/java/org/amdatu/authentication/tokenstore/mem/osgi/
trunk/amdatu-authentication/tokenstore-mem/src/main/java/org/amdatu/authentication/tokenstore/mem/osgi/Activator.java
trunk/amdatu-authentication/tokenstore-mem/src/main/java/org/amdatu/authentication/tokenstore/mem/service/
trunk/amdatu-authentication/tokenstore-mem/src/main/java/org/amdatu/authentication/tokenstore/mem/service/InMemTokenStorageProviderImpl.java
Removed:
trunk/amdatu-web/httpcontext/src/main/java/org/amdatu/web/httpcontext/BasicHttpSession.java
Modified:
trunk/amdatu-authentication/oauth-server/pom.xml
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/OAuthAuthorizeTokenServletImpl.java
trunk/amdatu-authentication/oauth-server/src/main/java/org/amdatu/authentication/oauth/server/service/OAuthTokenProviderImpl.java
trunk/amdatu-authentication/pom.xml
trunk/amdatu-authorization/login-service/pom.xml
trunk/amdatu-authorization/login-service/src/main/java/org/amdatu/authorization/login/service/osgi/Activator.java
trunk/amdatu-authorization/login-service/src/main/java/org/amdatu/authorization/login/service/service/LoginServiceImpl.java
trunk/amdatu-opensocial/gadgetmanagement/pom.xml
trunk/amdatu-opensocial/gadgetmanagement/src/main/java/org/amdatu/opensocial/gadgetmanagement/osgi/Activator.java
trunk/amdatu-opensocial/gadgetmanagement/src/main/java/org/amdatu/opensocial/gadgetmanagement/service/GadgetManagementServiceImpl.java
trunk/amdatu-opensocial/profile/src/main/java/org/amdatu/opensocial/profile/service/PersonServiceImpl.java
trunk/amdatu-release/pom.xml
trunk/amdatu-web/rest-jaxrs/pom.xml
trunk/integration-tests/pom.xml
trunk/integration-tests/src/test/java/org/amdatu/test/integration/base/IntegrationTestBase.java
trunk/integration-tests/src/test/java/org/amdatu/test/integration/base/OAuthTestBase.java
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/GadgetManagementServiceTest.java
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/OAuthThreeLeggedTest.java
trunk/pom.xml
trunk/src/main/resources/conf/felix-config.properties
Modified: trunk/amdatu-authentication/oauth-server/pom.xml
==============================================================================
--- trunk/amdatu-authentication/oauth-server/pom.xml (original)
+++ trunk/amdatu-authentication/oauth-server/pom.xml Wed Dec 15 12:19:44 2010
@@ -72,6 +72,12 @@
<version>${platform.version}</version>
<scope>compile</scope>
</dependency>
+ <dependency>
+ <groupId>org.amdatu.authentication</groupId>
+ <artifactId>tokenprovider</artifactId>
+ <version>${platform.version}</version>
+ <scope>provided</scope>
+ </dependency>
</dependencies>
<build>
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
Wed Dec 15 12:19:44 2010
@@ -35,6 +35,7 @@
import
org.amdatu.authentication.oauth.server.service.OAuthServiceConsumerRegistryREST;
import org.amdatu.authentication.oauth.server.service.OAuthServiceProviderImpl;
import org.amdatu.authentication.oauth.server.service.OAuthTokenProviderImpl;
+import org.amdatu.authentication.tokenprovider.TokenProvider;
import org.amdatu.web.httpcontext.HttpContextServiceFactory;
import org.amdatu.web.httpcontext.ResourceProvider;
import org.apache.felix.dm.Component;
@@ -59,6 +60,7 @@
.setImplementation(OAuthTokenProviderImpl.class)
.add(createServiceDependency().setService(LogService.class).setRequired(true))
.add(createServiceDependency().setService(OAuthServiceProvider.class).setRequired(true))
+
.add(createServiceDependency().setService(TokenProvider.class).setRequired(true))
.add(createServiceDependency().setService(OAuthServiceConsumerRegistry.class).setRequired(true)));
// Create and register the resource provider
@@ -83,6 +85,8 @@
.setImplementation(OAuthServiceConsumerRegistryREST.class)
.add(createServiceDependency().setService(LogService.class).setRequired(true))
.add(createServiceDependency().setService(OAuthServiceConsumerRegistry.class).setRequired(true)));
+
+
// Create and register the OAuth servlet components.
manager.add(createComponent(OAuthRequestTokenServlet.SERVLET_ALIAS,
OAuthRequestTokenServlet.class, OAuthRequestTokenServletImpl.class));
@@ -99,6 +103,7 @@
.setImplementation(servletClass)
.add(createServiceDependency().setService(OAuthTokenProvider.class).setRequired(true))
.add(createServiceDependency().setService(OAuthServiceProvider.class).setRequired(true))
+
.add(createServiceDependency().setService(TokenProvider.class).setRequired(true))
.add(createServiceDependency().setService(LogService.class).setRequired(true));
}
Modified:
trunk/amdatu-authentication/oauth-server/src/main/java/org/amdatu/authentication/oauth/server/service/OAuthAuthorizeTokenServletImpl.java
==============================================================================
---
trunk/amdatu-authentication/oauth-server/src/main/java/org/amdatu/authentication/oauth/server/service/OAuthAuthorizeTokenServletImpl.java
(original)
+++
trunk/amdatu-authentication/oauth-server/src/main/java/org/amdatu/authentication/oauth/server/service/OAuthAuthorizeTokenServletImpl.java
Wed Dec 15 12:19:44 2010
@@ -18,9 +18,11 @@
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.Map;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
+import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
@@ -35,9 +37,10 @@
import org.amdatu.authentication.oauth.api.OAuthServiceProvider;
import org.amdatu.authentication.oauth.server.OAuthAuthorizeTokenServlet;
import org.amdatu.authentication.oauth.server.OAuthTokenProvider;
-import org.amdatu.web.httpcontext.BasicHttpSession;
+import org.amdatu.authentication.tokenprovider.InvalidTokenException;
+import org.amdatu.authentication.tokenprovider.TokenProvider;
+import org.amdatu.authentication.tokenprovider.TokenProviderException;
import org.osgi.service.log.LogService;
-import org.osgi.service.useradmin.Authorization;
public class OAuthAuthorizeTokenServletImpl extends HttpServlet implements
OAuthAuthorizeTokenServlet {
// The serial version UID of this servlet
@@ -45,7 +48,8 @@
// Service dependencies, injected by the Felix dependency manager
private volatile LogService m_logService;
- private volatile OAuthTokenProvider m_tokenProvider;
+ private volatile TokenProvider m_tokenProvider;
+ private volatile OAuthTokenProvider m_oAuthTokenProvider;
private volatile OAuthServiceProvider m_serviceProvider;
public void init(ServletConfig config) throws ServletException {
@@ -55,7 +59,7 @@
public void doGet(HttpServletRequest request, HttpServletResponse
response) throws IOException, ServletException {
try {
OAuthMessage requestMessage = OAuthServlet.getMessage(request,
null);
- OAuthAccessor accessor =
m_tokenProvider.getAccessor(requestMessage);
+ OAuthAccessor accessor =
m_oAuthTokenProvider.getAccessor(requestMessage);
if (Boolean.TRUE.equals(accessor.getProperty("authorized"))) {
// already authorized send the user back
m_logService.log(LogService.LOG_DEBUG, "Token authorized,
redirecting user to callback url");
@@ -67,7 +71,7 @@
}
}
catch (Exception e) {
- m_tokenProvider.handleException(e, request, response, true);
+ m_oAuthTokenProvider.handleException(e, request, response, true);
}
}
@@ -75,7 +79,7 @@
public void doPost(HttpServletRequest request, HttpServletResponse
response) throws IOException, ServletException {
try {
OAuthMessage requestMessage = OAuthServlet.getMessage(request,
null);
- OAuthAccessor accessor =
m_tokenProvider.getAccessor(requestMessage);
+ OAuthAccessor accessor =
m_oAuthTokenProvider.getAccessor(requestMessage);
String userId = getUserId(request);
if (userId == null) {
// If there is no userid available now, we throw a permission
denied as it won't happen in a normal situation!
@@ -84,11 +88,11 @@
throw problem;
}
// set userId in accessor and mark it as authorized
- m_tokenProvider.markAsAuthorized(accessor, userId);
+ m_oAuthTokenProvider.markAsAuthorized(accessor, userId);
returnToConsumer(request, response, accessor);
}
catch (Exception e) {
- m_tokenProvider.handleException(e, request, response, true);
+ m_oAuthTokenProvider.handleException(e, request, response, true);
}
}
@@ -152,14 +156,14 @@
}
}
- private String getUserId(HttpServletRequest request) {
- BasicHttpSession session = BasicHttpSession.getSession(request);
- if (session != null) {
- Authorization auth = (Authorization)
session.getValue("authorization");
- if (auth != null) {
- return auth.getName();
- }
+ private String getUserId(HttpServletRequest request) throws
TokenProviderException, InvalidTokenException {
+ // Get the token, retrieve attributes stored in it and get the
USERNAME from it
+ String token = m_tokenProvider.getTokenFromRequest(request);
+ if (token != null) {
+ Map<String, String> attributes =
m_tokenProvider.verifyToken(token);
+ return attributes.get(TokenProvider.USERNAME);
+ } else {
+ return null;
}
- return null;
}
}
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
Wed Dec 15 12:19:44 2010
@@ -19,6 +19,8 @@
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
+import java.util.SortedMap;
+import java.util.TreeMap;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@@ -38,7 +40,8 @@
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.amdatu.authentication.tokenprovider.TokenProvider;
+import org.amdatu.authentication.tokenprovider.TokenProviderException;
import org.osgi.service.log.LogService;
public class OAuthTokenProviderImpl implements OAuthTokenProvider {
@@ -46,11 +49,12 @@
private volatile LogService m_logService;
private volatile OAuthServiceProvider m_serviceProvider;
private volatile OAuthServiceConsumerRegistry m_consumerRegistry;
-
+ private volatile TokenProvider m_tokenProvider;
+
// The oAuth validator
public OAuthValidator m_oAuthValidator = new SimpleOAuthValidator();
- // Distributed tokens
+ // Distributed oAuth tokens
private Collection<OAuthAccessor> m_tokens = new HashSet<OAuthAccessor>();
public void start() {
@@ -58,7 +62,7 @@
}
public synchronized OAuthConsumer getConsumer(OAuthMessage requestMessage)
throws IOException,
- OAuthProblemException {
+ OAuthProblemException {
try {
// try to load from local cache if not throw exception
String consumer_key = requestMessage.getConsumerKey();
@@ -88,33 +92,39 @@
* @throws OAuthException
*/
public synchronized void generateRequestToken(OAuthAccessor accessor)
throws OAuthException {
- // generate oauth_token and oauth_secret
- String consumer_key = (String) accessor.consumer.getProperty("name");
- // generate token and secret based on consumer_key
-
- // for now use md5 of name + current time as token
- String token_data = consumer_key + System.nanoTime();
- String token = DigestUtils.md5Hex(token_data);
- // for now use md5 of name + current time + token as secret
- String secret_data = consumer_key + System.nanoTime() + token;
- String secret = DigestUtils.md5Hex(secret_data);
-
- accessor.requestToken = token;
- accessor.tokenSecret = secret;
- accessor.accessToken = null;
+ try {
+ // Generate oauth_token and oauth_secret
+ String consumer_key = (String)
accessor.consumer.getProperty("name");
+ SortedMap<String, String> tokenAttributes = new TreeMap<String,
String>();
+ tokenAttributes.put("consumer_key", consumer_key);
+ String requestToken =
m_tokenProvider.generateToken(tokenAttributes);
+
+ SortedMap<String, String> tokenSecretAttributes = new
TreeMap<String, String>();
+ tokenSecretAttributes.put("token", requestToken);
+ String tokenSecret =
m_tokenProvider.generateToken(tokenSecretAttributes);
+
+ // Set the token and secret in the accessor
+ accessor.requestToken = requestToken;
+ accessor.tokenSecret = tokenSecret;
+ accessor.accessToken = null;
- // add to the local cache
- m_tokens.add(accessor);
+ // add to the local cache
+ m_tokens.add(accessor);
+ }
+ catch (TokenProviderException e) {
+ throw new OAuthException(e);
+ }
}
/**
* Get the access token and token secret for the given oauth_token.
*/
public synchronized OAuthAccessor getAccessor(OAuthMessage requestMessage)
throws IOException,
- OAuthProblemException {
+ OAuthProblemException {
// try to load from local cache if not throw exception
String consumer_token = requestMessage.getToken();
OAuthAccessor accessor = null;
+
for (OAuthAccessor a : m_tokens) {
if (a.requestToken != null) {
if (a.requestToken.equals(consumer_token)) {
@@ -171,21 +181,25 @@
* @throws OAuthException
*/
public synchronized void generateAccessToken(OAuthAccessor accessor)
throws OAuthException {
- // generate oauth_token and oauth_secret
- String consumer_key = (String) accessor.consumer.getProperty("name");
- // generate token and secret based on consumer_key
-
- // for now use md5 of name + current time as token
- String token_data = consumer_key + System.nanoTime();
- String token = DigestUtils.md5Hex(token_data);
- // first remove the accessor from cache
- m_tokens.remove(accessor);
-
- accessor.requestToken = null;
- accessor.accessToken = token;
-
- // update token in local cache
- m_tokens.add(accessor);
+ try {
+ // Generate oauth_token and oauth_secret
+ String consumer_key = (String)
accessor.consumer.getProperty("name");
+ SortedMap<String, String> oaAuthAttributes = new TreeMap<String,
String>();
+ oaAuthAttributes.put("consumer_key", consumer_key);
+ String accessToken =
m_tokenProvider.generateToken(oaAuthAttributes);
+
+ // first remove the accessor from cache
+ m_tokens.remove(accessor);
+
+ accessor.requestToken = null;
+ accessor.accessToken = accessToken;
+
+ // update token in local cache
+ m_tokens.add(accessor);
+ }
+ catch (TokenProviderException e) {
+ throw new OAuthException(e);
+ }
}
public synchronized void handleException(Exception e, HttpServletRequest
request, HttpServletResponse response,
Modified: trunk/amdatu-authentication/pom.xml
==============================================================================
--- trunk/amdatu-authentication/pom.xml (original)
+++ trunk/amdatu-authentication/pom.xml Wed Dec 15 12:19:44 2010
@@ -26,6 +26,8 @@
<module>oauth-client</module>
<module>oauth-server</module>
<module>oauth-consumerregistry-fs</module>
+ <module>tokenprovider</module>
+ <module>tokenstore-mem</module>
</modules>
</project>
\ No newline at end of file
Added:
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/InvalidTokenException.java
==============================================================================
--- (empty file)
+++
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/InvalidTokenException.java
Wed Dec 15 12:19:44 2010
@@ -0,0 +1,36 @@
+/*
+ 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.tokenprovider;
+
+/**
+ * This exception is thrown when a token provided is invalid.
+ *
+ * @author ivol
+ */
+public class InvalidTokenException extends Exception {
+ // The serial version UID of this exception class
+ private static final long serialVersionUID = 783720889456143935L;
+
+ /**
+ * Constructs a new token provider exception.
+ *
+ * @param msg An error message providing more information about the cause
of the error.
+ */
+ public InvalidTokenException(String msg) {
+ super(msg);
+ }
+}
Added:
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/TokenProvider.java
==============================================================================
--- (empty file)
+++
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/TokenProvider.java
Wed Dec 15 12:19:44 2010
@@ -0,0 +1,109 @@
+/*
+ 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.tokenprovider;
+
+import java.util.SortedMap;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * This service facilitates generating tokens. A token is an encrypted set of
attributes and a
+ * signature. The signature is generated from these attributes and a private
key, only known to
+ * this token provider.
+ * The common use case of creating and validating a token is as follows:
+ * -1- First determine a set of attributes that the token must contain. This
may include things like
+ * a username, IP address, a timestamp, a nonce or a consumer key (for oAuth
tokens).
+ * -2- From this set of attributes a signature is created, using the
generateSignature method. The signature
+ * is creating by applying a hash algorithm onto the set of attributes plus a
private key, only known by this
+ * token provider.
+ * -3- An unencrypted token is generated by converting the set of attributes
to a single string and append it
+ * to the signature of the attributes. An unencrypted token may for example be:
+ * 'cebca7fb93e4c5316a6e91b3d7af470b username=Administrator ip=127.0.0.1'
+ * -4- The token is encrypted using the AES encryption method, using the
private key. This token is returned
+ * by the generateToken method
+ * -5- The encrypted token is added to the token store
+ * -6- When a client wants to verify if a certain token is valid, it passes
this encrypted token to this provider.
+ * The provider first verifies that this token is available in the token
store. Then it decrypts the token,
+ * verifies that the signature is correct and then resolves the attributes
stored in the token. It returns
+ * those attributes.
+ * -7- A token can be invalidated by removing it from the token store.
+ *
+ * @author ivol
+ */
+public interface TokenProvider {
+ /**
+ * Name of the cookie that stores an amdatu token.
+ */
+ final String TOKEN_COOKIE_NAME = "amdatu_token";
+
+ /**
+ * Name under which the nonce parameter is stored.
+ */
+ final String NONCE = "token_nonce";
+
+ /**
+ * Name under which the timestamp parameter is stored.
+ */
+ final String TIMESTAMP = "token_timestamp";
+
+ /**
+ * Name under which a username parameter can be stored (this is optional).
+ */
+ final String USERNAME = "token_username";
+
+ /**
+ * Generates a new token for the specified set of token attributes. First
of all a signature is created
+ * from the set of attributes using a private key, only known by this
token provider. The atributes are
+ * converted to a single String and together with the signature this forms
the unencrypted token.
+ * Finally, the token is encrypted using aAES encryption method, again
using a private key only known
+ * by this token provider. This encrypted token is returned.
+ * Note that to this list of attributes always a nonce and a timestamp are
added. Therefore attributes
+ * with names NONCE or TIMESTAMP are preserved and should not be used. A
TokenProviderException is thrown
+ * in case the map of attributes already contains these attributes.
+ *
+ * @param attributes The attributes to create the token for. May be empty
or null, in which case the
+ * token is generated from only a nonce and a timestamp.
+ * @return The generated encrypted token
+ * @throws TokenProviderException In case an unexpected error aoccurred
during token generation.
+ */
+ String generateToken(SortedMap<String, String> attributes) throws
TokenProviderException;
+
+ /**
+ * Verifies if the token is valid. If the token is valid, a map of
attributes is returned which
+ * are included in the token. This is the same list as provided when the
token was generated, but
+ * with additional nonce and timestamp attributes. If the token is
invalid, a InvalidTokenException
+ * is thrown.
+ * @param encryptedToken The encrypted token to verify
+ * @return List of original attributes, plus nonce and timestamp
attributes.
+ * @throws TokenProviderException In case an unexpected error aoccurred
during token generation.
+ * @throws InvalidTokenException In case the provided token is invalid
+ */
+ SortedMap<String, String> verifyToken(String encryptedToken) throws
TokenProviderException, InvalidTokenException;
+
+ /**
+ * Invalidates the specified token. A token that has been invalidated
cannot be used anymore.
+ * @param encryptedToken the token to invalidate.
+ */
+ void invalidateToken(String encryptedToken);
+
+ /**
+ * Returns the request token associated with the specified request or null
of none is associated.
+ * @param request The request to get the token from
+ * @return the request token associated with the specified request
+ */
+ String getTokenFromRequest(HttpServletRequest request);
+}
Added:
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/TokenProviderException.java
==============================================================================
--- (empty file)
+++
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/TokenProviderException.java
Wed Dec 15 12:19:44 2010
@@ -0,0 +1,45 @@
+/*
+ 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.tokenprovider;
+
+/**
+ * Exception indicating an internal error that occurred during generating or
verifying tokens.
+ *
+ * @author ivol
+ */
+public class TokenProviderException extends Exception {
+ // The serial version UID of this exception class
+ private static final long serialVersionUID = 1008471221110336338L;
+
+ /**
+ * Constructs a new token provider exception.
+ *
+ * @param msg An error message providing more information about the cause
of the error.
+ */
+ public TokenProviderException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs a new token provider exception.
+ *
+ * @param t An exception providing more information about the cause of the
error.
+ */
+ public TokenProviderException(Throwable t) {
+ super(t);
+ }
+}
Added:
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/TokenRESTResource.java
==============================================================================
--- (empty file)
+++
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/TokenRESTResource.java
Wed Dec 15 12:19:44 2010
@@ -0,0 +1,25 @@
+/*
+ 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.tokenprovider;
+
+/**
+ * REST interface for token management (generating and verifying tokens).
+ *
+ * @author ivol
+ */
+public interface TokenRESTResource {
+}
Added:
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/TokenStorageProvider.java
==============================================================================
--- (empty file)
+++
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/TokenStorageProvider.java
Wed Dec 15 12:19:44 2010
@@ -0,0 +1,44 @@
+/*
+ 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.tokenprovider;
+
+/**
+ * Interface of a token storage provider. The only responsibility of a token
storage provider is
+ * storing tokens (duh). Tokens are simply single String values.
+ *
+ * @author ivol
+ */
+public interface TokenStorageProvider {
+ /**
+ * Adds a new token to the store.
+ * @param token The token to add
+ */
+ void addToken(String token);
+
+ /**
+ * Returns if this store holds the given token.
+ * @param token The token to verify
+ * @return true if this store holds this token, false otherwise
+ */
+ boolean hasToken(String token);
+
+ /**
+ * Removes a token from the store.
+ * @param token The token to remove.
+ */
+ void removeToken(String token);
+}
Added:
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/osgi/Activator.java
==============================================================================
--- (empty file)
+++
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/osgi/Activator.java
Wed Dec 15 12:19:44 2010
@@ -0,0 +1,58 @@
+/*
+ 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.tokenprovider.osgi;
+
+import org.amdatu.authentication.tokenprovider.TokenProvider;
+import org.amdatu.authentication.tokenprovider.TokenStorageProvider;
+import org.amdatu.authentication.tokenprovider.service.TokenProviderImpl;
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.log.LogService;
+
+/**
+ * This is the activator for the authorization bundle
+ * @author ivol
+ */
+public class Activator extends DependencyActivatorBase {
+
+ @Override
+ public void init(BundleContext context, DependencyManager manager) throws
Exception {
+ // Create and register the Token provider service component.
+ manager.add(
+ createComponent()
+ .setInterface(TokenProvider.class.getName(), null)
+ .setImplementation(TokenProviderImpl.class)
+
.add(createServiceDependency().setService(LogService.class).setRequired(true))
+
.add(createServiceDependency().setService(TokenStorageProvider.class).setRequired(true)));
+
+ // Create and register the REST API for the token provider service
component.
+ // TODO: This REST interface is disabled for now for security reasons.
+ // See http://jira.amdatu.org/jira/browse/AMDATU-230
+ /* manager.add(
+ createComponent()
+ .setInterface(TokenRESTResource.class.getName(), null)
+ .setImplementation(TokenRESTResourceImpl.class)
+
.add(createServiceDependency().setService(LogService.class).setRequired(true))
+
.add(createServiceDependency().setService(TokenProvider.class).setRequired(true)));
*/
+ }
+
+
+ @Override
+ public void destroy(BundleContext context, DependencyManager manager)
throws Exception {
+ }
+}
Added:
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/service/TokenProviderImpl.java
==============================================================================
--- (empty file)
+++
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/service/TokenProviderImpl.java
Wed Dec 15 12:19:44 2010
@@ -0,0 +1,256 @@
+/*
+ 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.tokenprovider.service;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+
+import org.amdatu.authentication.tokenprovider.InvalidTokenException;
+import org.amdatu.authentication.tokenprovider.TokenProvider;
+import org.amdatu.authentication.tokenprovider.TokenProviderException;
+import org.amdatu.authentication.tokenprovider.TokenStorageProvider;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.osgi.service.log.LogService;
+
+public class TokenProviderImpl implements TokenProvider {
+ // Service dependencies
+ private volatile LogService m_logService;
+
+ // Ecnryption and decryption key and ciphers
+ private final static String ENCRYPTION_METHOD = "AES";
+ private final static int PRIVATE_KEY_SIZE = 128;
+ private final static String DEFAULT_CHARSET = "UTF-8";
+ private SecretKey m_secretKey = null;
+ private String m_privateKey = null;
+ private static Cipher m_encryptCipher;
+ private static Cipher m_decryptCipher;
+
+ /**
+ * Initialize this service.
+ *
+ * @throws NoSuchAlgorithmException
+ * @throws InvalidKeyException
+ * @throws NoSuchPaddingException
+ * @throws UnsupportedEncodingException
+ */
+ public void init() throws NoSuchAlgorithmException, InvalidKeyException,
NoSuchPaddingException, UnsupportedEncodingException {
+ if (m_secretKey == null) {
+ KeyGenerator keyGen = KeyGenerator.getInstance(ENCRYPTION_METHOD);
+ keyGen.init(PRIVATE_KEY_SIZE);
+ m_secretKey = keyGen.generateKey();
+ m_privateKey = new
Base64().encodeToString(m_secretKey.getEncoded());
+ }
+ if (m_encryptCipher == null) {
+ m_encryptCipher = Cipher.getInstance(ENCRYPTION_METHOD);
+ m_encryptCipher.init(Cipher.ENCRYPT_MODE, m_secretKey);
+ }
+ if (m_decryptCipher == null) {
+ m_decryptCipher = Cipher.getInstance(ENCRYPTION_METHOD);
+ m_decryptCipher.init(Cipher.DECRYPT_MODE, m_secretKey);
+ }
+ }
+
+ // The token store
+ private TokenStorageProvider m_tokenStore;
+
+ private String generateSignature(SortedMap<String, String> attributes)
throws TokenProviderException {
+ String signvalue = m_privateKey;
+ if (attributes != null && attributes.size() > 0) {
+ try {
+ signvalue += attributesToString(attributes);
+ }
+ catch (UnsupportedEncodingException e) {
+ throw new TokenProviderException(e);
+ }
+ }
+ String signature = DigestUtils.md5Hex(signvalue);
+ return signature;
+ }
+
+ private boolean verifySignature(SortedMap<String, String> attributes,
String signature) throws TokenProviderException {
+ String verifySignature = generateSignature(attributes);
+ return signature.equals(verifySignature);
+ }
+
+ // Converts a map of attribute keys and values into a single String
representation, using
+ // URL encoding
+ private String attributesToString(SortedMap<String, String> attributes)
throws UnsupportedEncodingException {
+ String result = "";
+ if (attributes != null && attributes.size() > 0) {
+ for (String key : attributes.keySet()) {
+ String value = attributes.get(key);
+ String encKey =
URLEncoder.encode(key.toString(),DEFAULT_CHARSET);
+ String encValue =
URLEncoder.encode(value.toString(),DEFAULT_CHARSET);
+ result += " " + encKey + "=" + encValue;
+ }
+ }
+ return result;
+ }
+
+ // Converts a single String into a map of attribute keys and values using
URL deencoding
+ private SortedMap<String, String> stringToAttributes(String string) throws
UnsupportedEncodingException {
+ SortedMap<String, String> attributes = null;
+ if (string != null && !"".equals(string)) {
+ attributes = new TreeMap<String, String>();
+ String[] keyvalues = string.split(" "); // space is the attribute
separator
+ for (String keyvalue : keyvalues) {
+ String key = keyvalue.split("=")[0];
+ String value = keyvalue.split("=")[1];
+ attributes.put(key, value);
+ }
+ }
+ return attributes;
+ }
+
+ public String generateToken(SortedMap<String, String> attributes) throws
TokenProviderException {
+ try {
+ if (attributes.containsKey(NONCE)) {
+ throw new TokenProviderException("Invalid token attributes
provided. Parameter '" + NONCE + "' is a preserved name");
+ }
+ if (attributes.containsKey(TIMESTAMP)) {
+ throw new TokenProviderException("Invalid token attributes
provided. Parameter '" + TIMESTAMP + "' is a preserved name");
+ }
+
+ // Add nonce and timestamp attributes
+ String nonce = DigestUtils.md5Hex(new
Long(System.nanoTime()).toString());
+ attributes.put(NONCE, nonce);
+ String timestamp = new Long(System.currentTimeMillis()).toString();
+ attributes.put(TIMESTAMP, timestamp);
+
+ // First create the unencrypted token
+ String signature = generateSignature(attributes);
+ String token = signature + attributesToString(attributes);
+
+ // Encode the token using utf-8
+ byte[] utf8 = token.getBytes(DEFAULT_CHARSET);
+
+ // Encrypt it
+ byte[] enc = m_encryptCipher.doFinal(utf8);
+
+ // Encode to base64
+ String encryptedToken = Base64.encodeBase64String(enc);
+ encryptedToken = encryptedToken.replace("\r", ""); // remove new
lines
+ encryptedToken = encryptedToken.replace("\n", ""); // remove new
lines
+
+ // Store the encrypted token
+ m_tokenStore.addToken(encryptedToken);
+
+ return encryptedToken;
+ }
+ catch (BadPaddingException e) {
+ m_logService.log(LogService.LOG_ERROR, "Could not encrypt string",
e);
+ }
+ catch (IllegalBlockSizeException e) {
+ m_logService.log(LogService.LOG_ERROR, "Could not encrypt string",
e);
+ }
+ catch (UnsupportedEncodingException e) {
+ m_logService.log(LogService.LOG_ERROR, "Could not encrypt string",
e);
+ }
+ return null;
+ }
+
+ public SortedMap<String, String> verifyToken(String encryptedToken) throws
TokenProviderException, InvalidTokenException {
+ try {
+ // First verify that this token was generated by us
+ if (!m_tokenStore.hasToken(encryptedToken)) {
+ throw new InvalidTokenException("Token is invalid, token
unknown");
+ }
+
+ // Decode base64 to get bytes
+ byte[] dec = Base64.decodeBase64(encryptedToken);
+
+ // Decrypt
+ byte[] utf8 = m_decryptCipher.doFinal(dec);
+
+ // Decode using utf-8
+ String token = new String(utf8, DEFAULT_CHARSET);
+
+ // Now this token consists of signature + token attributes
+ String signature;
+ SortedMap<String, String> attributes = null;
+ if (token.indexOf(" ") != -1) {
+ signature = token.substring(0, token.indexOf(" "));
+ attributes =
stringToAttributes(token.substring(token.indexOf(" ") + 1));
+ } else {
+ signature = token;
+ }
+
+ // Now verify if this signature is valid
+ if (!verifySignature(attributes, signature)) {
+ throw new InvalidTokenException("Token is invalid, signature
mismatch");
+ }
+ return attributes;
+ }
+ catch (BadPaddingException e) {
+ m_logService.log(LogService.LOG_ERROR, "Could not decrypt string",
e);
+ throw new TokenProviderException(e);
+ }
+ catch (IllegalBlockSizeException e) {
+ m_logService.log(LogService.LOG_ERROR, "Could not decrypt string",
e);
+ throw new TokenProviderException(e);
+ }
+ catch (UnsupportedEncodingException e) {
+ m_logService.log(LogService.LOG_ERROR, "Could not decrypt string",
e);
+ throw new TokenProviderException(e);
+ }
+ }
+
+ public String updateToken(String encryptedToken, SortedMap<String, String>
newAttributes) throws TokenProviderException, InvalidTokenException {
+ // First validate that the token is valid and retrieve the original
token attributes
+ SortedMap<String, String> attributes = verifyToken(encryptedToken);
+
+ // Now update the token attributes with the new ones
+ if (newAttributes != null && newAttributes.size() > 0) {
+ for (String key : newAttributes.keySet()) {
+ String value = newAttributes.get(key);
+ attributes.put(key, value);
+ }
+ }
+
+ // Generate a new token
+ return generateToken(attributes);
+ }
+
+ public void invalidateToken(String encryptedToken) {
+ m_tokenStore.removeToken(encryptedToken);
+ }
+
+ public String getTokenFromRequest(HttpServletRequest request) {
+ if (request.getCookies() != null) {
+ for (Cookie cookie : request.getCookies()) {
+ if (TokenProvider.TOKEN_COOKIE_NAME.equals(cookie.getName())) {
+ return cookie.getValue();
+ }
+ }
+ }
+ return null;
+ }
+}
Added:
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/service/TokenRESTResourceImpl.java
==============================================================================
--- (empty file)
+++
trunk/amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/service/TokenRESTResourceImpl.java
Wed Dec 15 12:19:44 2010
@@ -0,0 +1,103 @@
+/*
+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.tokenprovider.service;
+
+import java.util.Enumeration;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.CacheControl;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.amdatu.authentication.tokenprovider.InvalidTokenException;
+import org.amdatu.authentication.tokenprovider.TokenProvider;
+import org.amdatu.authentication.tokenprovider.TokenProviderException;
+import org.amdatu.authentication.tokenprovider.TokenRESTResource;
+
+/**
+ * TODO: This REST interface is not yet activated in the OSGi activator as an
important security issue first needs
+ * to be addressed. See http://jira.amdatu.org/jira/browse/AMDATU-230
+ *
+ * This provides a REST interface on top of the token provider service. Note
that security is a difficult issue here.
+ * We cannot use oAuth Signed Requests, since that would create a chicken-egg
problem: in order to use oAuth Signed Requests
+ * we do need to have authenticated and authorized users (for consumer
registration, defining the consumer secrets).
+ * If for user authentication oAuth Signed Requests are required, that causes
a circular dependency.
+ * We need to think of certificates in the future. Certificates that are
deployed onto Amdatu nodes, which can be used
+ * to authenticate where a request is coming from and use that for
authorization. To invoke this service via REST instead of
+ * Java interface, we should use the HttpProxy project, as descibed in issue
+ *
+ * @author ivol
+ */
+ at Path("token")
+public class TokenRESTResourceImpl implements TokenRESTResource {
+ // Service dependencies
+ private volatile TokenProvider m_tokenProvider;
+
+ // HTTP caching policy for this REST interface
+ private static CacheControl m_cacheControl;
+ static {
+ m_cacheControl = new CacheControl();
+ m_cacheControl.setNoCache(true);
+ }
+
+ @SuppressWarnings("unchecked")
+ @POST
+ @Produces(MediaType.TEXT_PLAIN)
+ @Consumes("application/x-www-form-urlencoded")
+ public Response generateToken(@Context HttpServletRequest request) {
+ SortedMap<String, String> attributes = new TreeMap<String, String>();
+ Enumeration paramEnum = request.getParameterNames();
+ while (paramEnum.hasMoreElements()) {
+ String key = paramEnum.nextElement().toString();
+ String value = request.getParameter(key);
+ attributes.put(key, value);
+ }
+ try {
+ String token = m_tokenProvider.generateToken(attributes);
+ return Response.ok(token).cacheControl(m_cacheControl).build();
+ }
+ catch (TokenProviderException e) {
+ throw new WebApplicationException(e,
HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ @GET
+ @Path("{token}")
+ public Response validateToken(@PathParam("token") String token) {
+ try {
+ m_tokenProvider.verifyToken(token);
+ return Response.ok().cacheControl(m_cacheControl).build();
+ }
+ catch (TokenProviderException e) {
+ throw new WebApplicationException(e,
HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ }
+ catch (InvalidTokenException e) {
+ return
Response.status(HttpServletResponse.SC_NOT_FOUND).cacheControl(m_cacheControl).build();
+ }
+ }
+}
Added: trunk/amdatu-authentication/tokenstore-mem/pom.xml
==============================================================================
--- (empty file)
+++ trunk/amdatu-authentication/tokenstore-mem/pom.xml Wed Dec 15 12:19:44 2010
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.amdatu</groupId>
+ <artifactId>org.amdatu.authentication</artifactId>
+ <version>0.1.0-SNAPSHOT</version>
+ </parent>
+ <groupId>org.amdatu.authentication.tokenstore</groupId>
+ <artifactId>mem</artifactId>
+ <packaging>bundle</packaging>
+ <name>Amdatu Authentication - In-memory token store</name>
+ <description>This bundle implements an in-memory token store</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.amdatu.authentication</groupId>
+ <artifactId>tokenprovider</artifactId>
+ <version>${platform.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+
<Bundle-Activator>org.amdatu.authentication.tokenstore.mem.osgi.Activator</Bundle-Activator>
+
<Bundle-SymbolicName>org.amdatu.authentication.tokenstore.mem</Bundle-SymbolicName>
+
<Export-Package>org.amdatu.authentication.tokenstore.mem</Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
Added:
trunk/amdatu-authentication/tokenstore-mem/src/main/java/org/amdatu/authentication/tokenstore/mem/osgi/Activator.java
==============================================================================
--- (empty file)
+++
trunk/amdatu-authentication/tokenstore-mem/src/main/java/org/amdatu/authentication/tokenstore/mem/osgi/Activator.java
Wed Dec 15 12:19:44 2010
@@ -0,0 +1,45 @@
+/*
+ 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.tokenstore.mem.osgi;
+
+import org.amdatu.authentication.tokenprovider.TokenStorageProvider;
+import
org.amdatu.authentication.tokenstore.mem.service.InMemTokenStorageProviderImpl;
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.log.LogService;
+
+/**
+ * This is the activator for the token store in-memory store bundle
+ * @author ivol
+ */
+public class Activator extends DependencyActivatorBase {
+
+ @Override
+ public void init(BundleContext context, DependencyManager manager) throws
Exception {
+ // Create and register the OAuth token provider service component.
+ manager.add(
+ createComponent()
+ .setInterface(TokenStorageProvider.class.getName(), null)
+ .setImplementation(InMemTokenStorageProviderImpl.class)
+
.add(createServiceDependency().setService(LogService.class).setRequired(true)));
+ }
+
+ @Override
+ public void destroy(BundleContext context, DependencyManager manager)
throws Exception {
+ }
+}
Added:
trunk/amdatu-authentication/tokenstore-mem/src/main/java/org/amdatu/authentication/tokenstore/mem/service/InMemTokenStorageProviderImpl.java
==============================================================================
--- (empty file)
+++
trunk/amdatu-authentication/tokenstore-mem/src/main/java/org/amdatu/authentication/tokenstore/mem/service/InMemTokenStorageProviderImpl.java
Wed Dec 15 12:19:44 2010
@@ -0,0 +1,44 @@
+/*
+ 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.tokenstore.mem.service;
+
+import java.util.Collection;
+import java.util.HashSet;
+
+import org.amdatu.authentication.tokenprovider.TokenStorageProvider;
+
+/**
+ * This class implements a very simple in-memory token store.
+ *
+ * @author ivol
+ */
+public class InMemTokenStorageProviderImpl implements TokenStorageProvider {
+ // The in-memory token store
+ private Collection<String> m_tokens = new HashSet<String>();
+
+ public void addToken(String token) {
+ m_tokens.add(token);
+ }
+
+ public boolean hasToken(String token) {
+ return m_tokens.contains(token);
+ }
+
+ public void removeToken(String token) {
+ m_tokens.remove(token);
+ }
+}
Modified: trunk/amdatu-authorization/login-service/pom.xml
==============================================================================
--- trunk/amdatu-authorization/login-service/pom.xml (original)
+++ trunk/amdatu-authorization/login-service/pom.xml Wed Dec 15 12:19:44 2010
@@ -32,7 +32,13 @@
<artifactId>json</artifactId>
<version>20090211</version>
<scope>compile</scope>
- </dependency>
+ </dependency>
+ <dependency>
+ <groupId>org.amdatu.authentication</groupId>
+ <artifactId>tokenprovider</artifactId>
+ <version>${platform.version}</version>
+ <scope>provided</scope>
+ </dependency>
</dependencies>
<build>
Modified:
trunk/amdatu-authorization/login-service/src/main/java/org/amdatu/authorization/login/service/osgi/Activator.java
==============================================================================
---
trunk/amdatu-authorization/login-service/src/main/java/org/amdatu/authorization/login/service/osgi/Activator.java
(original)
+++
trunk/amdatu-authorization/login-service/src/main/java/org/amdatu/authorization/login/service/osgi/Activator.java
Wed Dec 15 12:19:44 2010
@@ -16,6 +16,7 @@
*/
package org.amdatu.authorization.login.service.osgi;
+import org.amdatu.authentication.tokenprovider.TokenProvider;
import org.amdatu.authorization.login.service.LoginService;
import org.amdatu.authorization.login.service.service.LoginServiceImpl;
import org.amdatu.web.httpcontext.HttpContextServiceFactory;
@@ -42,8 +43,11 @@
.setInterface(LoginService.class.getName(), null)
.setImplementation(LoginServiceImpl.class)
.add(createServiceDependency().setService(HttpContextServiceFactory.class).setRequired(true))
+
.add(createServiceDependency().setService(TokenProvider.class).setRequired(true))
.add(createServiceDependency().setService(LogService.class).setRequired(true))
.add(createServiceDependency().setService(UserAdmin.class).setRequired(true)));
+
+
}
@Override
Modified:
trunk/amdatu-authorization/login-service/src/main/java/org/amdatu/authorization/login/service/service/LoginServiceImpl.java
==============================================================================
---
trunk/amdatu-authorization/login-service/src/main/java/org/amdatu/authorization/login/service/service/LoginServiceImpl.java
(original)
+++
trunk/amdatu-authorization/login-service/src/main/java/org/amdatu/authorization/login/service/service/LoginServiceImpl.java
Wed Dec 15 12:19:44 2010
@@ -17,22 +17,31 @@
package org.amdatu.authorization.login.service.service;
import java.net.URL;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.NewCookie;
import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+import org.amdatu.authentication.tokenprovider.InvalidTokenException;
+import org.amdatu.authentication.tokenprovider.TokenProvider;
+import org.amdatu.authentication.tokenprovider.TokenProviderException;
import org.amdatu.authorization.login.service.LoginService;
import org.amdatu.authorization.login.service.osgi.Activator;
-import org.amdatu.web.httpcontext.BasicHttpSession;
import org.amdatu.web.httpcontext.HttpContextServiceFactory;
import org.amdatu.web.httpcontext.ResourceProvider;
import org.apache.felix.dm.Component;
@@ -40,7 +49,6 @@
import org.json.JSONObject;
import org.osgi.framework.BundleContext;
import org.osgi.service.log.LogService;
-import org.osgi.service.useradmin.Authorization;
import org.osgi.service.useradmin.Group;
import org.osgi.service.useradmin.Role;
import org.osgi.service.useradmin.User;
@@ -48,9 +56,10 @@
/**
* This service is responsible for authorization handling, based on the
UserAdmin OSGi service.
+ *
* @author ivol
*/
- at Path ("authorization")
+ at Path("authorization")
public class LoginServiceImpl implements ResourceProvider, LoginService {
// Default Administrator user credentials
private static final String DEFAULT_USERNAME = "Administrator";
@@ -62,17 +71,18 @@
private volatile BundleContext m_bundleContext;
private volatile HttpContextServiceFactory m_httpContextServiceFactory;
private volatile UserAdmin m_userAdmin;
+ private volatile TokenProvider m_tokenProvider;
// The private HTTP context service for this bundle
private Component m_httpContextComponent;
-
+
// Disable HTTP caching in this REST interface
private static CacheControl m_cacheControl;
static {
m_cacheControl = new CacheControl();
m_cacheControl.setNoCache(true);
}
-
+
/**
* The init() method is invoked by the Felix dependency manager.
*/
@@ -93,7 +103,8 @@
adminUser.getProperties().put(USER_NAME_CREDENTIAL_KEY,
DEFAULT_USERNAME);
Group adminGroup = (Group)
m_userAdmin.createRole(DEFAULT_ADMIN_GROUP, Role.GROUP);
adminGroup.addMember(adminUser);
- } else {
+ }
+ else {
m_logService.log(LogService.LOG_ERROR, "Failed to create
initial user " + DEFAULT_USERNAME);
}
}
@@ -107,21 +118,22 @@
/**
* This method can be used to check the availability of the Login Service.
+ *
* @return The text "Login service online"
*/
@GET
- @Produces({MediaType.TEXT_PLAIN})
+ @Produces( { MediaType.TEXT_PLAIN })
public String status() {
return "Login service online";
- }
-
+ }
+
/**
* This REST service returns the current login status. Returns the
username of the current user is logged in or an
* empty string if the user is not logged in.
*/
@GET
@Path("status")
- @Produces({MediaType.APPLICATION_JSON})
+ @Produces( { MediaType.APPLICATION_JSON })
public Response getLoginStatus(@Context final HttpServletRequest request) {
// TODO: here we have the authorization of this user, but to which
context should we bind
// it? And what about oAuth? For now we just bind it to the http
session and use the
@@ -129,18 +141,22 @@
// because of issue AMDATU-67.
JSONObject jsonObject = new JSONObject();
try {
- BasicHttpSession session = BasicHttpSession.getSession(request);
- if (session != null) {
- Authorization auth = (Authorization)
session.getValue("authorization");
- if (auth != null) {
- String currentUser = auth.getName();
- jsonObject.append("username", currentUser);
- return Response.ok(jsonObject.toString(),
MediaType.APPLICATION_JSON_TYPE).cacheControl(m_cacheControl).build();
- }
+ String userName = getUserName(request);
+ if (userName != null) {
+ jsonObject.append("username", userName);
+ return Response.ok(jsonObject.toString(),
MediaType.APPLICATION_JSON_TYPE).cacheControl(m_cacheControl)
+ .build();
}
- } catch (JSONException e) {
+ }
+ catch (JSONException e) {
m_logService.log(LogService.LOG_ERROR, "Could not retrieve current
login status", e);
}
+ catch (TokenProviderException e) {
+ // If the token is invalid, the user is not logged in anymore, ignore
this error
+ }
+ catch (InvalidTokenException e) {
+ // If the token is invalid, the user is not logged in anymore,
ignore this error
+ }
return Response.ok(jsonObject.toString(),
MediaType.APPLICATION_JSON_TYPE).cacheControl(m_cacheControl).build();
}
@@ -150,79 +166,88 @@
@POST
@Path("login")
@Consumes("application/x-www-form-urlencoded")
- @Produces({MediaType.APPLICATION_JSON})
+ @Produces( { MediaType.APPLICATION_JSON })
public Response login(@FormParam("username") final String username,
@FormParam("password") final String password,
- @Context final HttpServletRequest request) {
+ @Context final HttpServletRequest request) {
m_logService.log(LogService.LOG_INFO, "Login requested for user: " +
username);
// First retrieve the user with this username
JSONObject jsonObject = new JSONObject();
+ NewCookie cookie = null;
try {
Role userRole = m_userAdmin.getRole(username);
if (userRole != null && userRole.getType() == Role.USER) {
User user = (User) userRole;
if (user.hasCredential(PASSWORD_CREDENTIAL_KEY, password)) {
- Authorization auth = m_userAdmin.getAuthorization(user);
+ // Now generate a token for this user and write it to a
Set-Cookie header
+ String token = generateToken(request, user);
+ cookie = new NewCookie(TokenProvider.TOKEN_COOKIE_NAME,
token, "/", null, "Amdatu session", -1, false);
+
+ m_logService.log(LogService.LOG_INFO, "User '" + username
+ "' logged in successfully");
+ jsonObject.append("result", "ok");
+ jsonObject.append("username", username);
+ jsonObject.append("msg", "User '" + username + "' logged
in successfully");
- // TODO: here we have the authorization of this user, but
to which context should we bind
- // it? And what about oAuth? For now we just bind it to
the http session and use the
- // session info in the container. Note that we use our own
http session implementation
- // because of issue AMDATU-67.
- BasicHttpSession session =
BasicHttpSession.getSession(request);
- session.putValue("authorization", auth);
- if (session != null) {
- m_logService.log(LogService.LOG_INFO, "User '" +
username + "' logged in successfully");
- jsonObject.append("result", "ok");
- jsonObject.append("username", username);
- jsonObject.append("msg", "User '" + username + "'
logged in successfully");
- } else {
- m_logService.log(LogService.LOG_INFO, "User '" +
username
- + "' could not log in, missing JSESSIONID
cookie");
- jsonObject.append("result", "failed");
- jsonObject.append("msg", "Users browser didn't send
JSESSIONID, could not create http session");
- }
- } else {
+ }
+ else {
m_logService.log(LogService.LOG_INFO, "Incorrect password
provided for user '" + username + "'");
jsonObject.append("result", "failed");
jsonObject.append("msg", "Password is incorrect");
}
- } else {
+ }
+ else {
m_logService.log(LogService.LOG_INFO, "Username '" + username
+ "' unknown");
jsonObject.append("result", "failed");
jsonObject.append("msg", "Username is unknown");
}
- } catch (JSONException e) {
+ }
+ catch (JSONException e) {
m_logService.log(LogService.LOG_ERROR, "Could not retrieve current
login status", e);
+ throw new WebApplicationException(e,
HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
- return Response.ok(jsonObject.toString(),
MediaType.APPLICATION_JSON_TYPE).cacheControl(m_cacheControl).build();
+ catch (TokenProviderException e) {
+ m_logService.log(LogService.LOG_ERROR, "Could not retrieve current
login status", e);
+ throw new WebApplicationException(e,
HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ }
+
+ ResponseBuilder builder = Response.ok(jsonObject.toString(),
MediaType.APPLICATION_JSON_TYPE);
+ builder.cacheControl(m_cacheControl);
+ if (cookie != null) {
+ builder.cookie(cookie);
+ }
+ return builder.build();
}
/**
* REST based logout service with username/password.
+ *
* @return The result of the SPARQL query.
*/
@POST
@Path("logout")
- @Produces({MediaType.APPLICATION_JSON})
+ @Produces( { MediaType.APPLICATION_JSON })
public Response logout(@Context final HttpServletRequest request) {
// TODO: here we have the authorization of this user, but to which
context should we bind
// it? And what about oAuth? For now we just bind it to the http
session and use the
// session info in the container. Note that we use our own http
session implementation
// because of issue AMDATU-67.
JSONObject jsonObject = new JSONObject();
+ String userName = null;
try {
- BasicHttpSession session = BasicHttpSession.getSession(request);
- if (session != null) {
- Authorization auth = (Authorization)
session.getValue("authorization");
- if (auth != null) {
- m_logService.log(LogService.LOG_INFO, "User '" +
auth.getName() + "' logged out successfully");
- session.putValue("authorization", null);
- }
- }
+ userName = getUserName(request);
+ invalidateToken(request);
+ m_logService.log(LogService.LOG_INFO, "User '" + userName + "'
logged out successfully");
jsonObject.append("result", "ok");
- } catch (JSONException e) {
+ }
+ catch (JSONException e) {
m_logService.log(LogService.LOG_ERROR, "Could not retrieve current
login status", e);
}
+ catch (TokenProviderException e) {
+ m_logService.log(LogService.LOG_INFO, "User '" + userName + "'
could not be logged out");
+ }
+ catch (InvalidTokenException e) {
+ m_logService.log(LogService.LOG_INFO, "User '" + userName + "' not
logged out, token was already invalid");
+ }
return Response.ok(jsonObject.toString(),
MediaType.APPLICATION_JSON_TYPE).cacheControl(m_cacheControl).build();
}
@@ -233,4 +258,28 @@
public String getResourceId() {
return Activator.RESOURCE_ID;
}
+
+ private String generateToken(HttpServletRequest request, User user) throws
TokenProviderException {
+ SortedMap<String, String> attributes = new TreeMap<String, String>();
+ attributes.put("ip", request.getRemoteAddr());
+ attributes.put(TokenProvider.USERNAME, user.getName());
+ return m_tokenProvider.generateToken(attributes);
+ }
+
+ private String getUserName(HttpServletRequest request) throws
TokenProviderException, InvalidTokenException {
+ String token = m_tokenProvider.getTokenFromRequest(request);
+ if (token != null) {
+ // Now decrypt to get the username and signature
+ Map<String, String> attributes =
m_tokenProvider.verifyToken(token);
+ if (attributes != null) {
+ return attributes.get(TokenProvider.USERNAME);
+ }
+ }
+
+ return null;
+ }
+
+ private void invalidateToken(HttpServletRequest request) {
+
m_tokenProvider.invalidateToken(m_tokenProvider.getTokenFromRequest(request));
+ }
}
Modified: trunk/amdatu-opensocial/gadgetmanagement/pom.xml
==============================================================================
--- trunk/amdatu-opensocial/gadgetmanagement/pom.xml (original)
+++ trunk/amdatu-opensocial/gadgetmanagement/pom.xml Wed Dec 15 12:19:44 2010
@@ -63,7 +63,13 @@
<groupId>org.amdatu.libraries</groupId>
<artifactId>utilities</artifactId>
<scope>compile</scope>
- </dependency>
+ </dependency>
+ <dependency>
+ <groupId>org.amdatu.authentication</groupId>
+ <artifactId>tokenprovider</artifactId>
+ <version>${platform.version}</version>
+ <scope>provided</scope>
+ </dependency>
</dependencies>
<build>
Modified:
trunk/amdatu-opensocial/gadgetmanagement/src/main/java/org/amdatu/opensocial/gadgetmanagement/osgi/Activator.java
==============================================================================
---
trunk/amdatu-opensocial/gadgetmanagement/src/main/java/org/amdatu/opensocial/gadgetmanagement/osgi/Activator.java
(original)
+++
trunk/amdatu-opensocial/gadgetmanagement/src/main/java/org/amdatu/opensocial/gadgetmanagement/osgi/Activator.java
Wed Dec 15 12:19:44 2010
@@ -16,6 +16,7 @@
*/
package org.amdatu.opensocial.gadgetmanagement.osgi;
+import org.amdatu.authentication.tokenprovider.TokenProvider;
import org.amdatu.cassandra.listener.ColumnFamilyAvailable;
import org.amdatu.cassandra.persistencemanager.CassandraPersistenceManager;
import org.amdatu.opensocial.gadgetmanagement.GadgetManagement;
@@ -55,6 +56,7 @@
.add(createServiceDependency().setService(HttpContextServiceFactory.class).setRequired(true))
.add(createServiceDependency().setService(ColumnFamilyAvailable.class,
gadgetFilter).setRequired(true))
.add(createServiceDependency().setService(GadgetStore.class).setRequired(true))
+
.add(createServiceDependency().setService(TokenProvider.class).setRequired(true))
.add(createServiceDependency().setService(CassandraPersistenceManager.class,
keyspaceFilter).setRequired(true)));
}
Modified:
trunk/amdatu-opensocial/gadgetmanagement/src/main/java/org/amdatu/opensocial/gadgetmanagement/service/GadgetManagementServiceImpl.java
==============================================================================
---
trunk/amdatu-opensocial/gadgetmanagement/src/main/java/org/amdatu/opensocial/gadgetmanagement/service/GadgetManagementServiceImpl.java
(original)
+++
trunk/amdatu-opensocial/gadgetmanagement/src/main/java/org/amdatu/opensocial/gadgetmanagement/service/GadgetManagementServiceImpl.java
Wed Dec 15 12:19:44 2010
@@ -48,6 +48,9 @@
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
+import org.amdatu.authentication.tokenprovider.InvalidTokenException;
+import org.amdatu.authentication.tokenprovider.TokenProvider;
+import org.amdatu.authentication.tokenprovider.TokenProviderException;
import org.amdatu.authorization.login.service.LoginService;
import org.amdatu.cassandra.persistencemanager.CassandraException;
import org.amdatu.libraries.utilities.ConversionUtil;
@@ -58,7 +61,6 @@
import org.amdatu.opensocial.shindig.GadgetDefinition;
import org.amdatu.opensocial.shindig.GadgetStore;
import org.amdatu.opensocial.shindig.OpenSocialConstants;
-import org.amdatu.web.httpcontext.BasicHttpSession;
import org.amdatu.web.httpcontext.HttpContextServiceFactory;
import org.amdatu.web.httpcontext.ResourceProvider;
import org.apache.felix.dm.Component;
@@ -75,7 +77,6 @@
import org.json.JSONObject;
import org.osgi.framework.BundleContext;
import org.osgi.service.log.LogService;
-import org.osgi.service.useradmin.Authorization;
import org.osgi.service.useradmin.User;
import org.osgi.service.useradmin.UserAdmin;
@@ -93,7 +94,7 @@
private static final String[] GADGET_MODULEPREFS =
new String[] { "title", "description", "author", "author_email",
"author_affiliation", "screenshot",
- "title_url" };
+ "title_url" };
// Services injected by the Felix dependency manager
private volatile BundleContext m_bundleContext;
@@ -101,6 +102,7 @@
private volatile UserAdmin m_userAdmin;
private volatile HttpContextServiceFactory m_httpContextFactoryService;
private volatile GadgetStore m_gadgetStore;
+ private volatile TokenProvider m_tokenProvider;
private Component m_httpContextComponent;
@@ -117,13 +119,13 @@
m_noCacheControl = new CacheControl();
m_noCacheControl.setNoCache(true); // No cache
}
-
+
private static CacheControl m_maxAgeCacheControl;
static {
m_maxAgeCacheControl = new CacheControl();
m_maxAgeCacheControl.setMaxAge(300); // 5 minutes
}
-
+
/**
* The init() method is invoked by the Felix dependency manager.
*/
@@ -163,11 +165,11 @@
public String status() {
return "Gadget management service online";
}
-
+
public boolean addGadget(GadgetDefinition gadget) {
return m_gadgetStore.addGadget(gadget);
}
-
+
// Removes a gadget from the store
public boolean removeGadget(GadgetDefinition gadget) {
return m_gadgetStore.removeGadget(gadget);
@@ -282,22 +284,7 @@
public Response getMyGadgets(@Context HttpHeaders headers, @Context
HttpServletRequest request) {
JSONObject jsonObject = new JSONObject();
List<JSONObject> gadgets = new ArrayList<JSONObject>();
- String viewer = null;
- /*
- * FIXME: do this when oAuth is enabled List<String> authHeader =
- * headers.getRequestHeaders().get("Authorization"); if (authHeader !=
null) { String[] oAuthHeaders =
- * authHeader.get(0).split(","); for (String oAuthHeader :
oAuthHeaders) { if
- * (oAuthHeader.trim().startsWith("opensocial_viewer_id=")) { viewer =
oAuthHeader.split("=")[1]; // Chop off
- * additional quotes viewer = viewer.substring(1, viewer.length() -
1); } } }
- */
- // FIXME: but for now use the http session
- BasicHttpSession session = BasicHttpSession.getSession(request);
- if (session != null) {
- Authorization auth = (Authorization)
session.getValue("authorization");
- if (auth != null) {
- viewer = auth.getName();
- }
- }
+ String viewer = getUserNameFromRequest(request);
String errorMsg = "An error occurred while retrieving gadgets for
viewer '" + viewer + "'.";
try {
User user = null;
@@ -528,7 +515,7 @@
// TODO: assuming here it is UTF-8
reader =
new BufferedReader(
- new InputStreamReader(inputConnection.getInputStream(),
Charset.forName("UTF-8")));
+ new
InputStreamReader(inputConnection.getInputStream(), Charset.forName("UTF-8")));
String inputLine;
while ((inputLine = reader.readLine()) != null) {
xml += inputLine;
@@ -545,7 +532,7 @@
}
catch (IOException e) {
m_logService
- .log(LogService.LOG_ERROR, "Could not retrieve gadget XML from
url '" + url.toString() + "'", e);
+ .log(LogService.LOG_ERROR, "Could not retrieve gadget XML from url
'" + url.toString() + "'", e);
}
m_logService.log(LogService.LOG_DEBUG, "Retrieving gadgetspec '" + url
+ "' failed");
return null;
@@ -596,7 +583,7 @@
}
private JSONObject retrieveGadget(String gadgetUrl) throws JSONException,
NoSuchAlgorithmException,
- UnsupportedEncodingException {
+ UnsupportedEncodingException {
Map<String, String> gadgetSpec = getGadgetSpec(gadgetUrl);
if (gadgetSpec != null) {
JSONObject gadget = new JSONObject();
@@ -620,7 +607,7 @@
gadget.put("author", gadgetSpec.get("author_email"));
}
else if (!"".equals(gadgetSpec.get("author_affiliation"))
- && gadgetSpec.get("author_affiliation") != null) {
+ && gadgetSpec.get("author_affiliation") !=
null) {
gadget.put("author", gadgetSpec.get("author_affiliation"));
}
else {
@@ -641,7 +628,7 @@
// Adds a security token
private void addSecurityToken(JSONObject gadget, HttpServletRequest
request)
- throws BlobCrypterException, JSONException {
+ throws BlobCrypterException, JSONException {
// TODO: This is the same key as in securitytokenkey.txt file of the
shindig application bundle
// But we are too lazy to load that key from the file
String key = "Tr9W5GNmfCb7eexNi0m+/HVgAlvsHmCuMEofHs6+LoU=";
@@ -650,18 +637,20 @@
BlobCrypterSecurityToken st = new
BlobCrypterSecurityToken(blobCrypter, "default", hostName);
st.setAppUrl(gadget.getJSONObject("metadata").getString("gadgeturl"));
- Authorization auth = (Authorization)
BasicHttpSession.getSession(request).getValue("authorization");
- if (auth != null) {
- st.setViewerId(auth.getName());
- st.setOwnerId(auth.getName());
- }
- else {
- st.setViewerId("anonymous");
- st.setOwnerId("anonymous");
+ String viewerId = "anonymous";
+ String ownerId = "anonymous";
+
+ // Verify if we have a valid authentication token holding a username,
if so add the authenticated user as viewer
+ String userName = getUserNameFromRequest(request);
+ if (userName != null && !"".equals(userName)) {
+ viewerId = userName;
+ ownerId = userName;
}
-
+ st.setViewerId(viewerId);
+ st.setOwnerId(ownerId);
+
String securityToken = Utf8UrlCoder.encode(st.encrypt());
-
+
gadget.getJSONObject("metadata").put("securetoken", securityToken);
}
@@ -695,4 +684,23 @@
public GadgetCategory[] getCategories() {
return m_gadgetStore.getCategories();
}
+
+ private String getUserNameFromRequest(HttpServletRequest request) {
+ String token = m_tokenProvider.getTokenFromRequest(request);
+ if (token != null) {
+ try {
+ Map<String, String> attributes =
m_tokenProvider.verifyToken(token);
+ if (attributes.containsKey(TokenProvider.USERNAME)) {
+ return attributes.get(TokenProvider.USERNAME);
+ }
+ }
+ catch (TokenProviderException e) {
+ // Ignore invalid tokens
+ }
+ catch (InvalidTokenException e) {
+ // Ignore invalid tokens
+ }
+ }
+ return null;
+ }
}
Modified:
trunk/amdatu-opensocial/profile/src/main/java/org/amdatu/opensocial/profile/service/PersonServiceImpl.java
==============================================================================
---
trunk/amdatu-opensocial/profile/src/main/java/org/amdatu/opensocial/profile/service/PersonServiceImpl.java
(original)
+++
trunk/amdatu-opensocial/profile/src/main/java/org/amdatu/opensocial/profile/service/PersonServiceImpl.java
Wed Dec 15 12:19:44 2010
@@ -182,7 +182,10 @@
// Returns the person with the specified id.
private Person getPerson(String id) {
- User user = m_userAdmin.getUser(LoginService.USER_NAME_CREDENTIAL_KEY,
id);
+ User user = null;
+ if (id != null && !"".equals(id)) {
+ user = m_userAdmin.getUser(LoginService.USER_NAME_CREDENTIAL_KEY,
id);
+ }
if (user != null) {
try {
byte[] personBytes = (byte[])
user.getProperties().get(PersonService.OPEN_SOCIAL_PERSON_PROPERTIES_KEY);
Modified: trunk/amdatu-release/pom.xml
==============================================================================
--- trunk/amdatu-release/pom.xml (original)
+++ trunk/amdatu-release/pom.xml Wed Dec 15 12:19:44 2010
@@ -40,6 +40,20 @@
<scope>compile</scope>
<type>bundle</type>
</dependency>
+ <dependency>
+ <groupId>org.amdatu.authentication</groupId>
+ <artifactId>tokenprovider</artifactId>
+ <version>${platform.version}</version>
+ <scope>compile</scope>
+ <type>bundle</type>
+ </dependency>
+ <dependency>
+ <groupId>org.amdatu.authentication.tokenstore</groupId>
+ <artifactId>mem</artifactId>
+ <version>${platform.version}</version>
+ <scope>compile</scope>
+ <type>bundle</type>
+ </dependency>
<!-- Authorization bundles -->
<dependency>
Modified: trunk/amdatu-web/rest-jaxrs/pom.xml
==============================================================================
--- trunk/amdatu-web/rest-jaxrs/pom.xml (original)
+++ trunk/amdatu-web/rest-jaxrs/pom.xml Wed Dec 15 12:19:44 2010
@@ -19,7 +19,14 @@
<artifactId>jsr311-api</artifactId>
<version>${jsr311-api.version}</version>
<scope>compile</scope>
- </dependency>
+ </dependency>
+ <dependency>
+ <groupId>javax.annotation</groupId>
+ <artifactId>jsr250-api</artifactId>
+ <version>1.0</version>
+ <scope>compile</scope>
+ </dependency>
+
</dependencies>
<build>
@@ -33,7 +40,8 @@
<Embed-Dependency>*;scope=compile</Embed-Dependency>
<Embed-Transitive>true</Embed-Transitive>
<_exportcontents>
- javax.ws.rs.*;version=${jsr311-api.version}
+ javax.ws.rs.*;version=${jsr311-api.version},
+ javax.annotation.security
</_exportcontents>
</instructions>
</configuration>
Modified: trunk/integration-tests/pom.xml
==============================================================================
--- trunk/integration-tests/pom.xml (original)
+++ trunk/integration-tests/pom.xml Wed Dec 15 12:19:44 2010
@@ -210,7 +210,21 @@
<scope>test</scope>
<type>bundle</type>
</dependency>
-
+ <dependency>
+ <groupId>org.amdatu.authentication</groupId>
+ <artifactId>tokenprovider</artifactId>
+ <version>${platform.version}</version>
+ <scope>test</scope>
+ <type>bundle</type>
+ </dependency>
+ <dependency>
+ <groupId>org.amdatu.authentication.tokenstore</groupId>
+ <artifactId>mem</artifactId>
+ <version>${platform.version}</version>
+ <scope>test</scope>
+ <type>bundle</type>
+ </dependency>
+
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.configadmin</artifactId>
Modified:
trunk/integration-tests/src/test/java/org/amdatu/test/integration/base/IntegrationTestBase.java
==============================================================================
---
trunk/integration-tests/src/test/java/org/amdatu/test/integration/base/IntegrationTestBase.java
(original)
+++
trunk/integration-tests/src/test/java/org/amdatu/test/integration/base/IntegrationTestBase.java
Wed Dec 15 12:19:44 2010
@@ -65,7 +65,7 @@
public abstract class IntegrationTestBase {
public final static String TEST_PREFIX = "> TESTING: ";
public final static int SERVICE_TIMEOUT = 30;
-
+
// Time out for the http service to come available
private final static int HTTP_TIMEOUT = 10000;
@@ -141,7 +141,7 @@
@Before
public void setupTest() throws Exception {
initConfiguration();
-
+
m_manager = new DependencyManager(m_bundleContext);
Component[] components = getDependencies(m_manager);
@@ -165,17 +165,19 @@
// Generate more background information about the exact
services that were missing.
String moreInfo = "";
for (Component component : components) {
- if (component.getService() == null) {
- moreInfo = "\nComponent that failed to start: " +
component;
- List<ServiceDependency> dependencies =
component.getDependencies();
- for (ServiceDependency dependency : dependencies) {
- if (dependency.getState() ==
ServiceDependency.STATE_UNAVAILABLE_REQUIRED) {
- moreInfo += "\nThe component depends on the
following unavailable service: " + dependency.getName();
- }
- }
- }
+ if (component.getService() == null) {
+ moreInfo = "\nComponent that failed to start: " +
component;
+ List<ServiceDependency> dependencies =
component.getDependencies();
+ for (ServiceDependency dependency : dependencies) {
+ if (dependency.getState() ==
ServiceDependency.STATE_UNAVAILABLE_REQUIRED) {
+ moreInfo +=
+ "\nThe component depends on the following
unavailable service: "
+ + dependency.getName();
+ }
+ }
+ }
}
-
+
Assert.fail("Timed out waiting for all services to get
started, still "
+ (1 - semaphore.availablePermits()) + " to go." +
moreInfo);
}
@@ -184,9 +186,9 @@
Assert.fail("Interrupted while waiting for services to get
started.");
}
}
-
+
/**
- * Override to provide the initial configuration. Configuration must be
provided before
+ * Override to provide the initial configuration. Configuration must be
provided before
* service dependencies are provided since some managed services can only
start when their
* config has been provided.
*/
@@ -278,9 +280,9 @@
FileFilter ff = new FileFilter() {
public boolean accept(File pathname) {
return
pathname.getName().startsWith("org.amdatu.test.integration-")
- && pathname.getName().endsWith(".jar")
- && !pathname.getName().endsWith("-javadoc.jar")
- && !pathname.getName().endsWith("-sources.jar");
+ && pathname.getName().endsWith(".jar")
+ && !pathname.getName().endsWith("-javadoc.jar")
+ && !pathname.getName().endsWith("-sources.jar");
}
};
return new File("target").listFiles(ff)[0];
@@ -299,8 +301,8 @@
protected static MavenArtifactProvisionOption
amdatuUserAdminCassandraStore() {
return
mavenBundle().groupId("org.amdatu.cassandra").artifactId("useradminstore").versionAsInProject();
}
-
- protected static MavenArtifactProvisionOption amdatuUserAdminFSStore() {
+
+ protected static MavenArtifactProvisionOption amdatuUserAdminFSStore() {
return
mavenBundle().groupId("org.amdatu.core").artifactId("useradminstore-fs").versionAsInProject();
}
@@ -336,6 +338,14 @@
return
mavenBundle().groupId("org.amdatu.web").artifactId("httpcontext").versionAsInProject();
}
+ protected static MavenArtifactProvisionOption amdatuTokenProvider() {
+ return
mavenBundle().groupId("org.amdatu.authentication").artifactId("tokenprovider").versionAsInProject();
+ }
+
+ protected static MavenArtifactProvisionOption amdatuMemTokenStore() {
+ return
mavenBundle().groupId("org.amdatu.authentication.tokenstore").artifactId("mem").versionAsInProject();
+ }
+
protected static MavenArtifactProvisionOption amdatuOAuthAPI() {
return
mavenBundle().groupId("org.amdatu.authentication.oauth").artifactId("api").versionAsInProject();
}
@@ -347,10 +357,11 @@
protected static MavenArtifactProvisionOption amdatuOAuthServer() {
return
mavenBundle().groupId("org.amdatu.authentication.oauth").artifactId("server").versionAsInProject();
}
-
+
protected static MavenArtifactProvisionOption
amdatuOAuthConsumerRegistry() {
- return
mavenBundle().groupId("org.amdatu.authentication.oauth").artifactId("consumerregistry-fs").versionAsInProject();
- }
+ return
mavenBundle().groupId("org.amdatu.authentication.oauth").artifactId("consumerregistry-fs")
+ .versionAsInProject();
+ }
protected static MavenArtifactProvisionOption fileBasedConfiguration() {
return
mavenBundle().groupId("org.amdatu.core.config").artifactId("filebased").versionAsInProject();
@@ -362,17 +373,17 @@
protected static MavenArtifactProvisionOption slingCommons() {
return
mavenBundle().groupId("org.apache.sling").artifactId("org.apache.sling.commons.osgi")
- .versionAsInProject();
+ .versionAsInProject();
}
protected static MavenArtifactProvisionOption slingMime() {
return
mavenBundle().groupId("org.apache.sling").artifactId("org.apache.sling.commons.mime")
- .versionAsInProject();
+ .versionAsInProject();
}
protected static MavenArtifactProvisionOption paxUserAdmin() {
return
mavenBundle().groupId("org.ops4j.pax.useradmin").artifactId("pax-useradmin-service")
- .versionAsInProject();
+ .versionAsInProject();
}
protected static MavenArtifactProvisionOption paxSwissbox() {
@@ -389,7 +400,7 @@
protected static MavenArtifactProvisionOption felixHttpServiceWhiteboard()
{
return
mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.http.whiteboard")
- .versionAsInProject();
+ .versionAsInProject();
}
protected static MavenArtifactProvisionOption felixLog() {
@@ -398,12 +409,12 @@
protected static MavenArtifactProvisionOption configAdmin() {
return
mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.configadmin")
- .versionAsInProject();
+ .versionAsInProject();
}
protected static MavenArtifactProvisionOption dependencyManager() {
return
mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.dependencymanager")
- .versionAsInProject();
+ .versionAsInProject();
}
protected static MavenArtifactProvisionOption compendium() {
@@ -453,11 +464,12 @@
return
wrappedBundle(mavenBundle().groupId("servletapi").artifactId("servletapi")).exports(javaxServlet,
javaxServletHttp);
}
-
+
protected void waitForURL(String url, int status) throws
MalformedURLException, IOException {
if (!ConfigProvider.waitForURL(new URL(url), status, HTTP_TIMEOUT)) {
int responseCode = ConfigProvider.checkURL(new URL(url));
- throw new IllegalArgumentException("Timeout occurred waiting for
'" + url + "' to come available, response code=" + responseCode);
+ throw new IllegalArgumentException("Timeout occurred waiting for
'" + url
+ + "' to come available, response code=" + responseCode);
}
}
}
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
Wed Dec 15 12:19:44 2010
@@ -35,6 +35,7 @@
import org.amdatu.authentication.oauth.api.OAuthServiceProvider;
import org.amdatu.authentication.oauth.server.OAuthRequestTokenServlet;
import org.amdatu.authentication.oauth.server.OAuthTokenProvider;
+import org.amdatu.authentication.tokenprovider.TokenProvider;
import org.amdatu.authorization.login.service.LoginService;
import org.amdatu.test.integration.mock.OAuthProtectedTestServlet;
import org.apache.commons.httpclient.Header;
@@ -128,6 +129,8 @@
amdatuHttpContext(),
amdatuJaxRs(),
amdatuWink(),
+ amdatuTokenProvider(),
+ amdatuMemTokenStore(),
amdatuOAuthAPI(),
amdatuOAuthClient(),
amdatuOAuthServer(),
@@ -163,7 +166,7 @@
Header cookieHeader = postMethod.getResponseHeader("Set-Cookie");
HeaderElement[] headerElements = cookieHeader.getElements();
for (HeaderElement headerElement : headerElements) {
- if ("jsessionid".equalsIgnoreCase(headerElement.getName())) {
+ if
(TokenProvider.TOKEN_COOKIE_NAME.equalsIgnoreCase(headerElement.getName())) {
m_logService.log(LogService.LOG_DEBUG, "Login service set
cookie header " + headerElement.getName()
+ "=" + headerElement.getValue());
m_cookieHeaderElement = headerElement;
Modified:
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/GadgetManagementServiceTest.java
==============================================================================
---
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/GadgetManagementServiceTest.java
(original)
+++
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/GadgetManagementServiceTest.java
Wed Dec 15 12:19:44 2010
@@ -81,7 +81,9 @@
amdatuWink(),
amdatuLogin(),
amdatuShindig(),
- amdatuGadgetManagement()
+ amdatuGadgetManagement(),
+ amdatuTokenProvider(),
+ amdatuMemTokenStore()
);
}
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
Wed Dec 15 12:19:44 2010
@@ -19,10 +19,6 @@
import static org.amdatu.test.integration.base.ConfigProvider.TEST_USERNAME;
import static
org.amdatu.test.integration.mock.OAuthProtectedTestServlet.OAUTH_TYPE_PARAM;
import static
org.amdatu.test.integration.mock.OAuthProtectedTestServlet.OAUTH_TYPE_THREE_LEGGED;
-
-import java.util.HashMap;
-import java.util.Map;
-
import net.oauth.OAuthAccessor;
import net.oauth.OAuthMessage;
@@ -33,7 +29,6 @@
import org.amdatu.test.integration.base.OAuthTestBase;
import org.amdatu.test.integration.mock.OAuthProtectedTestServlet;
import org.amdatu.test.integration.mock.OAuthTestConsumer;
-import org.apache.commons.httpclient.HeaderElement;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
Modified: trunk/pom.xml
==============================================================================
--- trunk/pom.xml (original)
+++ trunk/pom.xml Wed Dec 15 12:19:44 2010
@@ -28,7 +28,7 @@
-->
<maven.dollar>$</maven.dollar>
<server.hostname>localhost</server.hostname>
- <server.port>3737</server.port>
+ <server.port>8080</server.port>
<server.port.secure>9090</server.port.secure>
<root.directory>./target</root.directory>
<conf.directory>${root.directory}/conf</conf.directory>
Modified: trunk/src/main/resources/conf/felix-config.properties
==============================================================================
--- trunk/src/main/resources/conf/felix-config.properties (original)
+++ trunk/src/main/resources/conf/felix-config.properties Wed Dec 15
12:19:44 2010
@@ -100,27 +100,29 @@
reference:file:amdatu-application/org.amdatu.cassandra.application-${platform.version}.jar
\
reference:file:amdatu-application/org.amdatu.cassandra.listener-${platform.version}.jar
\
reference:file:amdatu-application/org.amdatu.cassandra.persistencemanager-${platform.version}.jar
\
+
reference:file:amdatu-application/org.amdatu.cassandra.tenantstore-${platform.version}.jar
\
+
reference:file:amdatu-application/org.amdatu.cassandra.useradminstore-${platform.version}.jar
\
reference:file:amdatu-core/org.amdatu.core.loghandler-${platform.version}.jar \
reference:file:amdatu-core/org.amdatu.core.tenant-${platform.version}.jar \
reference:file:amdatu-core/org.amdatu.core.config.templates-${platform.version}.jar
\
-
reference:file:amdatu-application/org.amdatu.cassandra.tenantstore-${platform.version}.jar
\
-
reference:file:amdatu-application/org.amdatu.cassandra.useradminstore-${platform.version}.jar
\
reference:file:amdatu-application/org.amdatu.web.rest.jaxrs-${platform.version}.jar
\
reference:file:amdatu-application/org.amdatu.web.rest.wink-${platform.version}.jar
-felix.auto.start.10=reference:file:amdatu-application/org.amdatu.opensocial.shindig-${platform.version}.jar
\
-
reference:file:amdatu-application/org.amdatu.opensocial.profile-${platform.version}.jar
\
+felix.auto.start.10=reference:file:amdatu-application/org.amdatu.authorization.login.gadget-${platform.version}.jar
\
reference:file:amdatu-application/org.amdatu.authorization.login.service-${platform.version}.jar
\
-
reference:file:amdatu-application/org.amdatu.web.httpcontext-${platform.version}.jar
\
-
reference:file:amdatu-application/org.amdatu.semanticweb.sesame-${platform.version}.jar
\
-
reference:file:amdatu-application/org.amdatu.opensocial.dashboard-${platform.version}.jar
\
-
reference:file:amdatu-application/org.amdatu.opensocial.gadgetmanagement-${platform.version}.jar
\
-
reference:file:amdatu-application/org.amdatu.web.jsp-${platform.version}.jar \
-
reference:file:amdatu-application/org.amdatu.semanticweb.sparqlendpoint-${platform.version}.jar
\
-
reference:file:amdatu-application/org.amdatu.authorization.login.gadget-${platform.version}.jar
\
reference:file:amdatu-application/org.amdatu.authentication.oauth.api-${platform.version}.jar
\
reference:file:amdatu-application/org.amdatu.authentication.oauth.client-${platform.version}.jar
\
reference:file:amdatu-application/org.amdatu.authentication.oauth.server-${platform.version}.jar
\
-
reference:file:amdatu-application/org.amdatu.authentication.oauth.consumerregistry-fs-${platform.version}.jar
+
reference:file:amdatu-application/org.amdatu.authentication.oauth.consumerregistry-fs-${platform.version}.jar
\
+
reference:file:amdatu-application/org.amdatu.authentication.tokenprovider-${platform.version}.jar
\
+
reference:file:amdatu-application/org.amdatu.authentication.tokenstore.mem-${platform.version}.jar
\
+
reference:file:amdatu-application/org.amdatu.web.httpcontext-${platform.version}.jar
\
+
reference:file:amdatu-application/org.amdatu.web.jsp-${platform.version}.jar \
+
reference:file:amdatu-application/org.amdatu.opensocial.dashboard-${platform.version}.jar
\
+
reference:file:amdatu-application/org.amdatu.opensocial.gadgetmanagement-${platform.version}.jar
\
+
reference:file:amdatu-application/org.amdatu.opensocial.profile-${platform.version}.jar
\
+
reference:file:amdatu-application/org.amdatu.opensocial.shindig-${platform.version}.jar
\
+
reference:file:amdatu-application/org.amdatu.semanticweb.sesame-${platform.version}.jar
\
+
reference:file:amdatu-application/org.amdatu.semanticweb.sparqlendpoint-${platform.version}.jar
felix.auto.start.20=reference:file:amdatu-examples/org.amdatu.example.friends.gadget-${platform.version}.jar
\
reference:file:amdatu-examples/org.amdatu.example.course.gadget-${platform.version}.jar
\
reference:file:amdatu-examples/org.amdatu.example.course.service-${platform.version}.jar
\