Author: ivol37 at gmail.com Date: Wed Jan 5 16:00:04 2011 New Revision: 565
Log: First context patch Added: sandbox/ivol/ sandbox/ivol/r564-context-patch.patch Added: sandbox/ivol/r564-context-patch.patch ============================================================================== --- (empty file) +++ sandbox/ivol/r564-context-patch.patch Wed Jan 5 16:00:04 2011 @@ -0,0 +1,3280 @@ +Index: amdatu-authentication/contextmanager/pom.xml +=================================================================== +--- amdatu-authentication/contextmanager/pom.xml (revision 0) ++++ amdatu-authentication/contextmanager/pom.xml (revision 0) +@@ -0,0 +1,31 @@ ++<?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</groupId> ++ <artifactId>contextmanager</artifactId> ++ <packaging>bundle</packaging> ++ <name>Amdatu Authentication - Context manager</name> ++ <description>This bundle provides a generic pluggable context manager</description> ++ ++ <build> ++ <plugins> ++ <plugin> ++ <groupId>org.apache.felix</groupId> ++ <artifactId>maven-bundle-plugin</artifactId> ++ <configuration> ++ <instructions> ++ <Bundle-Activator>org.amdatu.authentication.contextmanager.osgi.Activator</Bundle-Activator> ++ <Bundle-SymbolicName>org.amdatu.authentication.contextmanager</Bundle-SymbolicName> ++ <Export-Package>org.amdatu.authentication.contextmanager</Export-Package> ++ </instructions> ++ </configuration> ++ </plugin> ++ </plugins> ++ </build> ++</project> +Index: amdatu-authentication/contextmanager/src/main/java/org/amdatu/authentication/contextmanager/ContextManager.java +=================================================================== +--- amdatu-authentication/contextmanager/src/main/java/org/amdatu/authentication/contextmanager/ContextManager.java (revision 0) ++++ amdatu-authentication/contextmanager/src/main/java/org/amdatu/authentication/contextmanager/ContextManager.java (revision 0) +@@ -0,0 +1,51 @@ ++/* ++ 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.contextmanager; ++ ++import java.util.Map; ++ ++/** ++ * The Context Manager is responsible for managing context providers. It keeps a list of all available ++ * context providers. It will only add providers to this registry when their ID has not been added yet; ++ * each context provider MUST have a unique identifier identifying itself. ++ * The context manager provides methods to retrieve properties from the context and to resolve context ++ * information from any property (i.e. a HTTP request). The context manager in fact just delegates these calls ++ * to the available context providers. ++ * ++ * @author ivol ++ */ ++public interface ContextManager { ++ /** ++ * Retrieves a value from a context. ++ * @param providerId The id of the provider to retrieve the value from. ++ * @param property The name of the property to retrieve ++ * @return The value of the context property retrieved from the specified provider, null if the property ++ * could not be found or is not availble. ++ * @throws UnknownProviderException In case no provider is available in the provider registry that matches ++ * the specified identifier. ++ */ ++ String getValue(String providerId, String property) throws UnknownProviderException; ++ ++ /** ++ * Resolves context(s) from the specified map of properties. This method will be delegated to each ++ * available context provider. The map of properties may contain any arbitrary property. Default ++ * properties that may be available are covered by ContextProvider (i.e. ContextProvider.PROPERTY_HTTP_REQUEST). ++ * @param context A map of arbitrary properties that may resolve to certain contextual information in ++ * available context providers. ++ */ ++ void resolve(Map<String, Object> properties); ++} +Index: amdatu-authentication/contextmanager/src/main/java/org/amdatu/authentication/contextmanager/ContextProvider.java +=================================================================== +--- amdatu-authentication/contextmanager/src/main/java/org/amdatu/authentication/contextmanager/ContextProvider.java (revision 0) ++++ amdatu-authentication/contextmanager/src/main/java/org/amdatu/authentication/contextmanager/ContextProvider.java (revision 0) +@@ -0,0 +1,60 @@ ++/* ++ 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.contextmanager; ++ ++import java.util.Map; ++ ++/** ++ * A context provider represents one specific piece of the overall context. It is responsible for ++ * managing that piece of context in terms of retrieving values from it and resolving the context ++ * from a given set of properties. ++ * Context providers are managed by the Context Manager, which keeps a registry of available ++ * context providers. Each context provider MUST have a unique identifier (returned by getId()). The ++ * set of available properties in this context is up to the implementation as well as resolving ++ * the context properties from a set of arbitrary properties. ++ * @author ivol ++ */ ++public interface ContextProvider { ++ /** ++ * Name of a context resolver property holding a HTTP request. ++ */ ++ String PROPERTY_HTTP_REQUEST = "httprequest"; ++ ++ /** ++ * Returns the unique identifier of this context provider. If multiple context provider try to ++ * claim the same identifier, one of them will not be registered in the ContextManager ++ * and will this be unusable. ++ * @return The unique identifier of this context provider. ++ */ ++ String getId(); ++ ++ /** ++ * Returns a value managed by this context provider. ++ * @param propertyName Name of the property to retrieve ++ * @return The value of this property or null if no such property exists ++ */ ++ String getValue(String propertyName); ++ ++ /** ++ * Invoked to allow the context provider to resolve a given set of arbitrary properties to ++ * a certain context. The map contains an arbitrary set of properties, but a default list of ++ * properties that may be available is covered by this interface (i.e. PROPERTY_HTTP_REQUEST). ++ * @param properties Map of arbitrary properties which could be resolved to a context by ++ * this context provider. ++ */ ++ void resolve(Map<String, Object> properties); ++} +Index: amdatu-authentication/contextmanager/src/main/java/org/amdatu/authentication/contextmanager/osgi/Activator.java +=================================================================== +--- amdatu-authentication/contextmanager/src/main/java/org/amdatu/authentication/contextmanager/osgi/Activator.java (revision 0) ++++ amdatu-authentication/contextmanager/src/main/java/org/amdatu/authentication/contextmanager/osgi/Activator.java (revision 0) +@@ -0,0 +1,43 @@ ++/* ++ 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.contextmanager.osgi; ++ ++import org.amdatu.authentication.contextmanager.ContextManager; ++import org.amdatu.authentication.contextmanager.ContextProvider; ++import org.amdatu.authentication.contextmanager.service.ContextManagerImpl; ++import org.apache.felix.dm.DependencyActivatorBase; ++import org.apache.felix.dm.DependencyManager; ++import org.osgi.framework.BundleContext; ++ ++/** ++ * This is the activator for the context manager bundle ++ * @author ivol ++ */ ++public class Activator extends DependencyActivatorBase { ++ @Override ++ public void init(BundleContext context, DependencyManager manager) throws Exception { ++ // Register the ContextManager service ++ manager.add(createComponent() ++ .setInterface(ContextManager.class.getName(), null) ++ .setImplementation(ContextManagerImpl.class) ++ .add(createServiceDependency().setService(ContextProvider.class).setCallbacks("onAdded", "onRemoved"))); ++ } ++ ++ @Override ++ public void destroy(BundleContext bundleContext, DependencyManager dependencyManager) throws Exception { ++ } ++} +Index: amdatu-authentication/contextmanager/src/main/java/org/amdatu/authentication/contextmanager/service/ContextManagerImpl.java +=================================================================== +--- amdatu-authentication/contextmanager/src/main/java/org/amdatu/authentication/contextmanager/service/ContextManagerImpl.java (revision 0) ++++ amdatu-authentication/contextmanager/src/main/java/org/amdatu/authentication/contextmanager/service/ContextManagerImpl.java (revision 0) +@@ -0,0 +1,100 @@ ++/* ++ 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.contextmanager.service; ++ ++import java.util.ArrayList; ++import java.util.List; ++import java.util.Map; ++ ++import org.amdatu.authentication.contextmanager.ContextManager; ++import org.amdatu.authentication.contextmanager.ContextProvider; ++import org.amdatu.authentication.contextmanager.UnknownProviderException; ++import org.osgi.framework.ServiceReference; ++ ++/** ++ * This class implements the ContextManager. ++ * ++ * @author ivol ++ */ ++public class ContextManagerImpl implements ContextManager { ++ // List of available context providers. ++ private List<ContextProvider> m_contextProviders = new ArrayList<ContextProvider>(); ++ ++ // Invoked when a service provider comes available ++ public void onAdded(ServiceReference ref, Object service) { ++ if (service instanceof ContextProvider) { ++ addContextProvider((ContextProvider) service); ++ } ++ } ++ ++ // Invoked when a service provider comes unavailable ++ public void onRemoved(ServiceReference ref, Object service) { ++ if (service instanceof ContextProvider) { ++ removeContextProvider((ContextProvider) service); ++ } ++ } ++ ++ // Adds a context provider to the registry, but only if no provider is available that ++ // mtaches the id of the context provider to be added. ++ private void addContextProvider(ContextProvider contextProvider) { ++ if (contextProvider.getId() == null || contextProvider.getId().trim().isEmpty()) { ++ // Reject context providers with empty id ++ return; ++ } ++ if (getContextProvider(contextProvider.getId()) != null) { ++ // Reject adding context providers that already exist with this id ++ return; ++ } ++ m_contextProviders.add(contextProvider); ++ } ++ ++ // Removed the context provider from the registry ++ private void removeContextProvider(ContextProvider contextProvider) { ++ ContextProvider provider = getContextProvider(contextProvider.getId()); ++ if (provider != null) { ++ m_contextProviders.remove(provider); ++ return; ++ } ++ } ++ ++ // Returns a context provider that matches the specified id ++ private ContextProvider getContextProvider(String id) { ++ for (ContextProvider provider : m_contextProviders) { ++ if (provider.getId().equals(id)) { ++ return provider; ++ } ++ } ++ return null; ++ } ++ ++ // Returns the value from the specified property from the specified provider ++ public String getValue(String providerId, String property) throws UnknownProviderException { ++ ContextProvider provider = getContextProvider(providerId); ++ if (provider != null) { ++ return provider.getValue(property); ++ } else { ++ throw new UnknownProviderException("Provider '" + providerId + "' is not available"); ++ } ++ } ++ ++ // Resolve contexts; just delegate to all available context providers ++ public void resolve(Map<String, Object> context) { ++ for (ContextProvider provider : m_contextProviders) { ++ provider.resolve(context); ++ } ++ } ++} +Index: amdatu-authentication/contextmanager/src/main/java/org/amdatu/authentication/contextmanager/UnknownProviderException.java +=================================================================== +--- amdatu-authentication/contextmanager/src/main/java/org/amdatu/authentication/contextmanager/UnknownProviderException.java (revision 0) ++++ amdatu-authentication/contextmanager/src/main/java/org/amdatu/authentication/contextmanager/UnknownProviderException.java (revision 0) +@@ -0,0 +1,48 @@ ++/* ++ 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.contextmanager; ++ ++/** ++ * Exception thrown by the ContextManager in case a property is requested from a provider id that ++ * is not available. ++ * ++ * @author ivol ++ */ ++public class UnknownProviderException extends Exception { ++ /** ++ * Serial version UID of this class. ++ */ ++ private static final long serialVersionUID = -5721742545697762926L; ++ ++ /** ++ * Constructs a UnknownProviderException. ++ * ++ * @param msg An error message providing more information about the cause of the error. ++ */ ++ public UnknownProviderException(String msg) { ++ super(msg); ++ } ++ ++ /** ++ * Constructs a new UnknownProviderException. ++ * ++ * @param t An exception providing more information about the cause of the error. ++ */ ++ public UnknownProviderException(Throwable t) { ++ super(t); ++ } ++} +\ No newline at end of file +Index: amdatu-authentication/oauth-server/pom.xml +=================================================================== +--- amdatu-authentication/oauth-server/pom.xml (revision 564) ++++ amdatu-authentication/oauth-server/pom.xml (working copy) +@@ -12,7 +12,7 @@ + <packaging>bundle</packaging> + <name>Amdatu Authentication - oAuth server</name> + <description>This bundle includes an API for oAuth service providers</description> +- ++ + <dependencies> + <dependency> + <groupId>org.amdatu.web</groupId> +@@ -31,7 +31,7 @@ + <dependency> + <groupId>org.amdatu.authentication.oauth</groupId> + <artifactId>api</artifactId> +- <version>${platform.version}</version> ++ <version>${platform.version}</version> + <scope>provided</scope> + <type>bundle</type> + </dependency> +@@ -77,9 +77,23 @@ + <artifactId>tokenprovider</artifactId> + <version>${platform.version}</version> + <scope>provided</scope> +- </dependency> ++ </dependency> ++ <dependency> ++ <groupId>org.amdatu.authentication</groupId> ++ <artifactId>contextmanager</artifactId> ++ <version>${platform.version}</version> ++ <scope>provided</scope> ++ <type>bundle</type> ++ </dependency> ++ <dependency> ++ <groupId>org.amdatu.authorization.login</groupId> ++ <artifactId>service</artifactId> ++ <version>${platform.version}</version> ++ <scope>provided</scope> ++ <type>bundle</type> ++ </dependency> + </dependencies> +- ++ + <build> + <plugins> + <plugin> +@@ -100,5 +114,5 @@ + </configuration> + </plugin> + </plugins> +- </build> ++ </build> + </project> +Index: amdatu-authentication/oauth-server/src/main/java/org/amdatu/authentication/oauth/server/service/OAuthAuthorizeTokenServletImpl.java +=================================================================== +--- amdatu-authentication/oauth-server/src/main/java/org/amdatu/authentication/oauth/server/service/OAuthAuthorizeTokenServletImpl.java (revision 564) ++++ amdatu-authentication/oauth-server/src/main/java/org/amdatu/authentication/oauth/server/service/OAuthAuthorizeTokenServletImpl.java (working copy) +@@ -18,11 +18,9 @@ + + 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; +@@ -37,27 +35,26 @@ + import org.amdatu.authentication.oauth.api.OAuthServiceProvider; + import org.amdatu.authentication.oauth.server.OAuthAuthorizeTokenServlet; + import org.amdatu.authentication.oauth.server.OAuthTokenProvider; +-import org.amdatu.authentication.tokenprovider.InvalidTokenException; +-import org.amdatu.authentication.tokenprovider.TokenProvider; +-import org.amdatu.authentication.tokenprovider.TokenProviderException; ++import org.amdatu.authentication.contextmanager.ContextManager; ++import org.amdatu.authorization.login.service.LoginContextProvider; + import org.osgi.service.log.LogService; + + public class OAuthAuthorizeTokenServletImpl extends HttpServlet implements OAuthAuthorizeTokenServlet { + // The serial version UID of this servlet + private static final long serialVersionUID = -3589350956712947896L; +- ++ + // Service dependencies, injected by the Felix dependency manager + private volatile LogService m_logService; +- private volatile TokenProvider m_tokenProvider; + private volatile OAuthTokenProvider m_oAuthTokenProvider; + private volatile OAuthServiceProvider m_serviceProvider; +- ++ private volatile ContextManager m_contextManager; ++ + public void init(ServletConfig config) throws ServletException { + super.init(config); + } + + public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { +- try { ++ try { + OAuthMessage requestMessage = OAuthServlet.getMessage(request, null); + OAuthAccessor accessor = m_oAuthTokenProvider.getAccessor(requestMessage); + if (Boolean.TRUE.equals(accessor.getProperty("authorized"))) { +@@ -80,7 +77,7 @@ + try { + OAuthMessage requestMessage = OAuthServlet.getMessage(request, null); + OAuthAccessor accessor = m_oAuthTokenProvider.getAccessor(requestMessage); +- String userId = getUserId(request); ++ String userId = m_contextManager.getValue(LoginContextProvider.ID, LoginContextProvider.USERNAME); + if (userId == null) { + // If there is no userid available now, we throw a permission denied as it won't happen in a normal situation! + // Maybe it's a hack attempt. +@@ -97,7 +94,7 @@ + } + + private void sendToAuthorizePage(HttpServletRequest request, HttpServletResponse response, OAuthAccessor accessor) +- throws IOException, ServletException { ++ throws IOException, ServletException { + String callback = request.getParameter("oauth_callback"); + if (callback == null || callback.length() <= 0) { + callback = "none"; +@@ -108,26 +105,26 @@ + request.setAttribute("TOKEN", accessor.requestToken); + m_logService.log(LogService.LOG_DEBUG, "Forwarding authorize token request to " + m_serviceProvider.getAuthorizeURL() + + ", token=" + accessor.requestToken + ", callback=" + callback); +- ++ + // Create a request wrapper returning the path of the JSP servlet instead of this servlet + HttpServletRequestWrapper wrapper = new HttpServletRequestWrapper(request) { + public String getPathInfo() { + return m_serviceProvider.getAuthorizeURL(); + } + }; +- ++ + // Dispatch the request to the authorize JSP + request.getRequestDispatcher(m_serviceProvider.getAuthorizeURL()).forward(wrapper, response); + } + + private void returnToConsumer(HttpServletRequest request, + HttpServletResponse response, OAuthAccessor accessor) +- throws IOException, ServletException { ++ throws IOException, ServletException { + // send the user back to site's callBackUrl + String callback = request.getParameter("oauth_callback"); + if ("none".equals(callback) +- && accessor.consumer.callbackURL != null +- && accessor.consumer.callbackURL.length() > 0) { ++ && accessor.consumer.callbackURL != null ++ && accessor.consumer.callbackURL.length() > 0) { + // first check if we have something in our properties file + callback = accessor.consumer.callbackURL; + } +@@ -144,8 +141,9 @@ + } + else { + // if callback is not passed in, use the callback from config +- if (callback == null || callback.length() <= 0) ++ if (callback == null || callback.length() <= 0) { + callback = accessor.consumer.callbackURL; ++ } + String token = accessor.requestToken; + if (token != null) { + callback = OAuth.addParameters(callback, "oauth_token", token); +@@ -155,15 +153,4 @@ + response.setHeader("Location", callback); + } + } +- +- 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; +- } +- } + } +Index: amdatu-authentication/pom.xml +=================================================================== +--- amdatu-authentication/pom.xml (revision 564) ++++ amdatu-authentication/pom.xml (working copy) +@@ -11,21 +11,22 @@ + <name>Amdatu Authentication</name> + <description>This module consists of all Authentication related bundles</description> + <packaging>pom</packaging> +- ++ + <dependencies> + <dependency> + <groupId>servletapi</groupId> + <artifactId>servletapi</artifactId> + <version>2.4</version> + <scope>provided</scope> +- </dependency> ++ </dependency> + </dependencies> +- ++ + <modules> + <module>oauth-api</module> + <module>oauth-client</module> + <module>oauth-server</module> + <module>oauth-consumerregistry-fs</module> ++ <module>contextmanager</module> + <module>tokenprovider</module> + <module>tokenstore-mem</module> + </modules> +Index: amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/osgi/Activator.java +=================================================================== +--- amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/osgi/Activator.java (revision 564) ++++ amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/osgi/Activator.java (working copy) +@@ -46,7 +46,7 @@ + .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. ++ // 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( +@@ -54,11 +54,11 @@ + .setInterface(TokenRESTResource.class.getName(), null) + .setImplementation(TokenRESTResourceImpl.class) + .add(createServiceDependency().setService(LogService.class).setRequired(true)) +- .add(createServiceDependency().setService(TokenProvider.class).setRequired(true))); */ ++ .add(createServiceDependency().setService(TokenProvider.class).setRequired(true))); */ + } + + @Override + public void destroy(BundleContext bundleContext, DependencyManager dependencyManager) throws Exception { + } +- ++ + } +Index: amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/service/TokenProviderImpl.java +=================================================================== +--- amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/service/TokenProviderImpl.java (revision 564) ++++ amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/service/TokenProviderImpl.java (working copy) +@@ -30,8 +30,6 @@ + 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; +@@ -43,9 +41,6 @@ + import org.osgi.service.log.LogService; + + public class TokenProviderImpl implements TokenProvider { +- // Name the authorization header when a token is passed in the "Authorization" header of a HTTP request +- public final static String AUTHORIZATION_HEADER = "Amdatu"; +- + // Service dependencies + private volatile LogService m_logService; + +@@ -251,27 +246,4 @@ + public void invalidateToken(String encryptedToken) { + m_tokenStore.removeToken(encryptedToken); + } +- +- public String getTokenFromRequest(HttpServletRequest request) { +- // Use case 1: The token is send along in a cookie with the request. The cookie is send +- // automatically when a request is send directly from the end users browser to the Amdatu server. +- if (request.getCookies() != null) { +- for (Cookie cookie : request.getCookies()) { +- if (TokenProvider.TOKEN_COOKIE_NAME.equals(cookie.getName())) { +- return cookie.getValue(); +- } +- } +- } +- +- // Use case 2: When requests are not send from a browser (for example calls to gadgets.ui.makeRequest +- // proxied via an openSocial container) the token can be send in the Authorization header (like Basic +- // and Digest HTTP authentication). +- String authHeader = request.getHeader("Authorization"); +- if (authHeader != null && !authHeader.isEmpty()) { +- if (authHeader.startsWith(AUTHORIZATION_HEADER + " ")) { +- return authHeader.substring(authHeader.indexOf(" ") + 1); +- } +- } +- return null; +- } + } +Index: amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/TokenProvider.java +=================================================================== +--- amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/TokenProvider.java (revision 564) ++++ amdatu-authentication/tokenprovider/src/main/java/org/amdatu/authentication/tokenprovider/TokenProvider.java (working copy) +@@ -18,8 +18,6 @@ + + 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 +@@ -49,33 +47,38 @@ + * Name of the cookie that stores an amdatu token. + */ + final String TOKEN_COOKIE_NAME = "amdatu_token"; +- ++ + /** ++ * Name of the authorization header when a token is passed in the "Authorization" header of a HTTP request ++ */ ++ final String TOKEN_AUTHORIZATION_HEADER = "Amdatu"; ++ ++ /** + * 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. ++ * 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 ++ * @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. +@@ -83,7 +86,7 @@ + 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 ++ * 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. +@@ -99,11 +102,4 @@ + * @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); + } +Index: amdatu-authorization/login-service/pom.xml +=================================================================== +--- amdatu-authorization/login-service/pom.xml (revision 564) ++++ amdatu-authorization/login-service/pom.xml (working copy) +@@ -12,15 +12,22 @@ + <packaging>bundle</packaging> + <name>Amdatu Authorization - Login service</name> + <description>Provides a service for login and logout functionality</description> +- +- <dependencies> ++ ++ <dependencies> + <dependency> + <groupId>org.amdatu.web</groupId> + <artifactId>httpcontext</artifactId> + <scope>provided</scope> + <type>bundle</type> +- </dependency> ++ </dependency> + <dependency> ++ <groupId>org.amdatu.authentication</groupId> ++ <artifactId>contextmanager</artifactId> ++ <version>${platform.version}</version> ++ <scope>provided</scope> ++ <type>bundle</type> ++ </dependency> ++ <dependency> + <groupId>org.amdatu.web.rest</groupId> + <artifactId>jaxrs</artifactId> + <version>${platform.version}</version> +@@ -64,6 +71,6 @@ + </plugin> + + </plugins> +- +- </build> ++ ++ </build> + </project> +Index: amdatu-authorization/login-service/src/main/java/org/amdatu/authorization/login/service/LoginContextProvider.java +=================================================================== +--- amdatu-authorization/login-service/src/main/java/org/amdatu/authorization/login/service/LoginContextProvider.java (revision 0) ++++ amdatu-authorization/login-service/src/main/java/org/amdatu/authorization/login/service/LoginContextProvider.java (revision 0) +@@ -0,0 +1,39 @@ ++/* ++ 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.authorization.login.service; ++ ++import org.amdatu.authentication.contextmanager.ContextProvider; ++ ++public interface LoginContextProvider extends ContextProvider { ++ /** ++ * Id of the login context provider. ++ */ ++ String ID = "org.amdatu.authorization.login.contextprovider"; ++ ++ /** ++ * Name of the username property in this context. The username represents a user authenticated ++ * against a User in UserAdmin. ++ */ ++ String USERNAME = "username"; ++ ++ /** ++ * Name of the user token property in this context. Each user that is logged in in Amdatu will ++ * be associated with this token. The token contains an arbitrary map of information, decryptable ++ * from the token. As such, the token holds non-persistent state information. ++ */ ++ String USER_TOKEN = "token"; ++} +Index: amdatu-authorization/login-service/src/main/java/org/amdatu/authorization/login/service/LoginService.java +=================================================================== +--- amdatu-authorization/login-service/src/main/java/org/amdatu/authorization/login/service/LoginService.java (revision 564) ++++ amdatu-authorization/login-service/src/main/java/org/amdatu/authorization/login/service/LoginService.java (working copy) +@@ -16,12 +16,16 @@ + */ + package org.amdatu.authorization.login.service; + +-import javax.ws.rs.core.Response; +-import javax.servlet.http.HttpServletRequest; ++import java.util.SortedMap; + ++import javax.security.auth.login.LoginException; + + /** +- * This interface defines the authorization service. ++ * The login service is responsible for verifying user credentials against those stored in UserAdmin. ++ * It provides login and logout methods. Upon successful login, the information about the fact that ++ * this user logged in successfully is written to the login context. Upon logout, this information ++ * is removed from the context. ++ * + * @author ivol + */ + public interface LoginService { +@@ -34,40 +38,37 @@ + * Key under which the password is stored in the credentials of the User. + */ + String PASSWORD_CREDENTIAL_KEY = "password"; +- ++ + /** +- * NB: Do NOT use this method since it will be removed from future versions. For more information, +- * see http://jira.amdatu.org/jira/browse/AMDATU-166. +- * +- * Shows the login status of the user. +- * @param request The current httprequest +- * @return Response the username of the current user is logged in or an +- * empty string if the user is not logged in. ++ * Verifies use credentials against those stored in UserAdmin. If the logion fails for any reason, ++ * a LoginException is thrown. If the login was successful, this information is added to the login ++ * context. ++ * @param username Username of the user to login ++ * @param password Password credential of this user ++ * @throws LoginException in case login failed for any reason. This may be an invalid username, invalid ++ * password or any other internal error + */ +- @Deprecated +- public Response getLoginStatus(HttpServletRequest request); +- ++ void login(String username, String password) throws LoginException; ++ + /** +- * NB: Do NOT use this method since it will be removed from future versions. For more information, +- * see http://jira.amdatu.org/jira/browse/AMDATU-166. +- * +- * Enables the user login with a username and password. +- * @param username The username +- * @param password The plain text password +- * @param request The current httprequest +- * @return Response The result of the login. ++ * Verifies use credentials against those stored in UserAdmin. If the logion fails for any reason, ++ * a LoginException is thrown. If the login was successful, this information is added to the login ++ * context. Additional login attributes can be passed, which will be added to the generated ++ * Amdatu token in the login context. This information will this be available in the login context ++ * by subsequent invocations accessing the login context. ++ * @param username Username of the user to login ++ * @param password Password credential of this user ++ * @param attributes Sorted map of additional attributes which will be added to the generated Amdatu ++ * token, and therefore will also be available in the login context (as the Amdatu token is stored in ++ * the login context). ++ * @throws LoginException in case login failed for any reason. This may be an invalid username, invalid ++ * password or any other internal error + */ +- @Deprecated +- public Response login(String username, String password, HttpServletRequest request); ++ void login(String username, String password, SortedMap<String, String> attributes) throws LoginException; + + /** +- * NB: Do NOT use this method since it will be removed from future versions. For more information, +- * see http://jira.amdatu.org/jira/browse/AMDATU-166. +- * +- * Enables the user logout. +- * @param request The current httprequest +- * @return Response The result of the logout. ++ * Logs out the user in the current login context, if a current (logged in) user is available in the ++ * current login context. If no current user is available in the current context this method does nothing. + */ +- @Deprecated +- public Response logout(HttpServletRequest request); ++ void logout(); + } +\ No newline at end of file +Index: amdatu-authorization/login-service/src/main/java/org/amdatu/authorization/login/service/osgi/Activator.java +=================================================================== +--- amdatu-authorization/login-service/src/main/java/org/amdatu/authorization/login/service/osgi/Activator.java (revision 564) ++++ amdatu-authorization/login-service/src/main/java/org/amdatu/authorization/login/service/osgi/Activator.java (working copy) +@@ -16,11 +16,15 @@ + */ + package org.amdatu.authorization.login.service.osgi; + ++import org.amdatu.authentication.contextmanager.ContextManager; + import org.amdatu.authentication.tokenprovider.TokenProvider; ++import org.amdatu.authorization.login.service.LoginContextProvider; + import org.amdatu.authorization.login.service.LoginService; ++import org.amdatu.authorization.login.service.service.LoginRESTServiceImpl; + import org.amdatu.authorization.login.service.service.LoginServiceImpl; + import org.amdatu.libraries.utilities.osgi.ServiceDependentActivator; + import org.amdatu.web.httpcontext.HttpContextServiceFactory; ++import org.amdatu.web.httpcontext.ResourceProvider; + import org.amdatu.web.rest.jaxrs.JaxRsSpi; + import org.apache.felix.dm.DependencyManager; + import org.osgi.framework.BundleContext; +@@ -43,21 +47,29 @@ + + @Override + public void initWithDependencies(BundleContext context, DependencyManager manager) throws Exception { +- // Create and register the authorization service. ++ // Create and register the login service. + manager.add( +- createComponent() +- .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))); +- +- ++ createComponent() ++ .setInterface(LoginService.class.getName(), null) ++ .setImplementation(LoginServiceImpl.class) ++ .add(createServiceDependency().setService(TokenProvider.class).setRequired(true)) ++ .add(createServiceDependency().setService(LogService.class).setRequired(true)) ++ .add(createServiceDependency().setService(UserAdmin.class).setRequired(true))); ++ ++ // Create and register the login REST API. ++ manager.add( ++ createComponent() ++ .setInterface(ResourceProvider.class.getName(), null) ++ .setImplementation(LoginRESTServiceImpl.class) ++ .add(createServiceDependency().setService(HttpContextServiceFactory.class).setRequired(true)) ++ .add(createServiceDependency().setService(LoginService.class).setRequired(true)) ++ .add(createServiceDependency().setService(LoginContextProvider.class).setRequired(true)) ++ .add(createServiceDependency().setService(ContextManager.class).setRequired(true)) ++ .add(createServiceDependency().setService(LogService.class).setRequired(true))); + } + + @Override + public void destroy(BundleContext bundleContext, DependencyManager dependencyManager) throws Exception { + } +- ++ + } +Index: amdatu-authorization/login-service/src/main/java/org/amdatu/authorization/login/service/service/LoginContextProviderImpl.java +=================================================================== +--- amdatu-authorization/login-service/src/main/java/org/amdatu/authorization/login/service/service/LoginContextProviderImpl.java (revision 0) ++++ amdatu-authorization/login-service/src/main/java/org/amdatu/authorization/login/service/service/LoginContextProviderImpl.java (revision 0) +@@ -0,0 +1,132 @@ ++/* ++ 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.authorization.login.service.service; ++ ++import java.util.HashMap; ++import java.util.Map; ++import java.util.SortedMap; ++ ++import javax.servlet.http.Cookie; ++import javax.servlet.http.HttpServletRequest; ++ ++import org.amdatu.authentication.contextmanager.ContextProvider; ++import org.amdatu.authentication.tokenprovider.InvalidTokenException; ++import org.amdatu.authentication.tokenprovider.TokenProvider; ++import org.amdatu.authentication.tokenprovider.TokenProviderException; ++import org.amdatu.authorization.login.service.LoginContextProvider; ++import org.osgi.service.log.LogService; ++ ++/** ++ * Implements a login context provider. The login context provider provides login related context information; ++ * the username of the user currently logged in and the Amdatu token distributed to that user to authenticate itself ++ * in subsequent requests. ++ * ++ * @author ivol ++ */ ++public class LoginContextProviderImpl implements LoginContextProvider { ++ // Login context information is bound to a ThreadLocal variable. ++ private static ThreadLocal<Map<String, String>> m_properties = new ThreadLocal<Map<String, String>>(); ++ ++ // Service dependencies injected by the dependency manager ++ private volatile TokenProvider m_tokenProvider; ++ private volatile LogService m_logService; ++ ++ public String getId() { ++ return LoginContextProvider.ID; ++ } ++ ++ public String getValue(String propertyName) { ++ if (m_properties.get() != null) { ++ return m_properties.get().get(propertyName); ++ } else { ++ return null; ++ } ++ } ++ ++ private void setValue(String propertyName, String value) { ++ if (m_properties.get() == null) { ++ m_properties.set(new HashMap<String, String>()); ++ } ++ if (value != null) { ++ m_properties.get().put(propertyName, value); ++ } else if ( m_properties.get().containsKey(propertyName)){ ++ m_properties.get().remove(propertyName); ++ } ++ } ++ ++ void setUsername(String username) { ++ setValue(LoginContextProvider.USERNAME, username); ++ } ++ ++ void setToken(String token) { ++ setValue(LoginContextProvider.USER_TOKEN, token); ++ } ++ ++ public void reset() { ++ m_properties = new ThreadLocal<Map<String, String>>(); ++ } ++ ++ // Resolve a map of arbitrary context resolve properties to this context. ++ public void resolve(Map<String, Object> properties) { ++ // Check if the HTTP request is one of the context resolver properties, in which case we can resolve the ++ // login context from the amdatu token (if available). ++ if (properties.containsKey(ContextProvider.PROPERTY_HTTP_REQUEST)) { ++ HttpServletRequest request = (HttpServletRequest) properties.get(ContextProvider.PROPERTY_HTTP_REQUEST); ++ String amdatuToken = getAmdatuTokenFromRequest(request); ++ if (amdatuToken != null) { ++ setToken(amdatuToken); ++ try { ++ SortedMap<String, String> tokenProperties = m_tokenProvider.verifyToken(amdatuToken); ++ if (tokenProperties != null) { ++ if (tokenProperties.containsKey(TokenProvider.USERNAME)) { ++ setUsername(tokenProperties.get(TokenProvider.USERNAME)); ++ } ++ } ++ } ++ catch (TokenProviderException e) { ++ m_logService.log(LogService.LOG_ERROR, "An error occured while verifying token '" + amdatuToken + "'", e); ++ } ++ catch (InvalidTokenException e) { ++ // Invalid token, log nothing ++ } ++ } ++ } ++ } ++ ++ private String getAmdatuTokenFromRequest(HttpServletRequest request) { ++ // Use case 1: The token is send along in a cookie with the request. The cookie is send ++ // automatically when a request is send directly from the end users browser to the Amdatu server. ++ if (request.getCookies() != null) { ++ for (Cookie cookie : request.getCookies()) { ++ if (TokenProvider.TOKEN_COOKIE_NAME.equals(cookie.getName())) { ++ return cookie.getValue(); ++ } ++ } ++ } ++ ++ // Use case 2: When requests are not send from a browser (for example calls to gadgets.ui.makeRequest ++ // proxied via an openSocial container) the token can be send in the Authorization header (like Basic ++ // and Digest HTTP authentication). ++ String authHeader = request.getHeader("Authorization"); ++ if (authHeader != null && !authHeader.isEmpty()) { ++ if (authHeader.startsWith(TokenProvider.TOKEN_AUTHORIZATION_HEADER + " ")) { ++ return authHeader.substring(authHeader.indexOf(" ") + 1); ++ } ++ } ++ return null; ++ } ++} +Index: amdatu-authorization/login-service/src/main/java/org/amdatu/authorization/login/service/service/LoginRESTServiceImpl.java +=================================================================== +--- amdatu-authorization/login-service/src/main/java/org/amdatu/authorization/login/service/service/LoginRESTServiceImpl.java (revision 548) ++++ amdatu-authorization/login-service/src/main/java/org/amdatu/authorization/login/service/service/LoginRESTServiceImpl.java (working copy) +@@ -17,10 +17,10 @@ + 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.security.auth.login.LoginException; + import javax.servlet.http.HttpServletRequest; + import javax.servlet.http.HttpServletResponse; + import javax.ws.rs.Consumes; +@@ -37,9 +37,8 @@ + 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.LoginContextProvider; + import org.amdatu.authorization.login.service.LoginService; + import org.amdatu.authorization.login.service.osgi.Activator; + import org.amdatu.web.httpcontext.HttpContextServiceFactory; +@@ -49,10 +48,6 @@ + import org.json.JSONObject; + import org.osgi.framework.BundleContext; + import org.osgi.service.log.LogService; +-import org.osgi.service.useradmin.Group; +-import org.osgi.service.useradmin.Role; +-import org.osgi.service.useradmin.User; +-import org.osgi.service.useradmin.UserAdmin; + + /** + * This service is responsible for authorization handling, based on the UserAdmin OSGi service. +@@ -60,18 +55,13 @@ + * @author ivol + */ + @Path("authorization") +-public class LoginServiceImpl implements ResourceProvider, LoginService { +- // Default Administrator user credentials +- private static final String DEFAULT_USERNAME = "Administrator"; +- private static final String DEFAULT_PASSWORD = "Administrator"; +- private static final String DEFAULT_ADMIN_GROUP = "Administrators"; +- ++public class LoginRESTServiceImpl implements ResourceProvider { + // Service dependencies, injected by the Felix dependency manager + private volatile LogService m_logService; + private volatile BundleContext m_bundleContext; + private volatile HttpContextServiceFactory m_httpContextServiceFactory; +- private volatile UserAdmin m_userAdmin; +- private volatile TokenProvider m_tokenProvider; ++ private volatile LoginService m_loginService; ++ private volatile LoginContextProvider m_loginContext; + + // The private HTTP context service for this bundle + private Component m_httpContextComponent; +@@ -90,26 +80,11 @@ + // Create our own http context service which registers static resources and JSPs automatically + m_httpContextComponent = m_httpContextServiceFactory.create(m_bundleContext, this); + ++ // Register our LoginContext provider ++ + m_logService.log(LogService.LOG_INFO, getClass().getName() + " service initialized"); + } + +- @SuppressWarnings("unchecked") +- public void start() { +- // If we don't have a user named 'Administrator', we create one now. +- if (m_userAdmin.getRole(DEFAULT_USERNAME) == null) { +- User adminUser = (User) m_userAdmin.createRole(DEFAULT_USERNAME, Role.USER); +- if (adminUser != null) { +- adminUser.getCredentials().put(PASSWORD_CREDENTIAL_KEY, DEFAULT_PASSWORD); +- adminUser.getProperties().put(USER_NAME_CREDENTIAL_KEY, DEFAULT_USERNAME); +- Group adminGroup = (Group) m_userAdmin.createRole(DEFAULT_ADMIN_GROUP, Role.GROUP); +- adminGroup.addMember(adminUser); +- } +- else { +- m_logService.log(LogService.LOG_ERROR, "Failed to create initial user " + DEFAULT_USERNAME); +- } +- } +- } +- + // The destroy() method is automatically invoked by the Felix dependency manager + public void destroy() { + // Stop the HTTP context service we created ourselves +@@ -135,28 +110,18 @@ + @Path("status") + @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 +- // session info in the container. Note that we use our own http session implementation +- // because of issue AMDATU-67. + JSONObject jsonObject = new JSONObject(); + try { +- String userName = getUserName(request); ++ String userName = m_loginContext.getValue(LoginContextProvider.USERNAME); + if (userName != null) { + jsonObject.append("username", userName); + return Response.ok(jsonObject.toString(), MediaType.APPLICATION_JSON_TYPE).cacheControl(m_cacheControl) +- .build(); ++ .build(); + } + } + 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(); + } + +@@ -175,28 +140,22 @@ + 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)) { +- // 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); ++ try { ++ // Login with specified username and password. If login fails, an exception is thrown. ++ // Add the IP address of this request to the login context ++ SortedMap<String, String> attributes = new TreeMap<String, String>(); ++ attributes.put("ip", request.getRemoteAddr()); ++ m_loginService.login(username, password, attributes); + +- 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, "Incorrect password provided for user '" + username + "'"); +- jsonObject.append("result", "failed"); +- jsonObject.append("msg", "Password is incorrect"); +- } ++ // Now write the login token to a Set-Cookie header ++ String token = m_loginContext.getValue(LoginContextProvider.USER_TOKEN); ++ cookie = new NewCookie(TokenProvider.TOKEN_COOKIE_NAME, token, "/", null, "Amdatu session", -1, false); ++ jsonObject.append("result", "ok"); ++ jsonObject.append("username", username); ++ jsonObject.append("msg", "User '" + username + "' logged in successfully"); + } +- else { +- m_logService.log(LogService.LOG_INFO, "Username '" + username + "' unknown"); ++ catch (LoginException e) { ++ m_logService.log(LogService.LOG_INFO, "Username '" + username + "' unknown and/or password invalid"); + jsonObject.append("result", "failed"); + jsonObject.append("msg", "Username is unknown"); + } +@@ -205,11 +164,6 @@ + m_logService.log(LogService.LOG_ERROR, "Could not retrieve current login status", e); + throw new WebApplicationException(e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } +- 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) { +@@ -227,27 +181,14 @@ + @Path("logout") + @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 { +- userName = getUserName(request); +- invalidateToken(request); +- m_logService.log(LogService.LOG_INFO, "User '" + userName + "' logged out successfully"); ++ m_loginService.logout(); + jsonObject.append("result", "ok"); + } + 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(); + } + +@@ -258,28 +199,4 @@ + 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)); +- } + } +Index: amdatu-authorization/login-service/src/main/java/org/amdatu/authorization/login/service/service/LoginServiceImpl.java +=================================================================== +--- amdatu-authorization/login-service/src/main/java/org/amdatu/authorization/login/service/service/LoginServiceImpl.java (revision 564) ++++ amdatu-authorization/login-service/src/main/java/org/amdatu/authorization/login/service/service/LoginServiceImpl.java (working copy) +@@ -16,51 +16,24 @@ + */ + 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 javax.security.auth.login.LoginException; + +-import org.amdatu.authentication.tokenprovider.InvalidTokenException; ++import org.amdatu.authentication.contextmanager.ContextProvider; + import org.amdatu.authentication.tokenprovider.TokenProvider; + import org.amdatu.authentication.tokenprovider.TokenProviderException; ++import org.amdatu.authorization.login.service.LoginContextProvider; + import org.amdatu.authorization.login.service.LoginService; +-import org.amdatu.authorization.login.service.osgi.Activator; +-import org.amdatu.web.httpcontext.HttpContextServiceFactory; +-import org.amdatu.web.httpcontext.ResourceProvider; +-import org.apache.felix.dm.Component; +-import org.json.JSONException; +-import org.json.JSONObject; +-import org.osgi.framework.BundleContext; ++import org.apache.felix.dm.DependencyManager; + import org.osgi.service.log.LogService; + import org.osgi.service.useradmin.Group; + import org.osgi.service.useradmin.Role; + import org.osgi.service.useradmin.User; + import org.osgi.service.useradmin.UserAdmin; + +-/** +- * This service is responsible for authorization handling, based on the UserAdmin OSGi service. +- * +- * @author ivol +- */ +- at Path("authorization") +-public class LoginServiceImpl implements ResourceProvider, LoginService { ++public class LoginServiceImpl implements LoginService { + // Default Administrator user credentials + private static final String DEFAULT_USERNAME = "Administrator"; + private static final String DEFAULT_PASSWORD = "Administrator"; +@@ -68,27 +41,23 @@ + + // Service dependencies, injected by the Felix dependency manager + private volatile LogService m_logService; +- private volatile BundleContext m_bundleContext; +- private volatile HttpContextServiceFactory m_httpContextServiceFactory; + private volatile UserAdmin m_userAdmin; + private volatile TokenProvider m_tokenProvider; ++ private volatile DependencyManager m_dependencyManager; + +- // The private HTTP context service for this bundle +- private Component m_httpContextComponent; ++ private LoginContextProviderImpl m_loginContext = new LoginContextProviderImpl(); + +- // 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. + */ + public void init() { +- // Create our own http context service which registers static resources and JSPs automatically +- m_httpContextComponent = m_httpContextServiceFactory.create(m_bundleContext, this); ++ // Register our LoginContext provider ++ m_dependencyManager.add( ++ m_dependencyManager.createComponent() ++ .setImplementation(m_loginContext) ++ .setInterface(new String[] {ContextProvider.class.getName(), LoginContextProvider.class.getName()}, null) ++ .add(m_dependencyManager.createServiceDependency().setService(TokenProvider.class).setRequired(true)) ++ .add(m_dependencyManager.createServiceDependency().setService(LogService.class).setRequired(true))); + + m_logService.log(LogService.LOG_INFO, getClass().getName() + " service initialized"); + } +@@ -110,176 +79,57 @@ + } + } + +- // The destroy() method is automatically invoked by the Felix dependency manager +- public void destroy() { +- // Stop the HTTP context service we created ourselves +- m_httpContextComponent.stop(); ++ public void login(String username, String password) throws LoginException { ++ login(username, password, null); + } + +- /** +- * This method can be used to check the availability of the Login Service. +- * +- * @return The text "Login service online" +- */ +- @GET +- @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 }) +- 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 +- // session info in the container. Note that we use our own http session implementation +- // because of issue AMDATU-67. +- JSONObject jsonObject = new JSONObject(); ++ public void login(String username, String password, SortedMap<String, String> attributes) throws LoginException { + try { +- 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) { +- 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(); +- } +- +- /** +- * REST based login service with username/password. +- */ +- @POST +- @Path("login") +- @Consumes("application/x-www-form-urlencoded") +- @Produces( { MediaType.APPLICATION_JSON }) +- public Response login(@FormParam("username") final String username, @FormParam("password") final String password, +- @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 { ++ // First validate username and password + Role userRole = m_userAdmin.getRole(username); + if (userRole != null && userRole.getType() == Role.USER) { + User user = (User) userRole; +- if (user.hasCredential(PASSWORD_CREDENTIAL_KEY, password)) { +- // 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); ++ if (user.hasCredential(LoginService.PASSWORD_CREDENTIAL_KEY, password)) { ++ // Now generate a token for this user ++ String token = generateToken(user, attributes); + ++ // Finally, write the info to the current login context ++ m_loginContext.setUsername(username); ++ m_loginContext.setToken(token); + 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"); +- ++ return; + } +- else { +- m_logService.log(LogService.LOG_INFO, "Incorrect password provided for user '" + username + "'"); +- jsonObject.append("result", "failed"); +- jsonObject.append("msg", "Password is incorrect"); +- } + } +- else { +- m_logService.log(LogService.LOG_INFO, "Username '" + username + "' unknown"); +- jsonObject.append("result", "failed"); +- jsonObject.append("msg", "Username is unknown"); +- } ++ throw new LoginException("Username and/or password invalid"); ++ } catch (TokenProviderException e) { ++ throw new LoginException(e.toString()); + } +- 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); +- } +- 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 }) +- 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 { +- userName = getUserName(request); +- invalidateToken(request); ++ public void logout() { ++ String userName = m_loginContext.getValue(LoginContextProvider.USERNAME); ++ if (userName != null) { ++ invalidateToken(); ++ (m_loginContext).setUsername(null); + m_logService.log(LogService.LOG_INFO, "User '" + userName + "' logged out successfully"); +- jsonObject.append("result", "ok"); ++ } else { ++ m_logService.log(LogService.LOG_INFO, "No user was logged in in the current context, unable to logout"); + } +- 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(); + } + +- public URL getResource(String name) { +- return null; +- } +- +- public String getResourceId() { +- return Activator.RESOURCE_ID; +- } +- +- private String generateToken(HttpServletRequest request, User user) throws TokenProviderException { ++ private String generateToken(User user, SortedMap<String, String> additionAttrs) 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); ++ if (additionAttrs != null) { ++ for (String key : additionAttrs.keySet()) { ++ String value = additionAttrs.get(key); ++ attributes.put(key, value); + } + } +- +- return null; ++ return m_tokenProvider.generateToken(attributes); + } + +- private void invalidateToken(HttpServletRequest request) { +- m_tokenProvider.invalidateToken(m_tokenProvider.getTokenFromRequest(request)); ++ private void invalidateToken() { ++ m_tokenProvider.invalidateToken(m_loginContext.getValue(LoginContextProvider.USER_TOKEN)); + } + } +Index: amdatu-authorization/useradmin-rest/pom.xml +=================================================================== +--- amdatu-authorization/useradmin-rest/pom.xml (revision 564) ++++ amdatu-authorization/useradmin-rest/pom.xml (working copy) +@@ -12,8 +12,8 @@ + <packaging>bundle</packaging> + <name>Amdatu Authorization - User Admin REST API</name> + <description>Provides a REST API on UserAdmin</description> +- +- <dependencies> ++ ++ <dependencies> + <dependency> + <groupId>org.amdatu.web</groupId> + <artifactId>httpcontext</artifactId> +@@ -45,8 +45,29 @@ + <version>${platform.version}</version> + <scope>provided</scope> + </dependency> ++ <dependency> ++ <groupId>org.amdatu.authentication</groupId> ++ <artifactId>contextmanager</artifactId> ++ <version>${platform.version}</version> ++ <scope>provided</scope> ++ <type>bundle</type> ++ </dependency> ++ <dependency> ++ <groupId>org.amdatu.authorization.login</groupId> ++ <artifactId>service</artifactId> ++ <version>${platform.version}</version> ++ <scope>provided</scope> ++ <type>bundle</type> ++ </dependency> ++ <dependency> ++ <groupId>org.amdatu.core</groupId> ++ <artifactId>tenant</artifactId> ++ <version>${platform.version}</version> ++ <scope>provided</scope> ++ <type>bundle</type> ++ </dependency> + </dependencies> +- ++ + <build> + <plugins> + <plugin> +@@ -59,7 +80,7 @@ + <Embed-Dependency>*;scope=compile</Embed-Dependency> + </instructions> + </configuration> +- </plugin> +- </plugins> +- </build> ++ </plugin> ++ </plugins> ++ </build> + </project> +Index: amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/osgi/Activator.java +=================================================================== +--- amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/osgi/Activator.java (revision 564) ++++ amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/osgi/Activator.java (working copy) +@@ -16,6 +16,7 @@ + */ + package org.amdatu.authorization.useradmin.rest.osgi; + ++import org.amdatu.authentication.contextmanager.ContextManager; + import org.amdatu.authentication.tokenprovider.TokenProvider; + import org.amdatu.authorization.useradmin.rest.service.GroupsResource; + import org.amdatu.authorization.useradmin.rest.service.RolesResource; +@@ -26,7 +27,6 @@ + import org.apache.felix.dm.DependencyManager; + import org.osgi.framework.BundleContext; + import org.osgi.service.log.LogService; +-import org.osgi.service.useradmin.UserAdmin; + + /** + * This is the activator for the UserAdmin REST API bundle +@@ -45,25 +45,25 @@ + manager.add(createComponent() + .setInterface(RESTService.class.getName(), null) + .setImplementation(UsersResource.class) ++ .add(createServiceDependency().setService(ContextManager.class).setRequired(true)) + .add(createServiceDependency().setService(LogService.class).setRequired(true)) +- .add(createServiceDependency().setService(TokenProvider.class).setRequired(true)) +- .add(createServiceDependency().setService(UserAdmin.class).setRequired(true))); ++ .add(createServiceDependency().setService(TokenProvider.class).setRequired(true))); + + // Create the groups resource service and register it as REST service + manager.add(createComponent() + .setInterface(RESTService.class.getName(), null) + .setImplementation(GroupsResource.class) ++ .add(createServiceDependency().setService(ContextManager.class).setRequired(true)) + .add(createServiceDependency().setService(LogService.class).setRequired(true)) +- .add(createServiceDependency().setService(TokenProvider.class).setRequired(true)) +- .add(createServiceDependency().setService(UserAdmin.class).setRequired(true))); +- ++ .add(createServiceDependency().setService(TokenProvider.class).setRequired(true))); ++ + // Create the groups resource service and register it as REST service + manager.add(createComponent() + .setInterface(RESTService.class.getName(), null) + .setImplementation(RolesResource.class) ++ .add(createServiceDependency().setService(ContextManager.class).setRequired(true)) + .add(createServiceDependency().setService(LogService.class).setRequired(true)) +- .add(createServiceDependency().setService(TokenProvider.class).setRequired(true)) +- .add(createServiceDependency().setService(UserAdmin.class).setRequired(true))); ++ .add(createServiceDependency().setService(TokenProvider.class).setRequired(true))); + } + + @Override +Index: amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/service/GroupsResource.java +=================================================================== +--- amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/service/GroupsResource.java (revision 564) ++++ amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/service/GroupsResource.java (working copy) +@@ -95,7 +95,7 @@ + @DefaultValue("1") @QueryParam("startIndex") final int startIndex, + @DefaultValue("50") @QueryParam("maxResults") final int maxResults, + @Context final HttpServletRequest request) { +- if (!isAuthorized(request)) { ++ if (!isAuthorized()) { + return Response.status(Response.Status.UNAUTHORIZED).build(); + } + return super.getRoles(filter, sortOrder, startIndex, maxResults, Role.GROUP); +@@ -121,7 +121,7 @@ + @Path("{name}") + @Produces({MediaType.APPLICATION_JSON}) + public Response getGroup(@PathParam("name") final String name, @Context final HttpServletRequest request) { +- if (!isAuthorized(request)) { ++ if (!isAuthorized()) { + return Response.status(Response.Status.UNAUTHORIZED).build(); + } + return super.getRole(name, Role.GROUP); +@@ -141,7 +141,7 @@ + @Path("{name}") + @Produces({MediaType.APPLICATION_JSON}) + public Response createGroup(@PathParam("name") final String name, @Context final HttpServletRequest request) { +- if (!isAuthorized(request)) { ++ if (!isAuthorized()) { + return Response.status(Response.Status.UNAUTHORIZED).build(); + } + return super.createRole(name, Role.GROUP); +@@ -163,7 +163,7 @@ + @Produces({MediaType.APPLICATION_JSON}) + public Response setCredential(@PathParam("name") final String name, + @PathParam("key") final String key, @QueryParam("value") final String value, @Context final HttpServletRequest request) { +- if (!isAuthorized(request)) { ++ if (!isAuthorized()) { + return Response.status(Response.Status.UNAUTHORIZED).build(); + } + return setCredential(name, key, value, Role.GROUP); +@@ -185,7 +185,7 @@ + @Produces({MediaType.APPLICATION_JSON}) + public Response setProperty(@PathParam("name") final String name, + @PathParam("key") final String key, @QueryParam("value") final String value, @Context final HttpServletRequest request) { +- if (!isAuthorized(request)) { ++ if (!isAuthorized()) { + return Response.status(Response.Status.UNAUTHORIZED).build(); + } + return setProperty(name, key, value, Role.USER); +@@ -207,7 +207,7 @@ + @Produces({MediaType.APPLICATION_JSON}) + public Response addBasicMember(@PathParam("name") final String name, + @PathParam("memberName") final String memberName, @Context final HttpServletRequest request) { +- if (!isAuthorized(request)) { ++ if (!isAuthorized()) { + return Response.status(Response.Status.UNAUTHORIZED).build(); + } + return addMember(name, memberName, false); +@@ -229,7 +229,7 @@ + @Produces({MediaType.APPLICATION_JSON}) + public Response addRequiredMember(@PathParam("name") final String name, + @PathParam("memberName") final String memberName, @Context final HttpServletRequest request) { +- if (!isAuthorized(request)) { ++ if (!isAuthorized()) { + return Response.status(Response.Status.UNAUTHORIZED).build(); + } + return addMember(name, memberName, true); +@@ -248,7 +248,7 @@ + @Path("{name}") + @Produces({MediaType.APPLICATION_JSON}) + public Response removeGroup(@PathParam("name") final String name, @Context final HttpServletRequest request) { +- if (!isAuthorized(request)) { ++ if (!isAuthorized()) { + return Response.status(Response.Status.UNAUTHORIZED).build(); + } + return super.removeRole(name, Role.GROUP); +@@ -269,11 +269,11 @@ + @Produces({MediaType.APPLICATION_JSON}) + public Response removeMember(@PathParam("name") final String name, @PathParam("memberName") final String memberName, + @Context final HttpServletRequest request) { +- if (!isAuthorized(request)) { ++ if (!isAuthorized()) { + return Response.status(Response.Status.UNAUTHORIZED).build(); + } +- Role role = m_userAdmin.getRole(name); +- Role member = m_userAdmin.getRole(memberName); ++ Role role = getUserAdmin().getRole(name); ++ Role member = getUserAdmin().getRole(memberName); + if (role != null && role.getType() == Role.GROUP && member != null) { + if (((Group) role).removeMember(member)) { + return buildOK(); +@@ -286,8 +286,8 @@ + } + + private Response addMember(String name, String memberName, boolean required) { +- Role role = m_userAdmin.getRole(name); +- Role member = m_userAdmin.getRole(memberName); ++ Role role = getUserAdmin().getRole(name); ++ Role member = getUserAdmin().getRole(memberName); + if (role != null && role.getType() == Role.GROUP && member != null) { + if (!required && ((Group) role).addMember(member)) { + return buildOK(); +Index: amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/service/ResourceBase.java +=================================================================== +--- amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/service/ResourceBase.java (revision 564) ++++ amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/service/ResourceBase.java (working copy) +@@ -21,25 +21,26 @@ + import java.util.Collections; + import java.util.Comparator; + import java.util.List; +-import java.util.Map; + +-import javax.servlet.http.HttpServletRequest; + import javax.ws.rs.WebApplicationException; + import javax.ws.rs.core.CacheControl; + import javax.ws.rs.core.MediaType; + import javax.ws.rs.core.Response; + +-import org.amdatu.authentication.tokenprovider.InvalidTokenException; ++import org.amdatu.authentication.contextmanager.ContextManager; ++import org.amdatu.authentication.contextmanager.UnknownProviderException; + import org.amdatu.authentication.tokenprovider.TokenProvider; +-import org.amdatu.authentication.tokenprovider.TokenProviderException; ++import org.amdatu.authorization.login.service.LoginContextProvider; + import org.amdatu.authorization.useradmin.rest.bean.RoleBean; + import org.amdatu.authorization.useradmin.rest.bean.SearchResultBean; ++import org.amdatu.core.tenant.TenantContextProvider; + import org.amdatu.libraries.utilities.rest.AtomSyndicationLink; + import org.amdatu.web.rest.jaxrs.RESTService; + import org.json.JSONObject; ++import org.osgi.framework.BundleContext; + import org.osgi.framework.InvalidSyntaxException; ++import org.osgi.framework.ServiceReference; + import org.osgi.service.log.LogService; +-import org.osgi.service.useradmin.Group; + import org.osgi.service.useradmin.Role; + import org.osgi.service.useradmin.User; + import org.osgi.service.useradmin.UserAdmin; +@@ -47,11 +48,13 @@ + abstract class ResourceBase implements RESTService { + // FIXME: Temporary fix for AMDATU-81 + private static final String DEFAULT_ADMIN_GROUP = "Administrators"; +- ++ + // Service dependencies injected by the depedency manager + protected volatile LogService m_logService; +- protected volatile UserAdmin m_userAdmin; ++ //protected volatile UserAdmin m_userAdmin; + protected volatile TokenProvider m_tokenProvider; ++ private volatile ContextManager m_contextManager; ++ private volatile BundleContext m_bundleContext; + + // Disable HTTP caching in this REST interface + private static CacheControl m_cacheControl; +@@ -62,7 +65,7 @@ + + /** + * Returns the roles (users or groups) for the specified filter options. +- * ++ * + * @param filter the filter to pass to UserAdmin + * @param sortOrder The sort order ('ascending' or 'descending') + * @param startIndex The startindex +@@ -80,7 +83,7 @@ + } + + // First retrieve all roles with the specified filter +- Role[] roles = m_userAdmin.getRoles(null); ++ Role[] roles = getUserAdmin().getRoles(null); + final boolean descending = "desc".equalsIgnoreCase(sortOrder) || "descending".equalsIgnoreCase(sortOrder); + + // Now filter out the user or groups (we should only return roles of type roleType) +@@ -119,7 +122,7 @@ + } + + SearchResultBean result = new SearchResultBean(); +- result.addRoles(roleRange, m_userAdmin); ++ result.addRoles(roleRange, getUserAdmin()); + + // Calculate paging + Paging paging = new Paging(); +@@ -140,7 +143,7 @@ + getBaseUrl() + "?startIndex=" + paging.pageStartIndex + "&endIndex=" + paging.pageEndIndex + + "&maxResults=" + maxResults; + result.addLink(new AtomSyndicationLink().setHref(url).setRel("Alternate").setType("application/json")); +- ++ + // Start + url = + getBaseUrl() + "?startIndex=" + paging.firstStartIndex + "&endIndex=" + paging.firstEndIndex +@@ -185,10 +188,10 @@ + } + + protected Response getRole(String name, int roleType) { +- Role role = m_userAdmin.getRole(name); ++ Role role = getUserAdmin().getRole(name); + if (role != null && role.getType() == roleType) { + try { +- RoleBean user = RoleBean.fromRole(role, m_userAdmin); ++ RoleBean user = RoleBean.fromRole(role, getUserAdmin()); + return Response.ok(user).cacheControl(m_cacheControl).build(); + } + catch (URISyntaxException e) { +@@ -202,7 +205,7 @@ + } + + protected Response createRole(String name, int roleType) { +- Role role = m_userAdmin.createRole(name, roleType); ++ Role role = getUserAdmin().createRole(name, roleType); + if (role != null) { + return buildOK(); + } +@@ -213,7 +216,7 @@ + + @SuppressWarnings("unchecked") + protected Response setCredential(String name, String key, String value, int roleType) { +- Role role = m_userAdmin.getRole(name); ++ Role role = getUserAdmin().getRole(name); + if (role != null && role.getType() == roleType) { + ((User) role).getCredentials().put(key, value); + return buildOK(); +@@ -225,7 +228,7 @@ + + @SuppressWarnings("unchecked") + protected Response setProperty(String name, String key, String value, int roleType) { +- Role role = m_userAdmin.getRole(name); ++ Role role = getUserAdmin().getRole(name); + if (role != null && role.getType() == roleType) { + role.getProperties().put(key, value); + return buildOK(); +@@ -236,9 +239,9 @@ + } + + protected Response removeRole(String name, int roleType) { +- Role role = m_userAdmin.getRole(name); ++ Role role = getUserAdmin().getRole(name); + if (role != null && role.getType() == roleType) { +- if (m_userAdmin.removeRole(name)) { ++ if (getUserAdmin().removeRole(name)) { + return buildOK(); + } + else { +@@ -288,7 +291,7 @@ + + /** + * Calculate paging +- * ++ * + * @param currentStartIndex The requested start index to display + * @param pageResults The amount of results in the current selection + * @param maxResults The maximum amount of results displayed on one page +@@ -341,39 +344,46 @@ + } + + protected abstract String getBaseUrl(); +- ++ + // FIXME: Temporary fix for AMDATU-81. Until AMDATU-230 has been fixed we need to make a + // quick fix, not having any form of authorization is simply not acceptable. For now +- // we check if the user is logged in and in the "Administrators" role. This role is ++ // we check if the user is logged in and in the "Administrators" role. This role is + // hard coded. +- protected boolean isAuthorized(HttpServletRequest request) { +- String token = m_tokenProvider.getTokenFromRequest(request); +- if (token != null) { ++ protected boolean isAuthorized() { ++ try { ++ String userName = m_contextManager.getValue(LoginContextProvider.ID, LoginContextProvider.USERNAME); ++ if (userName != null && !userName.isEmpty()) { ++ User user = (User) getUserAdmin().getRole(userName); ++ if (user != null) { ++ return getUserAdmin().getAuthorization(user).hasRole(DEFAULT_ADMIN_GROUP); ++ } ++ } ++ } ++ catch (UnknownProviderException e) { ++ m_logService.log(LogService.LOG_ERROR, "Login context unavailable", e); ++ } ++ return false; ++ } ++ ++ protected UserAdmin getUserAdmin() { ++ try { + try { +- Map<String, String> attributes = m_tokenProvider.verifyToken(token); +- if (attributes.containsKey(TokenProvider.USERNAME)) { +- String userName = attributes.get(TokenProvider.USERNAME); +- if (userName != null && !userName.isEmpty()) { +- User user = (User) m_userAdmin.getRole(userName); +- if (user != null) { +- return m_userAdmin.getAuthorization(user).hasRole(DEFAULT_ADMIN_GROUP); +- } ++ String tenantId = m_contextManager.getValue(TenantContextProvider.ID, TenantContextProvider.TENANT_ID); ++ if (tenantId != null && !tenantId.isEmpty()) { ++ String filter = "(org.ops4j.pax.useradmin.storageprovider.type=Cassandra_" + tenantId + ")"; ++ ServiceReference[] servRefs = m_bundleContext.getAllServiceReferences(UserAdmin.class.getName(), filter); ++ if (servRefs != null && servRefs.length > 0) { ++ return (UserAdmin) m_bundleContext.getService(servRefs[0]); + } +- } ++ } ++ } catch (UnknownProviderException e) { ++ m_logService.log(LogService.LOG_ERROR, "Could not find tenant context provider", e); + } +- catch (TokenProviderException e) { +- // Ignore invalid tokens +- } +- catch (InvalidTokenException e) { +- // Ignore invalid tokens +- } ++ ServiceReference[] servRefs = m_bundleContext.getAllServiceReferences(UserAdmin.class.getName(), null); ++ return (UserAdmin) m_bundleContext.getService(servRefs[0]); ++ } catch (InvalidSyntaxException e) { ++ m_logService.log(LogService.LOG_ERROR, "Could not find useradmin service", e); + } +- return false; ++ return null; + } +- +- public void fix() { +- Role role = m_userAdmin.getRole("Administrator"); +- Group group = (Group) m_userAdmin.getRole(DEFAULT_ADMIN_GROUP); +- group.addMember(role); +- } + } +Index: amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/service/RolesResource.java +=================================================================== +--- amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/service/RolesResource.java (revision 564) ++++ amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/service/RolesResource.java (working copy) +@@ -77,7 +77,7 @@ + @DefaultValue("1") @QueryParam("startIndex") final int startIndex, + @DefaultValue("50") @QueryParam("maxResults") final int maxResults, + @Context final HttpServletRequest request) { +- if (!isAuthorized(request)) { ++ if (!isAuthorized()) { + return Response.status(Response.Status.UNAUTHORIZED).build(); + } + return super.getRoles(filter, sortOrder, startIndex, maxResults, Role.ROLE); +Index: amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/service/UsersResource.java +=================================================================== +--- amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/service/UsersResource.java (revision 564) ++++ amdatu-authorization/useradmin-rest/src/main/java/org/amdatu/authorization/useradmin/rest/service/UsersResource.java (working copy) +@@ -92,7 +92,7 @@ + @DefaultValue("1") @QueryParam("startIndex") final int startIndex, + @DefaultValue("50") @QueryParam("maxResults") final int maxResults, + @Context final HttpServletRequest request) { +- if (!isAuthorized(request)) { ++ if (!isAuthorized()) { + return Response.status(Response.Status.UNAUTHORIZED).build(); + } + return super.getRoles(filter, sortOrder, startIndex, maxResults, Role.USER); +@@ -116,7 +116,7 @@ + @Path("{name}") + @Produces({MediaType.APPLICATION_JSON}) + public Response getUser(@PathParam("name") final String name, @Context final HttpServletRequest request) { +- if (!isAuthorized(request)) { ++ if (!isAuthorized()) { + return Response.status(Response.Status.UNAUTHORIZED).build(); + } + return super.getRole(name, Role.USER); +@@ -136,7 +136,7 @@ + @Path("{name}") + @Produces({MediaType.APPLICATION_JSON}) + public Response createUser(@PathParam("name") final String name, @Context final HttpServletRequest request) { +- if (!isAuthorized(request)) { ++ if (!isAuthorized()) { + return Response.status(Response.Status.UNAUTHORIZED).build(); + } + return super.createRole(name, Role.USER); +@@ -158,7 +158,7 @@ + @Produces({MediaType.APPLICATION_JSON}) + public Response setCredential(@PathParam("name") final String name, + @PathParam("key") final String key, @FormParam("value") final String value, @Context final HttpServletRequest request) { +- if (!isAuthorized(request)) { ++ if (!isAuthorized()) { + return Response.status(Response.Status.UNAUTHORIZED).build(); + } + return setCredential(name, key, value, Role.USER); +@@ -180,7 +180,7 @@ + @Produces({MediaType.APPLICATION_JSON}) + public Response setProperty(@PathParam("name") final String name, + @PathParam("key") final String key, @FormParam("value") final String value, @Context final HttpServletRequest request) { +- if (!isAuthorized(request)) { ++ if (!isAuthorized()) { + return Response.status(Response.Status.UNAUTHORIZED).build(); + } + return setProperty(name, key, value, Role.USER); +@@ -199,7 +199,7 @@ + @Path("{name}") + @Produces({MediaType.APPLICATION_JSON}) + public Response removeUser(@PathParam("name") final String name, @Context final HttpServletRequest request) { +- if (!isAuthorized(request)) { ++ if (!isAuthorized()) { + return Response.status(Response.Status.UNAUTHORIZED).build(); + } + return super.removeRole(name, Role.USER); +Index: amdatu-cassandra/cassandra-useradminstore/pom.xml +=================================================================== +--- amdatu-cassandra/cassandra-useradminstore/pom.xml (revision 564) ++++ amdatu-cassandra/cassandra-useradminstore/pom.xml (working copy) +@@ -12,31 +12,31 @@ + <packaging>bundle</packaging> + <name>Amdatu Cassandra - User Admin Cassandra Store</name> + <description>Provides an implementation of the Pax UserAdmin store</description> +- +- <dependencies> ++ ++ <dependencies> + <dependency> + <groupId>org.ops4j.pax.useradmin</groupId> + <artifactId>pax-useradmin-service</artifactId> + <scope>provided</scope> +- </dependency> ++ </dependency> + <dependency> + <groupId>org.amdatu.cassandra</groupId> + <artifactId>listener</artifactId> + <scope>provided</scope> + <type>bundle</type> +- </dependency> ++ </dependency> + <dependency> + <groupId>org.amdatu.cassandra</groupId> + <artifactId>application</artifactId> + <scope>provided</scope> + <type>bundle</type> +- </dependency> ++ </dependency> + <dependency> + <groupId>org.amdatu.cassandra</groupId> + <artifactId>persistencemanager</artifactId> + <scope>provided</scope> + <type>bundle</type> +- </dependency> ++ </dependency> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> +@@ -53,15 +53,22 @@ + <dependency> + <groupId>org.amdatu.web</groupId> + <artifactId>httpcontext</artifactId> +- <scope>provided</scope> ++ <scope>provided</scope> + <type>bundle</type> + </dependency> + <dependency> ++ <groupId>org.amdatu.core</groupId> ++ <artifactId>tenant</artifactId> ++ <version>${platform.version}</version> ++ <scope>provided</scope> ++ <type>bundle</type> ++ </dependency> ++ <dependency> + <groupId>org.json</groupId> + <artifactId>json</artifactId> + <version>20090211</version> + <scope>compile</scope> +- </dependency> ++ </dependency> + </dependencies> + + <build> +@@ -80,5 +87,5 @@ + </configuration> + </plugin> + </plugins> +- </build> ++ </build> + </project> +Index: amdatu-cassandra/cassandra-useradminstore/src/main/java/org/amdatu/cassandra/useradminstore/osgi/Activator.java +=================================================================== +--- amdatu-cassandra/cassandra-useradminstore/src/main/java/org/amdatu/cassandra/useradminstore/osgi/Activator.java (revision 564) ++++ amdatu-cassandra/cassandra-useradminstore/src/main/java/org/amdatu/cassandra/useradminstore/osgi/Activator.java (working copy) +@@ -16,21 +16,16 @@ + */ + package org.amdatu.cassandra.useradminstore.osgi; + +-import java.util.Hashtable; +- + import org.amdatu.cassandra.application.CassandraDaemonService; +-import org.amdatu.cassandra.listener.ColumnFamilyAvailable; + import org.amdatu.cassandra.listener.ColumnFamilyProvider; +-import org.amdatu.cassandra.persistencemanager.CassandraPersistenceManager; + import org.amdatu.cassandra.useradminstore.rest.HttpContextRegistrationServiceImpl; +-import org.amdatu.cassandra.useradminstore.service.CassandraStorageProvider; ++import org.amdatu.cassandra.useradminstore.service.CassandraStorageProviderRegistrationServiceImpl; + import org.amdatu.cassandra.useradminstore.service.RoleColumnFamilyProvider; ++import org.amdatu.core.tenant.Tenant; + import org.amdatu.web.httpcontext.HttpContextServiceFactory; + import org.amdatu.web.httpcontext.ResourceProvider; + import org.apache.felix.dm.DependencyActivatorBase; + import org.apache.felix.dm.DependencyManager; +-import org.ops4j.pax.useradmin.service.UserAdminConstants; +-import org.ops4j.pax.useradmin.service.spi.StorageProvider; + import org.osgi.framework.BundleContext; + import org.osgi.service.http.HttpService; + import org.osgi.service.log.LogService; +@@ -42,42 +37,28 @@ + // The resource identifier for this bundle. Resources are only considered to be 'ours' when + // it is prefixed with this id + public final static String RESOURCE_ID = "useradmin"; +- ++ + @Override + public void init(BundleContext context, DependencyManager manager) throws Exception { + // First define a service that provides the Role ColumnFamily we need + manager.add(createComponent() +- .setInterface(new String[]{ColumnFamilyProvider.class.getName()}, null) +- .setImplementation(RoleColumnFamilyProvider.class)); +- +- // This filter is used to define a service dependency on the ColumnFamilyAvailable service +- // for the Role ColumnFamily. As a result, our service will depend on the availability +- // of this ColumnFamily. +- String roleFilter = "(" + ColumnFamilyAvailable.FILTER_NAME + "=" + CassandraStorageProvider.CF_ROLE + ")"; +- String keyspaceFilter = +- "(" + CassandraPersistenceManager.KEYSPACE_AWARE_KEY + "=" +- + CassandraPersistenceManager.DEFAULT_KEYSPACE + ")"; +- roleFilter = "(&" + roleFilter + keyspaceFilter + ")"; +- +- // Create and register the CassandraStorageProvider service. +- Hashtable<String, String> properties = new Hashtable<String, String>(); +- properties.put(UserAdminConstants.STORAGEPROVIDER_TYPE, "Cassandra"); +- properties.put("service.ranking", "10"); +- manager.add(createComponent() +- .setInterface(new String[]{StorageProvider.class.getName()}, properties) +- .setImplementation(CassandraStorageProvider.class) +- .add(createServiceDependency().setService(LogService.class).setRequired(true)) +- .add(createServiceDependency().setService(CassandraPersistenceManager.class, keyspaceFilter).setRequired(true)) +- .add(createServiceDependency().setService(ColumnFamilyAvailable.class, roleFilter).setRequired(true)) +- .add(createServiceDependency().setService(CassandraDaemonService.class).setRequired(true))); +- ++ .setInterface(new String[]{ColumnFamilyProvider.class.getName()}, null) ++ .setImplementation(RoleColumnFamilyProvider.class)); ++ ++ // Create and register the tenant storage provider registration service, this service is responsible ++ // for launching a storage provider for each available tenant ++ manager.add(createAdapterService(Tenant.class, null) ++ .setImplementation(CassandraStorageProviderRegistrationServiceImpl.class) ++ .add(createServiceDependency().setService(CassandraDaemonService.class).setRequired(true)) ++ .add(createServiceDependency().setService(LogService.class).setRequired(true))); ++ + // Create and register the http context registration service + manager.add(createComponent() +- .setInterface(ResourceProvider.class.getName(), null) +- .setImplementation(HttpContextRegistrationServiceImpl.class) +- .add(createServiceDependency().setService(LogService.class).setRequired(true)) +- .add(createServiceDependency().setService(HttpContextServiceFactory.class).setRequired(true)) +- .add(createServiceDependency().setService(HttpService.class).setRequired(true))); ++ .setInterface(ResourceProvider.class.getName(), null) ++ .setImplementation(HttpContextRegistrationServiceImpl.class) ++ .add(createServiceDependency().setService(LogService.class).setRequired(true)) ++ .add(createServiceDependency().setService(HttpContextServiceFactory.class).setRequired(true)) ++ .add(createServiceDependency().setService(HttpService.class).setRequired(true))); + } + + @Override +Index: amdatu-cassandra/cassandra-useradminstore/src/main/java/org/amdatu/cassandra/useradminstore/service/CassandraStorageProviderRegistrationServiceImpl.java +=================================================================== +--- amdatu-cassandra/cassandra-useradminstore/src/main/java/org/amdatu/cassandra/useradminstore/service/CassandraStorageProviderRegistrationServiceImpl.java (revision 0) ++++ amdatu-cassandra/cassandra-useradminstore/src/main/java/org/amdatu/cassandra/useradminstore/service/CassandraStorageProviderRegistrationServiceImpl.java (revision 0) +@@ -0,0 +1,58 @@ ++package org.amdatu.cassandra.useradminstore.service; ++ ++import java.util.Hashtable; ++ ++import org.amdatu.cassandra.application.CassandraDaemonService; ++import org.amdatu.cassandra.listener.ColumnFamilyAvailable; ++import org.amdatu.cassandra.persistencemanager.CassandraPersistenceManager; ++import org.amdatu.core.tenant.Tenant; ++import org.apache.cassandra.thrift.InvalidRequestException; ++import org.apache.felix.dm.DependencyManager; ++import org.apache.thrift.TException; ++import org.ops4j.pax.useradmin.service.UserAdminConstants; ++import org.ops4j.pax.useradmin.service.spi.StorageProvider; ++import org.osgi.service.log.LogService; ++ ++public class CassandraStorageProviderRegistrationServiceImpl { ++ // Service dependencies injected by the depedency manager ++ private volatile DependencyManager m_dependencyManager; ++ private volatile Tenant m_tenant; ++ private volatile CassandraDaemonService m_daemonService; ++ private volatile LogService m_logService; ++ ++ public void start() { ++ try { ++ // We will create a storage provider that stores users for this tenant in a keyspace that equals the ++ // tenant id. We therefore first verify if that keyspace exists and if not, we create it. ++ if (!m_daemonService.getKeyspaces().contains(m_tenant.getId())) { ++ m_daemonService.addKeyspace(m_tenant.getId()); ++ } ++ ++ // This filter is used to define a service dependency on the ColumnFamilyAvailable service ++ // for the Role ColumnFamily. As a result, our service will depend on the availability ++ // of this ColumnFamily. ++ String roleFilter = "(" + ColumnFamilyAvailable.FILTER_NAME + "=" + CassandraStorageProvider.CF_ROLE + ")"; ++ String keyspaceFilter = "(" + CassandraPersistenceManager.KEYSPACE_AWARE_KEY + "=" + m_tenant.getId() + ")"; ++ roleFilter = "(&" + roleFilter + keyspaceFilter + ")"; ++ ++ // Create and register the CassandraStorageProvider service. ++ Hashtable<String, String> properties = new Hashtable<String, String>(); ++ properties.put(UserAdminConstants.STORAGEPROVIDER_TYPE, "Cassandra_" + m_tenant.getId()); ++ properties.put("service.ranking", "10"); ++ properties.put(Tenant.SERVICE_PREFIX + "id", m_tenant.getId()); ++ m_dependencyManager.add(m_dependencyManager.createComponent() ++ .setInterface(new String[]{StorageProvider.class.getName()}, properties) ++ .setImplementation(CassandraStorageProvider.class) ++ .add(m_dependencyManager.createServiceDependency().setService(LogService.class).setRequired(true)) ++ .add(m_dependencyManager.createServiceDependency().setService(CassandraPersistenceManager.class, keyspaceFilter).setRequired(true)) ++ .add(m_dependencyManager.createServiceDependency().setService(ColumnFamilyAvailable.class, roleFilter).setRequired(true)) ++ .add(m_dependencyManager.createServiceDependency().setService(CassandraDaemonService.class).setRequired(true))); ++ ++ m_logService.log(LogService.LOG_INFO, "Cassandra useradmin storage provided started successfully for tenant '" + m_tenant.getId() + "'"); ++ } catch (TException e) { ++ m_logService.log(LogService.LOG_ERROR, "Could not start cassandra useradmin storage provider for tenant '" + m_tenant.getId() + "'", e); ++ } catch (InvalidRequestException e) { ++ m_logService.log(LogService.LOG_ERROR, "Could not start cassandra useradmin storage provider for tenant '" + m_tenant.getId() + "'", e); ++ } ++ } ++} +Index: amdatu-cassandra/cassandra-useradminstore/src/main/java/org/amdatu/cassandra/useradminstore/service/RoleColumnFamilyProvider.java +=================================================================== +--- amdatu-cassandra/cassandra-useradminstore/src/main/java/org/amdatu/cassandra/useradminstore/service/RoleColumnFamilyProvider.java (revision 564) ++++ amdatu-cassandra/cassandra-useradminstore/src/main/java/org/amdatu/cassandra/useradminstore/service/RoleColumnFamilyProvider.java (working copy) +@@ -20,12 +20,11 @@ + import org.amdatu.cassandra.listener.ColumnFamilyProvider; + import org.amdatu.cassandra.listener.ColumnFamilyDefinition.ColumnType; + import org.amdatu.cassandra.listener.ColumnFamilyDefinition.CompareType; +-import org.amdatu.cassandra.persistencemanager.CassandraPersistenceManager; + + /** + * This service only provides the Role Column Family. Note that the CassandraStorageProvider has + * a required dependency on the availability of this ColumnFamily (using ColumnFamilyAvailable +- * with filter columnfamily=Role). So the CassandraStorageProvider doesn't start until this ++ * with filter columnfamily=Role). So the CassandraStorageProvider doesn't start until this + * ColumnFamily is available in Cassandra (i.e. present in the last read storage config of Cassandra). + * The UserAdmin has a required dependency on the store, so the UserAdmin will not be available until + * the store is. +@@ -34,11 +33,11 @@ + public class RoleColumnFamilyProvider implements ColumnFamilyProvider { + public ColumnFamilyDefinition[] getColumnFamilies() { + return new ColumnFamilyDefinition[]{ +- new ColumnFamilyDefinition( +- CassandraStorageProvider.CF_ROLE, +- new String[]{CassandraPersistenceManager.DEFAULT_KEYSPACE}, +- ColumnType.SUPER, +- CompareType.BYTESTYPE, +- CompareType.BYTESTYPE)}; ++ new ColumnFamilyDefinition( ++ CassandraStorageProvider.CF_ROLE, ++ null, ++ ColumnType.SUPER, ++ CompareType.BYTESTYPE, ++ CompareType.BYTESTYPE)}; + } + } +Index: amdatu-core/config-filebased/pom.xml +=================================================================== +--- amdatu-core/config-filebased/pom.xml (revision 564) ++++ amdatu-core/config-filebased/pom.xml (working copy) +@@ -15,7 +15,7 @@ + <description>This bundle contains the configuration files of all Amdatu bundles and is repsonsible for registration of these configs in ConfigAdmin.</description> + + <build> +- <finalName>${groupId}.${artifactId}-${platform.version}</finalName> ++ <finalName>${project.groupId}.${project.artifactId}-${platform.version}</finalName> + <resources> + <resource> + <directory>src/main/resources</directory> +Index: amdatu-core/tenant/pom.xml +=================================================================== +--- amdatu-core/tenant/pom.xml (revision 564) ++++ amdatu-core/tenant/pom.xml (working copy) +@@ -13,16 +13,23 @@ + <name>Amdatu Core - Tenant Service</name> + <description>This bundle provides a tenant management service with tenant CRUD operations</description> + +- <dependencies> ++ <dependencies> + <dependency> + <groupId>org.amdatu.libraries</groupId> + <artifactId>utilities</artifactId> + <version>${platform.version}</version> + <scope>compile</scope> + <type>jar</type> +- </dependency> ++ </dependency> ++ <dependency> ++ <groupId>org.amdatu.authentication</groupId> ++ <artifactId>contextmanager</artifactId> ++ <version>${platform.version}</version> ++ <scope>provided</scope> ++ <type>bundle</type> ++ </dependency> + </dependencies> +- ++ + <build> + <plugins> + <plugin> +@@ -38,7 +45,7 @@ + </instructions> + </configuration> + </plugin> +- ++ + </plugins> +- </build> ++ </build> + </project> +Index: amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/osgi/Activator.java +=================================================================== +--- amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/osgi/Activator.java (revision 564) ++++ amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/osgi/Activator.java (working copy) +@@ -17,8 +17,11 @@ + */ + package org.amdatu.core.tenant.osgi; + ++import org.amdatu.authentication.contextmanager.ContextProvider; ++import org.amdatu.core.tenant.TenantContextProvider; + import org.amdatu.core.tenant.TenantManagementService; + import org.amdatu.core.tenant.TenantStorageProvider; ++import org.amdatu.core.tenant.service.TenantContextProviderImpl; + import org.amdatu.core.tenant.service.TenantManagementServiceImpl; + import org.apache.felix.dm.DependencyActivatorBase; + import org.apache.felix.dm.DependencyManager; +@@ -33,14 +36,21 @@ + public class Activator extends DependencyActivatorBase { + @Override + public void init(BundleContext context, DependencyManager manager) throws Exception { +- + // Create and register the Tenant management service + manager.add( +- createComponent() +- .setImplementation(TenantManagementServiceImpl.class) +- .setInterface(TenantManagementService.class.getName(), null) +- .add(createServiceDependency().setService(TenantStorageProvider.class).setRequired(true)) +- .add(createServiceDependency().setService(LogService.class).setRequired(true))); ++ createComponent() ++ .setImplementation(TenantManagementServiceImpl.class) ++ .setInterface(TenantManagementService.class.getName(), null) ++ .add(createServiceDependency().setService(TenantStorageProvider.class).setRequired(true)) ++ .add(createServiceDependency().setService(LogService.class).setRequired(true))); ++ ++ // Create and register the Tenant context provider ++ manager.add( ++ createComponent() ++ .setImplementation(TenantContextProviderImpl.class) ++ .setInterface(new String[]{TenantContextProvider.class.getName(), ContextProvider.class.getName()}, null) ++ .add(createServiceDependency().setService(TenantManagementService.class).setRequired(true)) ++ .add(createServiceDependency().setService(LogService.class).setRequired(true))); + } + + @Override +Index: amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/service/TenantContextProviderImpl.java +=================================================================== +--- amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/service/TenantContextProviderImpl.java (revision 0) ++++ amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/service/TenantContextProviderImpl.java (revision 0) +@@ -0,0 +1,131 @@ ++/* ++ 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.core.tenant.service; ++ ++import java.util.ArrayList; ++import java.util.HashMap; ++import java.util.List; ++import java.util.Map; ++ ++import javax.servlet.http.HttpServletRequest; ++ ++import org.amdatu.authentication.contextmanager.ContextProvider; ++import org.amdatu.core.tenant.Tenant; ++import org.amdatu.core.tenant.TenantContextProvider; ++import org.amdatu.core.tenant.TenantEntity; ++import org.amdatu.core.tenant.TenantException; ++import org.amdatu.core.tenant.TenantManagementService; ++import org.osgi.service.log.LogService; ++ ++/** ++ * Implementation of the tenant context provider. ++ * ++ * @author ivol ++ */ ++public class TenantContextProviderImpl implements TenantContextProvider { ++ // Tenant context information is bound to a ThreadLocal variable. ++ private static ThreadLocal<Map<String, String>> m_properties = new ThreadLocal<Map<String, String>>(); ++ ++ // Service dependencies injected by the dependency manager ++ private volatile TenantManagementService m_tenantManagementService; ++ private volatile LogService m_logService; ++ ++ public String getId() { ++ return TenantContextProvider.ID; ++ } ++ ++ public String getValue(String propertyName) { ++ if (m_properties.get() != null) { ++ return m_properties.get().get(propertyName); ++ } else { ++ return null; ++ } ++ } ++ ++ private void setValue(String key, String value) { ++ if (m_properties.get() == null) { ++ m_properties.set(new HashMap<String, String>()); ++ } ++ m_properties.get().put(key, value); ++ } ++ ++ public void start() { ++ try { ++ // TODO: this is test code, create test tenants! ++ if (m_tenantManagementService.getTenantById("tenant_a") == null) { ++ TenantEntity tenantA = m_tenantManagementService.createTenant("tenant_a", "Tenant A"); ++ tenantA.putProperty(HOSTNAME, "localhost"); ++ m_tenantManagementService.updateTenant(tenantA); ++ } ++ if (m_tenantManagementService.getTenantById("tenant_b") == null) { ++ TenantEntity tenantB = m_tenantManagementService.createTenant("tenant_b", "Tenant B"); ++ tenantB.putProperty(HOSTNAME, "127.0.0.1"); ++ m_tenantManagementService.updateTenant(tenantB); ++ } ++ } catch (TenantException e) { ++ } ++ } ++ ++ public void resolve(Map<String, Object> properties) { ++ // Check if the context resolver properties contain a HTTP request, if so we are able to resolve ++ // this to a tenant context ++ String serverName = ""; ++ if (properties.containsKey(ContextProvider.PROPERTY_HTTP_REQUEST)) { ++ try { ++ HttpServletRequest request = (HttpServletRequest) properties.get(ContextProvider.PROPERTY_HTTP_REQUEST); ++ serverName = request.getServerName(); ++ ++ // Start with a full list of tenants and remove tenants that do not match the hostname of the request. ++ List<TenantEntity> matchingTenants = new ArrayList<TenantEntity>(); ++ for (TenantEntity tenant : m_tenantManagementService.getTenants()) { ++ matchingTenants.add(tenant); ++ } ++ int size = matchingTenants.size(); ++ ++ // Loop over all available Tenants and determine the cross section ++ // of all matches. Note that if a tenant match returns UNKNOWN, this means that ++ // it is unable to resolve and so the result should be ignored. ++ for (int i=0; i<size;) { ++ if (!match(matchingTenants.get(i), serverName)) { ++ matchingTenants.remove(matchingTenants.get(i)); ++ size--; ++ } else { ++ i++; ++ } ++ } ++ if (size == 1) { ++ setValue(TENANT_ID, matchingTenants.get(0).getId()); ++ } ++ } catch (TenantException e) { ++ m_logService.log(LogService.LOG_ERROR, "Could not resolve '" + serverName + "' to a tenant", e); ++ } ++ } ++ } ++ ++ private boolean match(Tenant tenant, String serverName) { ++ if (tenant.getProperties().containsKey(TenantContextProvider.HOSTNAME)) { ++ String tenantHostname = tenant.getProperties().get(TenantContextProvider.HOSTNAME); ++ if (!serverName.equals(tenantHostname)) { ++ return false; ++ } ++ } ++ ++ // True means that either the hostname matches the tenant or the tenant didn't contain a hostname ++ // and could not be matched. ++ return true; ++ } ++} +Index: amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/service/TenantManagementServiceImpl.java +=================================================================== +--- amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/service/TenantManagementServiceImpl.java (revision 564) ++++ amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/service/TenantManagementServiceImpl.java (working copy) +@@ -16,9 +16,17 @@ + */ + package org.amdatu.core.tenant.service; + +-import java.util.*; ++import java.util.ArrayList; ++import java.util.HashMap; ++import java.util.List; ++import java.util.Map; ++import java.util.Properties; + +-import org.amdatu.core.tenant.*; ++import org.amdatu.core.tenant.Tenant; ++import org.amdatu.core.tenant.TenantEntity; ++import org.amdatu.core.tenant.TenantException; ++import org.amdatu.core.tenant.TenantManagementService; ++import org.amdatu.core.tenant.TenantStorageProvider; + import org.apache.felix.dm.Component; + import org.apache.felix.dm.DependencyManager; + +@@ -98,8 +106,8 @@ + + private void createTenantService(TenantEntity tenant) { + Component component = m_manager.createComponent() +- .setImplementation(tenant) +- .setInterface(Tenant.class.getName(), createServiceProperties(tenant)); ++ .setImplementation(tenant) ++ .setInterface(Tenant.class.getName(), createServiceProperties(tenant)); + m_manager.add(component); + m_tenantComponents.put(tenant, component); + } +@@ -121,7 +129,7 @@ + } + properties.put(Tenant.SERVICE_PREFIX + "id", tenant.getId()); + properties.put(Tenant.SERVICE_PREFIX + "name", tenant.getName()); +- ++ + return properties; + } + } +Index: amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/TenantContextProvider.java +=================================================================== +--- amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/TenantContextProvider.java (revision 0) ++++ amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/TenantContextProvider.java (revision 0) +@@ -0,0 +1,37 @@ ++/* ++/* ++ 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.core.tenant; ++ ++import org.amdatu.authentication.contextmanager.ContextProvider; ++ ++public interface TenantContextProvider extends ContextProvider { ++ /** ++ * Id of the tenant context provider. ++ */ ++ String ID = "org.amdatu.core.tenant.contextprovider"; ++ ++ /** ++ * Name of the hostname property in this context. The hostname is matched to one or more tenants. ++ */ ++ String HOSTNAME = "hostname"; ++ ++ /** ++ * Name of the tenant property in this context. ++ */ ++ String TENANT_ID = "tenantid"; ++} +Index: amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/TenantEntity.java +=================================================================== +--- amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/TenantEntity.java (revision 564) ++++ amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/TenantEntity.java (working copy) +@@ -1,5 +1,4 @@ + /* +-/* + Copyright (C) 2010 Amdatu.org + + This program is free software: you can redistribute it and/or modify +@@ -55,7 +54,7 @@ + public void setName(String name) { + m_name = name; + } +- ++ + public Map<String, String> getProperties() { + return new HashMap<String, String>(m_properties); + } +@@ -75,16 +74,19 @@ + + @Override + public boolean equals(Object obj) { +- if (this == obj) ++ if (this == obj) { + return true; +- if (obj == null) ++ } ++ if (obj == null) { + return false; +- if (getClass() != obj.getClass()) ++ } ++ if (getClass() != obj.getClass()) { + return false; ++ } + TenantEntity other = (TenantEntity) obj; + return m_id == other.getId(); + } +- ++ + public boolean matches(Map<String, String> properties) { + for (String key : properties.keySet()) { + if (!m_properties.containsKey(key)) { +Index: amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/TenantManagementService.java +=================================================================== +--- amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/TenantManagementService.java (revision 564) ++++ amdatu-core/tenant/src/main/java/org/amdatu/core/tenant/TenantManagementService.java (working copy) +@@ -1,5 +1,4 @@ + /* +-/* + Copyright (C) 2010 Amdatu.org + + This program is free software: you can redistribute it and/or modify +@@ -23,7 +22,7 @@ + /** + * Interface of the tenant service. Responsible for managing tenants. Service adapters + * are used to create tenant aware services. The tenant service will provide tenants +- * and the Felix dependency manager will automatically invoke a service instance for ++ * and the Felix dependency manager will automatically invoke a service instance for + * each tenant aware service in which the tenant is injected. + */ + public interface TenantManagementService { +@@ -31,23 +30,23 @@ + * Gets all tenants, or an empty list if there are none. + */ + List<TenantEntity> getTenants() throws TenantException; +- ++ + /** + * Gets the tenant with the given ID, or <code>null</code> if this doesn't exist. + */ + TenantEntity getTenantById(String id) throws TenantException; +- ++ + /** + * Gets all tenants that match the given properties, or an empty list if there are none. + */ + List<TenantEntity> getTenants(Map<String, String> properties) throws TenantException; +- ++ + /** + * Creates a new tenant with the specified id and name. + * @throws TenantException in case a tenant with the specified id already exists. + */ + TenantEntity createTenant(String id, String name) throws TenantException; +- ++ + void updateTenant(TenantEntity tenant) throws TenantException; + + void deleteTenant(TenantEntity tenant) throws TenantException; +Index: amdatu-opensocial/gadgetmanagement/pom.xml +=================================================================== +--- amdatu-opensocial/gadgetmanagement/pom.xml (revision 564) ++++ amdatu-opensocial/gadgetmanagement/pom.xml (working copy) +@@ -12,8 +12,8 @@ + <packaging>bundle</packaging> + <name>Amdatu Open Social - Gadget Management</name> + <description>Provides a service to manage gadgets stored in the gadget store</description> +- +- <dependencies> ++ ++ <dependencies> + <dependency> + <groupId>org.amdatu.web</groupId> + <artifactId>httpcontext</artifactId> +@@ -32,7 +32,7 @@ + <version>${platform.version}</version> + <scope>provided</scope> + <type>bundle</type> +- </dependency> ++ </dependency> + <dependency> + <groupId>org.amdatu.cassandra</groupId> + <artifactId>listener</artifactId> +@@ -52,7 +52,7 @@ + <artifactId>shindig</artifactId> + <scope>provided</scope> + <type>bundle</type> +- </dependency> ++ </dependency> + <dependency> + <groupId>org.json</groupId> + <artifactId>json</artifactId> +@@ -70,8 +70,15 @@ + <version>${platform.version}</version> + <scope>provided</scope> + </dependency> ++ <dependency> ++ <groupId>org.amdatu.authentication</groupId> ++ <artifactId>contextmanager</artifactId> ++ <version>${platform.version}</version> ++ <scope>provided</scope> ++ <type>bundle</type> ++ </dependency> + </dependencies> +- ++ + <build> + <plugins> + <plugin> +@@ -80,12 +87,12 @@ + <configuration> + <instructions> + <Bundle-Activator>org.amdatu.opensocial.gadgetmanagement.osgi.Activator</Bundle-Activator> +- <Bundle-SymbolicName> org.amdatu.opensocial.gadgetmanagement</Bundle-SymbolicName> ++ <Bundle-SymbolicName> org.amdatu.opensocial.gadgetmanagement</Bundle-SymbolicName> + <Embed-Dependency>*;scope=compile</Embed-Dependency> + <Embed-Transitive>true</Embed-Transitive> + </instructions> + </configuration> +- </plugin> +- </plugins> +- </build> ++ </plugin> ++ </plugins> ++ </build> + </project> +Index: amdatu-opensocial/gadgetmanagement/src/main/java/org/amdatu/opensocial/gadgetmanagement/osgi/Activator.java +=================================================================== +--- amdatu-opensocial/gadgetmanagement/src/main/java/org/amdatu/opensocial/gadgetmanagement/osgi/Activator.java (revision 564) ++++ amdatu-opensocial/gadgetmanagement/src/main/java/org/amdatu/opensocial/gadgetmanagement/osgi/Activator.java (working copy) +@@ -16,7 +16,7 @@ + */ + package org.amdatu.opensocial.gadgetmanagement.osgi; + +-import org.amdatu.authentication.tokenprovider.TokenProvider; ++import org.amdatu.authentication.contextmanager.ContextManager; + import org.amdatu.cassandra.listener.ColumnFamilyAvailable; + import org.amdatu.cassandra.persistencemanager.CassandraPersistenceManager; + import org.amdatu.libraries.utilities.osgi.ServiceDependentActivator; +@@ -51,19 +51,19 @@ + String gadgetFilter = "(" + ColumnFamilyAvailable.FILTER_NAME + "=" + GadgetStore.CF_GADGET + ")"; + String keyspaceFilter = + "(" + CassandraPersistenceManager.KEYSPACE_AWARE_KEY + "=" +- + CassandraPersistenceManager.DEFAULT_KEYSPACE + ")"; ++ + CassandraPersistenceManager.DEFAULT_KEYSPACE + ")"; + gadgetFilter = "(&" + gadgetFilter + keyspaceFilter + ")"; + manager.add( +- createComponent() +- .setInterface(new String[]{GadgetManagement.class.getName(), ResourceProvider.class.getName()}, null) +- .setImplementation(GadgetManagementServiceImpl.class) +- .add(createServiceDependency().setService(LogService.class).setRequired(true)) +- .add(createServiceDependency().setService(UserAdmin.class).setRequired(true)) +- .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))); ++ createComponent() ++ .setInterface(new String[]{GadgetManagement.class.getName(), ResourceProvider.class.getName()}, null) ++ .setImplementation(GadgetManagementServiceImpl.class) ++ .add(createServiceDependency().setService(LogService.class).setRequired(true)) ++ .add(createServiceDependency().setService(UserAdmin.class).setRequired(true)) ++ .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(ContextManager.class).setRequired(true)) ++ .add(createServiceDependency().setService(CassandraPersistenceManager.class, keyspaceFilter).setRequired(true))); + } + + @Override +Index: amdatu-opensocial/gadgetmanagement/src/main/java/org/amdatu/opensocial/gadgetmanagement/service/GadgetManagementServiceImpl.java +=================================================================== +--- amdatu-opensocial/gadgetmanagement/src/main/java/org/amdatu/opensocial/gadgetmanagement/service/GadgetManagementServiceImpl.java (revision 564) ++++ amdatu-opensocial/gadgetmanagement/src/main/java/org/amdatu/opensocial/gadgetmanagement/service/GadgetManagementServiceImpl.java (working copy) +@@ -48,9 +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.authentication.contextmanager.ContextManager; ++import org.amdatu.authentication.contextmanager.UnknownProviderException; ++import org.amdatu.authorization.login.service.LoginContextProvider; + import org.amdatu.authorization.login.service.LoginService; + import org.amdatu.cassandra.persistencemanager.CassandraException; + import org.amdatu.libraries.utilities.ConversionUtil; +@@ -102,7 +102,7 @@ + private volatile UserAdmin m_userAdmin; + private volatile HttpContextServiceFactory m_httpContextFactoryService; + private volatile GadgetStore m_gadgetStore; +- private volatile TokenProvider m_tokenProvider; ++ private volatile ContextManager m_contextManager; + + private Component m_httpContextComponent; + +@@ -284,9 +284,10 @@ + public Response getMyGadgets(@Context HttpHeaders headers, @Context HttpServletRequest request) { + JSONObject jsonObject = new JSONObject(); + List<JSONObject> gadgets = new ArrayList<JSONObject>(); +- String viewer = getUserNameFromRequest(request); +- String errorMsg = "An error occurred while retrieving gadgets for viewer '" + viewer + "'."; ++ String errorMsg = ""; + try { ++ String viewer = m_contextManager.getValue(LoginContextProvider.ID, LoginContextProvider.USERNAME); ++ errorMsg = "An error occurred while retrieving gadgets for viewer '" + viewer + "'."; + User user = null; + String[] gadgetIds = null; + if (viewer != null && !"anonymous".equals(viewer)) { +@@ -381,6 +382,9 @@ + catch (IOException e) { + m_logService.log(LogService.LOG_ERROR, errorMsg, e); + } ++ catch (UnknownProviderException e) { ++ m_logService.log(LogService.LOG_ERROR, "Loging context unavailable", e); ++ } + + return Response.ok(jsonObject.toString(), MediaType.APPLICATION_JSON_TYPE).cacheControl(m_noCacheControl).build(); + } +@@ -639,12 +643,17 @@ + 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; ++ try { ++ // Verify if we have a valid authentication token holding a username, if so add the authenticated user as viewer ++ String userName = m_contextManager.getValue(LoginContextProvider.ID, LoginContextProvider.USERNAME); ++ if (userName != null && !"".equals(userName)) { ++ viewerId = userName; ++ ownerId = userName; ++ } + } ++ catch (UnknownProviderException e) { ++ m_logService.log(LogService.LOG_WARNING, "Login context uinavailable, could not retrieve user", e); ++ } + st.setViewerId(viewerId); + st.setOwnerId(ownerId); + +@@ -691,25 +700,6 @@ + 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; +- } +- + private String toAbsoluteUrl(String url, HttpServletRequest request) { + if (url.startsWith("/")) { + // This is a relative URL, convert to absolute URL +Index: amdatu-release/pom.xml +=================================================================== +--- amdatu-release/pom.xml (revision 564) ++++ amdatu-release/pom.xml (working copy) +@@ -13,48 +13,55 @@ + <dependencies> + <!-- Authentication bundles --> + <dependency> ++ <groupId>org.amdatu.authentication</groupId> ++ <artifactId>contextmanager</artifactId> ++ <version>${platform.version}</version> ++ <scope>compile</scope> ++ <type>bundle</type> ++ </dependency> ++ <dependency> + <groupId>org.amdatu.authentication.oauth</groupId> +- <artifactId>api</artifactId> ++ <artifactId>api</artifactId> + <version>${platform.version}</version> + <scope>compile</scope> + <type>bundle</type> +- </dependency> ++ </dependency> + <dependency> + <groupId>org.amdatu.authentication.oauth</groupId> +- <artifactId>server</artifactId> ++ <artifactId>server</artifactId> + <version>${platform.version}</version> + <scope>compile</scope> + <type>bundle</type> + </dependency> + <dependency> + <groupId>org.amdatu.authentication.oauth</groupId> +- <artifactId>client</artifactId> ++ <artifactId>client</artifactId> + <version>${platform.version}</version> + <scope>compile</scope> + <type>bundle</type> +- </dependency> ++ </dependency> + <dependency> + <groupId>org.amdatu.authentication.oauth</groupId> +- <artifactId>consumerregistry-fs</artifactId> ++ <artifactId>consumerregistry-fs</artifactId> + <version>${platform.version}</version> + <scope>compile</scope> + <type>bundle</type> +- </dependency> ++ </dependency> + <dependency> + <groupId>org.amdatu.authentication</groupId> +- <artifactId>tokenprovider</artifactId> ++ <artifactId>tokenprovider</artifactId> + <version>${platform.version}</version> + <scope>compile</scope> + <type>bundle</type> +- </dependency> ++ </dependency> + <dependency> + <groupId>org.amdatu.authentication.tokenstore</groupId> +- <artifactId>mem</artifactId> ++ <artifactId>mem</artifactId> + <version>${platform.version}</version> + <scope>compile</scope> + <type>bundle</type> +- </dependency> +- ++ </dependency> ++ + <!-- Authorization bundles --> + <dependency> + <groupId>org.amdatu.authorization.login</groupId> +@@ -76,7 +83,7 @@ + <version>${platform.version}</version> + <scope>compile</scope> + <type>bundle</type> +- </dependency> ++ </dependency> + <dependency> + <groupId>org.amdatu.authorization.useradmin</groupId> + <artifactId>rest</artifactId> +@@ -192,7 +199,7 @@ + <version>${platform.version}</version> + <scope>compile</scope> + <type>bundle</type> +- </dependency> ++ </dependency> + + <!-- Open Social bundles --> + <dependency> +@@ -238,7 +245,7 @@ + <version>${platform.version}</version> + <scope>compile</scope> + <type>bundle</type> +- </dependency> ++ </dependency> + <dependency> + <groupId>org.amdatu.semanticweb</groupId> + <artifactId>sesame</artifactId> +Index: amdatu-web/httpcontext/pom.xml +=================================================================== +--- amdatu-web/httpcontext/pom.xml (revision 564) ++++ amdatu-web/httpcontext/pom.xml (working copy) +@@ -13,6 +13,22 @@ + <name>Amdatu Web - HTTP Context</name> + <description>Provides a HTTPContext implementation</description> + ++ <dependencies> ++ <dependency> ++ <groupId>org.amdatu.authentication</groupId> ++ <artifactId>tokenprovider</artifactId> ++ <version>${platform.version}</version> ++ <scope>provided</scope> ++ </dependency> ++ <dependency> ++ <groupId>org.amdatu.authentication</groupId> ++ <artifactId>contextmanager</artifactId> ++ <version>${platform.version}</version> ++ <scope>provided</scope> ++ <type>bundle</type> ++ </dependency> ++ </dependencies> ++ + <build> + <plugins> + <plugin> +Index: amdatu-web/httpcontext/src/main/java/org/amdatu/web/httpcontext/osgi/Activator.java +=================================================================== +--- amdatu-web/httpcontext/src/main/java/org/amdatu/web/httpcontext/osgi/Activator.java (revision 564) ++++ amdatu-web/httpcontext/src/main/java/org/amdatu/web/httpcontext/osgi/Activator.java (working copy) +@@ -16,8 +16,15 @@ + */ + package org.amdatu.web.httpcontext.osgi; + ++import java.util.Dictionary; ++import java.util.Hashtable; ++ ++import javax.servlet.Filter; ++ ++import org.amdatu.authentication.contextmanager.ContextManager; + import org.amdatu.web.httpcontext.HttpContextServiceFactory; + import org.amdatu.web.httpcontext.service.HttpContextFactoryServiceImpl; ++import org.amdatu.web.httpcontext.service.HttpRequestContextResolver; + import org.apache.felix.dm.DependencyActivatorBase; + import org.apache.felix.dm.DependencyManager; + import org.osgi.framework.BundleContext; +@@ -30,13 +37,26 @@ + */ + public class Activator extends DependencyActivatorBase { + @Override +- public void init(BundleContext context, DependencyManager manager) throws Exception { ++ public void init(BundleContext context, DependencyManager manager) throws Exception { + manager.add( +- createComponent() +- .setImplementation(HttpContextFactoryServiceImpl.class) +- .setInterface(HttpContextServiceFactory.class.getName(), null) +- .add(createServiceDependency().setService(HttpService.class).setRequired(true)) +- .add(createServiceDependency().setService(LogService.class).setRequired(true))); ++ createComponent() ++ .setImplementation(HttpContextFactoryServiceImpl.class) ++ .setInterface(HttpContextServiceFactory.class.getName(), null) ++ .add(createServiceDependency().setService(HttpService.class).setRequired(true)) ++ .add(createServiceDependency().setService(LogService.class).setRequired(true))); ++ ++ // Create and register a HttpSessionContext resolver filter. This filter is mapped on * ++ // and will set context information into SessionContext based on information send along ++ // with a HTTP context ++ Dictionary<String, String> filterProperties = new Hashtable<String, String>(); ++ filterProperties.put("pattern", ".*"); ++ filterProperties.put("service.ranking", "99999999"); // We definitely want to be the first!!!! ++ filterProperties.put("contextId", "sesioncontextfilter"); ++ manager.add( ++ createComponent() ++ .setImplementation(HttpRequestContextResolver.class) ++ .setInterface(Filter.class.getName(), filterProperties) ++ .add(createServiceDependency().setService(ContextManager.class).setRequired(true))); + } + + @Override +Index: amdatu-web/httpcontext/src/main/java/org/amdatu/web/httpcontext/service/HttpRequestContextResolver.java +=================================================================== +--- amdatu-web/httpcontext/src/main/java/org/amdatu/web/httpcontext/service/HttpRequestContextResolver.java (revision 0) ++++ amdatu-web/httpcontext/src/main/java/org/amdatu/web/httpcontext/service/HttpRequestContextResolver.java (revision 0) +@@ -0,0 +1,56 @@ ++/* ++ 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.web.httpcontext.service; ++ ++import java.io.IOException; ++import java.util.HashMap; ++import java.util.Map; ++ ++import javax.servlet.Filter; ++import javax.servlet.FilterChain; ++import javax.servlet.FilterConfig; ++import javax.servlet.ServletException; ++import javax.servlet.ServletRequest; ++import javax.servlet.ServletResponse; ++ ++import org.amdatu.authentication.contextmanager.ContextManager; ++import org.amdatu.authentication.contextmanager.ContextProvider; ++ ++/** ++ * This filter captures HTTP requests and invokes resolve() on the ContextManager. The ContextManager will delegate the ++ * resolving to all available Context Providers. Any provider that can resolve context information from a HTTP request ++ * can do so. ++ * ++ * @author ivol ++ */ ++public class HttpRequestContextResolver implements Filter { ++ // Service dependencies, injected by the dependency manager ++ private volatile ContextManager m_contextManager; ++ ++ public void init(FilterConfig filterConfig) throws ServletException { ++ } ++ ++ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { ++ Map<String, Object> contextProperties = new HashMap<String, Object>(); ++ contextProperties.put(ContextProvider.PROPERTY_HTTP_REQUEST, request); ++ m_contextManager.resolve(contextProperties); ++ chain.doFilter(request, response); ++ } ++ ++ public void destroy() { ++ } ++} +Index: src/main/resources/conf/felix-config.properties +=================================================================== +--- src/main/resources/conf/felix-config.properties (revision 564) ++++ src/main/resources/conf/felix-config.properties (working copy) +@@ -110,6 +110,7 @@ + reference:file:amdatu-application/org.amdatu.authorization.login.service-${platform.version}.jar \ + reference:file:amdatu-application/org.amdatu.authorization.useradmin.gadget-${platform.version}.jar \ + reference:file:amdatu-application/org.amdatu.authorization.useradmin.rest-${platform.version}.jar \ ++ reference:file:amdatu-application/org.amdatu.authentication.contextmanager-${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 \
