Return-Path: X-Original-To: apmail-sling-commits-archive@www.apache.org Delivered-To: apmail-sling-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id DF45210A3A for ; Mon, 5 Aug 2013 10:09:26 +0000 (UTC) Received: (qmail 54017 invoked by uid 500); 5 Aug 2013 10:09:26 -0000 Delivered-To: apmail-sling-commits-archive@sling.apache.org Received: (qmail 53985 invoked by uid 500); 5 Aug 2013 10:09:26 -0000 Mailing-List: contact commits-help@sling.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@sling.apache.org Delivered-To: mailing list commits@sling.apache.org Received: (qmail 53978 invoked by uid 99); 5 Aug 2013 10:09:25 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 05 Aug 2013 10:09:25 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 05 Aug 2013 10:09:15 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id BD8482388831; Mon, 5 Aug 2013 10:08:52 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1510413 [1/2] - in /sling/trunk/bundles: api/ api/src/main/java/org/apache/sling/api/resource/ extensions/serviceusermapper/ extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/ extensions/serviceusermapper/src/m... Date: Mon, 05 Aug 2013 10:08:51 -0000 To: commits@sling.apache.org From: fmeschbe@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20130805100852.BD8482388831@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: fmeschbe Date: Mon Aug 5 10:08:50 2013 New Revision: 1510413 URL: http://svn.apache.org/r1510413 Log: SLING-2944 Implement Service User Mapper * Add ServiceUserMapper service and implementation bundle * Add service login methods to ResourceResolverFactory and SlingRepository * Add implementations of new methods Added: sling/trunk/bundles/extensions/serviceusermapper/ - copied from r1499677, sling/whiteboard/fmeschbe/deprecate_login_administrative/serviceusermapper/ sling/trunk/bundles/jcr/api/src/main/java/org/apache/sling/jcr/api/package-info.java sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/package-info.java sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/util/package-info.java sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/RepositoryHolder.java - copied unchanged from r1499675, sling/whiteboard/fmeschbe/deprecate_login_administrative/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/RepositoryHolder.java Modified: sling/trunk/bundles/api/ (props changed) sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/ResourceProviderFactory.java sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/ResourceResolverFactory.java sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/package-info.java sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/ServiceUserMapper.java sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/Mapping.java sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImpl.java sling/trunk/bundles/extensions/serviceusermapper/src/test/java/org/apache/sling/serviceusermapping/impl/MappingTest.java sling/trunk/bundles/extensions/serviceusermapper/src/test/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImplTest.java sling/trunk/bundles/jcr/api/ (props changed) sling/trunk/bundles/jcr/api/pom.xml sling/trunk/bundles/jcr/api/src/main/java/org/apache/sling/jcr/api/SlingRepository.java sling/trunk/bundles/jcr/base/ (props changed) sling/trunk/bundles/jcr/base/pom.xml sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepository.java sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/internal/loader/Loader.java sling/trunk/bundles/jcr/jackrabbit-server/ (props changed) sling/trunk/bundles/jcr/jackrabbit-server/pom.xml sling/trunk/bundles/jcr/jackrabbit-server/src/main/java/org/apache/sling/jcr/jackrabbit/server/impl/Activator.java (props changed) sling/trunk/bundles/jcr/jackrabbit-server/src/main/java/org/apache/sling/jcr/jackrabbit/server/impl/SlingServerRepository.java (contents, props changed) sling/trunk/bundles/jcr/jackrabbit-server/src/main/resources/OSGI-INF/metatype/metatype.properties sling/trunk/bundles/jcr/resource/ (props changed) sling/trunk/bundles/jcr/resource/pom.xml sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProvider.java sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProviderFactory.java sling/trunk/bundles/resourceresolver/ (props changed) sling/trunk/bundles/resourceresolver/pom.xml sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryActivator.java sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryImpl.java sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/MockedResourceResolverImplTest.java sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverImplTest.java sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverMangleNamespacesTest.java Propchange: sling/trunk/bundles/api/ ------------------------------------------------------------------------------ --- svn:mergeinfo (added) +++ svn:mergeinfo Mon Aug 5 10:08:50 2013 @@ -0,0 +1 @@ +/sling/whiteboard/fmeschbe/deprecate_login_administrative/api:1458693-1499665 Modified: sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/ResourceProviderFactory.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/ResourceProviderFactory.java?rev=1510413&r1=1510412&r2=1510413&view=diff ============================================================================== --- sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/ResourceProviderFactory.java (original) +++ sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/ResourceProviderFactory.java Mon Aug 5 10:08:50 2013 @@ -23,71 +23,111 @@ import java.util.Map; /** * The ResourceProviderFactory defines the service API to get and * create ResourceProviderss dynamically on a per usage base. - * * Instead of sharing a resource provider between resource resolvers, the * factory allows to create an own instance of a resource provider per resource - * resolver. - * The factory also supports authentication. + * resolver. The factory also supports authentication. *

- * If the resource provider is not used anymore and implements the {@link DynamicResourceProvider} - * interface, the close method should be called. + * If the resource provider is not used anymore and implements the + * {@link DynamicResourceProvider} interface, the close method should be called. * * @since 2.2.0 */ public interface ResourceProviderFactory { /** - * A required resource provider factory is accessed directly when a new resource resolver - * is created. Only if authentication against all required resource provider factories - * is successful, a resource resolver is created by the resource resolver factory. - * Boolean service property, default value is false + * A required resource provider factory is accessed directly when a new + * resource resolver is created. Only if authentication against all required + * resource provider factories is successful, a resource resolver is created + * by the resource resolver factory. Boolean service property, default value + * is false */ String PROPERTY_REQUIRED = "required"; /** + * The authentication information property referrring to the bundle + * providing a service for which a resource provider is to be retrieved. If + * this property is provided, the + * {@link ResourceResolverFactory#SUBSERVICE} property may also be + * present. + *

+ * {@link ResourceResolverFactory} implementations must provide this + * property if their implementation of the + * {@link ResourceResolverFactory#getServiceResourceResolver(Map)} method + * use a resource provider factory. + *

+ * The type of this property, if present, is + * org.osgi.framework.Bundle. + * + * @since 2.4 (bundle version 2.5.0) + */ + String SERVICE_BUNDLE = "sling.service.bundle"; + + /** * Returns a new {@link ResourceProvider} instance with further * configuration taken from the given authenticationInfo map. * Generally this map will contain a user name and password to authenticate. *

+ * The authenticationInfo map will in general contain the same + * information as provided to the respective {@link ResourceResolver} + * method. For + *

* If the authenticationInfo map is null the - * ResourceProvider returned will generally not be authenticated - * and only provide minimal privileges, if any at all. + * ResourceProvider returned will generally not be + * authenticated and only provide minimal privileges, if any at all. + *

+ * Implementations must ignore the {@value ResourceResolverFactory#USER} + * property the {@link #SERVICE_BUNDLE} property is provided to implement + * service authentication. + *

+ * The {@value ResourceResolverFactory#USER_IMPERSONATION} property is + * obeyed but requires that the actual user has permission to impersonate as + * the requested user. If such permission is missing, a + * {@code LoginException} is thrown. * - * @param authenticationInfo - * A map of further credential information which may be used by - * the implementation to parameterize how the resource provider is - * created. This may be null. - * @return A {@link ResourceProvider} according to the authenticationInfo. - * @throws LoginException - * If an error occurs creating the new ResourceProvider with the - * provided credential data. + * @param authenticationInfo A map of further credential information which + * may be used by the implementation to parameterize how the + * resource provider is created. This may be null. + * @return A {@link ResourceProvider} according to the + * authenticationInfo. + * @throws LoginException If an error occurs creating the new + * ResourceProvider with the provided credential + * data. + * @see Service + * Authentication */ ResourceProvider getResourceProvider(Map authenticationInfo) throws LoginException; /** * Returns a new {@link ResourceProvider} instance with administrative - * privileges with further configuration taken from the given authenticationInfo - * map. + * privileges with further configuration taken from the given + * authenticationInfo map. *

* Note, that if the authenticationInfo map contains the - * {@link ResourceResolverFactory#USER_IMPERSONATION} attribute the ResourceProvider returned will only - * have administrative privileges if the user identified by the property has administrative + * {@link ResourceResolverFactory#USER_IMPERSONATION} attribute the + * ResourceProvider returned will only have administrative + * privileges if the user identified by the property has administrative * privileges. *

- * NOTE: This method is intended for use by infrastructure bundles to access the - * resource tree and provide general services. This method MUST not be used to handle client - * requests of whatever kinds. To handle client requests a regular authenticated resource - * provider retrieved through {@link #getResourceProvider(Map)} must be used. + * Implementations of this method should throw {@code LoginException} if + * they don't support it. * - * @param authenticationInfo - * A map of further credential information which may be used by - * the implementation to parameterize how the resource provider is - * created. This may be null. + * @param authenticationInfo A map of further credential information which + * may be used by the implementation to parameterize how the + * resource provider is created. This may be null. * @return A {@link ResourceProvider} with administrative privileges unless - * the {@link ResourceResolverFactory#USER_IMPERSONATION} was set in the authenticationInfo. - * @throws LoginException - * If an error occurs creating the new ResourceResolverFactory with the - * provided credential data. + * the {@link ResourceResolverFactory#USER_IMPERSONATION} was set in + * the authenticationInfo. + * @throws LoginException If an error occurs creating the new + * ResourceResolverFactory with the provided + * credential data. + * @deprecated as of 2.4 (bundle version 2.5.0) because of inherent security + * issues. Implementations may implement this method at their + * discretion but must support the new service based resource + * provider generation in the {@link #getResourceProvider(Map)} + * method honouring the {@link #SERVICE_BUNDLE} and + * {@link ResourceResolverFactory#SUBSERVICE} properties. */ + @Deprecated ResourceProvider getAdministrativeResourceProvider(Map authenticationInfo) throws LoginException; } Modified: sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/ResourceResolverFactory.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/ResourceResolverFactory.java?rev=1510413&r1=1510412&r2=1510413&view=diff ============================================================================== --- sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/ResourceResolverFactory.java (original) +++ sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/ResourceResolverFactory.java Mon Aug 5 10:08:50 2013 @@ -33,11 +33,9 @@ public interface ResourceResolverFactory /** * Name of the authentication information property providing the name of the - * user for which the {@link #getResourceResolver(Map)} and - * {@link #getAdministrativeResourceResolver(Map)} create resource - * resolvers. on whose behalf the request is being handled. This property - * may be missing in which case an anonymous (unauthenticated) resource - * resolver is returned if possible. + * user for which the {@link #getResourceResolver(Map)} method creates + * resource resolvers. This property may be missing in which case an + * anonymous (unauthenticated) resource resolver is returned if possible. *

* The type of this property, if present, is String. */ @@ -54,13 +52,14 @@ public interface ResourceResolverFactory /** * Name of the authentication information property causing the - * {@link #getResourceResolver(Map)} and - * {@link #getAdministrativeResourceResolver(Map)} methods to try to - * impersonate the created resource resolver to the requested user and - * return the impersonated resource resolver. + * {@link #getResourceResolver(Map)}, + * {@link #getAdministrativeResourceResolver(Map)}, and + * {@link #getServiceResourceResolver(Map)} methods to try to impersonate + * the created resource resolver to the requested user and return the + * impersonated resource resolver. *

* If this impersonation fails the actual creation of the resource resolver - * fails. + * fails and a {@code LoginException} is thrown. *

* If this property is not set in the authentication info or is set to the * same name as the {@link #USER user.name} property this property is @@ -71,6 +70,17 @@ public interface ResourceResolverFactory String USER_IMPERSONATION = "user.impersonation"; /** + * Name of the authentication information property providing the Subservice + * Name for the service requesting a resource resolver. + *

+ * The type of this property, if present, is String. + * + * @see #getServiceResourceResolver(Map) + * @since 2.4 (bundle version 2.5.0) + */ + String SUBSERVICE = "sling.service.subservice"; + + /** * Returns a new {@link ResourceResolver} instance with further * configuration taken from the given authenticationInfo map. * Generally this map will contain a user name and password to authenticate. @@ -78,6 +88,10 @@ public interface ResourceResolverFactory * If the authenticationInfo map is null the * ResourceResolver returned will generally not be * authenticated and only provide minimal privileges, if any at all. + *

+ * The {@link #USER_IMPERSONATION} property is obeyed but requires that the + * actual user has permission to impersonate as the requested user. If such + * permission is missing, a {@code LoginException} is thrown. * * @param authenticationInfo A map of further credential information which * may be used by the implementation to parameterize how the @@ -88,8 +102,7 @@ public interface ResourceResolverFactory * ResourceResolver with the provided credential * data. */ - ResourceResolver getResourceResolver(Map authenticationInfo) - throws LoginException; + ResourceResolver getResourceResolver(Map authenticationInfo) throws LoginException; /** * Returns a new {@link ResourceResolver} instance with administrative @@ -104,8 +117,13 @@ public interface ResourceResolverFactory * NOTE: This method is intended for use by infrastructure bundles to * access the repository and provide general services. This method MUST not * be used to handle client requests of whatever kinds. To handle client - * requests a regular authenticated resource resolver retrieved - * through {@link #getResourceResolver(Map)} must be used. + * requests a regular authenticated resource resolver retrieved through + * {@link #getResourceResolver(Map)} must be used. + *

+ * This method is deprecated. Services running in the Sling system should + * use the {@link #getServiceResourceResolver(Map)} method instead. + * Implementations of this method should throw {@code LoginException} if + * they don't support it. * * @param authenticationInfo A map of further credential information which * may be used by the implementation to parameterize how the @@ -116,7 +134,39 @@ public interface ResourceResolverFactory * @throws LoginException If an error occurs creating the new * ResourceResolver with the provided credential * data. + * @deprecated as of 2.4 (bundle version 2.5.0) because of inherent security + * issues. Services requiring specific permissions should use + * the {@link #getServiceResourceResolver(Map)} instead. + */ + @Deprecated + ResourceResolver getAdministrativeResourceResolver(Map authenticationInfo) throws LoginException; + + /** + * Returns a new {@link ResourceResolver} instance with privileges assigned + * to the service provided by the calling bundle. + *

+ * The provided {@code authenticationInfo} map may be used to provide + * additional information such as the {@value #SUBSERVICE}. + * {@link #USER} and {@link #PASSWORD} properties provided in the map are + * ignored. + *

+ * The {@link #USER_IMPERSONATION} property is obeyed but requires that the + * actual service user has permission to impersonate as the requested user. + * If such permission is missing, a {@code LoginException} is thrown. + * + * @param authenticationInfo A map of further service information which may + * be used by the implementation to parametrize how the resource + * resolver is created. This may be null. + * @return A {@link ResourceResolver} with appropriate permissions to + * execute the service. + * @throws LoginException If an error occurrs creating the new + * ResourceResolver for the service represented by + * the calling bundle. + * @since 2.4 (bundle version 2.5.0) to replace + * {@link #getAdministrativeResourceResolver(Map)} + * @see Service + * Authentication */ - ResourceResolver getAdministrativeResourceResolver( - Map authenticationInfo) throws LoginException; + ResourceResolver getServiceResourceResolver(Map authenticationInfo) throws LoginException; } Modified: sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/package-info.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/package-info.java?rev=1510413&r1=1510412&r2=1510413&view=diff ============================================================================== --- sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/package-info.java (original) +++ sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/package-info.java Mon Aug 5 10:08:50 2013 @@ -17,7 +17,7 @@ * under the License. */ -@Version("2.3.2") +@Version("2.4") package org.apache.sling.api.resource; import aQute.bnd.annotation.Version; Modified: sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/ServiceUserMapper.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/ServiceUserMapper.java?rev=1510413&r1=1499677&r2=1510413&view=diff ============================================================================== --- sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/ServiceUserMapper.java (original) +++ sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/ServiceUserMapper.java Mon Aug 5 10:08:50 2013 @@ -24,7 +24,7 @@ import aQute.bnd.annotation.ProviderType /** * The ServiceUserMapper service can be used to map a service - * provided by a bundle to the name of a user account used to access the + * provided by a bundle to the ID of a user account used to access the * ResourceResolver used by the service to access its data. *

* The goal of this service is to allow services to be implemented accessing the @@ -36,9 +36,9 @@ import aQute.bnd.annotation.ProviderType * bundle. Other services may be implemented in multiple bundles. In certain * cases there may be sub-services requiring different access levels. For * example a couple of bundles may implement a "mail" service where each bundle - * implement implements a part of the service such as the "smtp", "queuing", and + * implements a part of the service such as the "smtp", "queuing", and * "delivery" sub services. Such sub services are identified with the - * {@code serviceInfo} parameter on the method calls. + * {@code subServiceName} parameter on the method calls. *

* In addition to allowing to phase out the use of * {@code ResourceResolver.getAdministrativeResourceResolver} and @@ -50,6 +50,10 @@ import aQute.bnd.annotation.ProviderType * {@code SlingRepository} services. *

* This service is not intended to be implemented by clients. + * + * @see Service Authentication */ @ProviderType public interface ServiceUserMapper { @@ -62,35 +66,43 @@ public interface ServiceUserMapper { String BUNDLE_HEADER_SERVICE_NAME = "Sling-Service"; /** - * Returns the name of the service represented by the {@code bundle} and the - * {@code serviceInfo}. + * Returns the ID of the service represented by the given {@code bundle} and + * the {@code subServiceName}. *

- * The service name consists of a name derived from the bundle and the - * {@code serviceInfo} value if not {@code null} or empty. + * The service ID consists of a name derived from the bundle and the + * {@code serviceInfo} value if not {@code null} or empty: + * + *

+     * serviceID = serviceName [ ":" subServiceName ] .
+     * serviceName = Sling-Service manifest header or bundle symbolic name .
+     * 
+ *

+ * The service name for a bundle is taken from the + * {@value #BUNDLE_HEADER_SERVICE_NAME} manifest header of the bundle. If + * there is no such header or the value is empty, the bundle's symbolic name + * is used. * * @param bundle The bundle implementing the service request access to * resources. - * @param serviceInfo Additional information about the concrete service - * requesting access. This parameter is optional and may be - * an empty string or {@code null}. - * @return The name of the service represented by the bundle along with the + * @param subServiceName Name of the sub service. This parameter is optional and + * may be an empty string or {@code null}. + * @return The ID of the service represented by the bundle along with the * additional service information. */ - String getServiceName(Bundle bundle, String serviceInfo); + String getServiceID(Bundle bundle, String subServiceName); /** - * Returns the name of a user to the be used to access the Sling Resource - * tree or the JCR Repository. + * Returns the ID of a user to access the data store on behalf of the + * service. * * @param bundle The bundle implementing the service request access to * resources. - * @param serviceInfo Additional information about the concrete service - * requesting access. This parameter is optional and may be - * an empty string or {@code null}. - * @return The name of the user to use to provide access to the resources - * for the service. This may be {@code null} if no particular user - * can be derived for the service identified by the bundle and the + * @param subServiceName Name of the sub service. This parameter is optional and + * may be an empty string or {@code null}. + * @return The ID of the user to use to provide access to the resources for + * the service. This may be {@code null} if no particular user can + * be derived for the service identified by the bundle and the * optional {@code serviceInfo}. */ - String getUserForService(Bundle bundle, String serviceInfo); + String getServiceUserID(Bundle bundle, String subServiceName); } Modified: sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/Mapping.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/Mapping.java?rev=1510413&r1=1499677&r2=1510413&view=diff ============================================================================== --- sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/Mapping.java (original) +++ sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/Mapping.java Mon Aug 5 10:08:50 2013 @@ -26,7 +26,7 @@ class Mapping { private final String serviceName; - private final String serviceInfo; + private final String subServiceName; private final String userName; @@ -34,7 +34,7 @@ class Mapping { * Creates a mapping entry for the entry specification of the form: * *

-     * spec = serviceName [ ":" serviceInfo ] "=" userName .
+     * spec = serviceName [ ":" subServiceName ] "=" userName .
      * 
* * @param spec The mapping specification. @@ -57,10 +57,10 @@ class Mapping { if (colon < 0 || colon > equals) { this.serviceName = spec.substring(0, equals); - this.serviceInfo = null; + this.subServiceName = null; } else { this.serviceName = spec.substring(0, colon); - this.serviceInfo = spec.substring(colon + 1, equals); + this.subServiceName = spec.substring(colon + 1, equals); } this.userName = spec.substring(equals + 1); @@ -72,12 +72,12 @@ class Mapping { * * @param serviceName The name of the service to match. If this is * {@code null} this mapping will not match. - * @param serviceInfo The info of the service to match. This may be + * @param subServiceName The Subservice Name to match. This may be * {@code null}. * @return The user name if this mapping matches or {@code null} otherwise. */ - String map(final String serviceName, final String serviceInfo) { - if (this.serviceName.equals(serviceName) && equals(this.serviceInfo, serviceInfo)) { + String map(final String serviceName, final String subServiceName) { + if (this.serviceName.equals(serviceName) && equals(this.subServiceName, subServiceName)) { return userName; } Modified: sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImpl.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImpl.java?rev=1510413&r1=1499677&r2=1510413&view=diff ============================================================================== --- sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImpl.java (original) +++ sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImpl.java Mon Aug 5 10:08:50 2013 @@ -44,8 +44,8 @@ public class ServiceUserMapperImpl imple @Property( label = "Service Mappings", description = "Provides mappings from service name to user names. " - + "Each entry is of the form 'serviceName [ \":\" serviceInfo ] \"=\" userName' " - + "where serviceName and serviceInfo identify the service and userName " + + "Each entry is of the form 'serviceName [ \":\" subServiceName ] \"=\" userName' " + + "where serviceName and subServiceName identify the service and userName " + "defines the name of the user to provide to the service. Invalid entries are logged and ignored.", unbounded = PropertyUnbounded.ARRAY) private static final String PROP_SERVICE2USER_MAPPING = "user.mapping"; @@ -90,17 +90,17 @@ public class ServiceUserMapperImpl imple this.defaultUser = PropertiesUtil.toString(config.get(PROP_DEFAULT_USER), PROP_DEFAULT_USER_DEFAULT); } - public String getServiceName(Bundle bundle, String serviceInfo) { + public String getServiceID(Bundle bundle, String subServiceName) { final String serviceName = getServiceName(bundle); - return (serviceInfo == null || serviceInfo.length() == 0) ? serviceName : serviceName + ":" + serviceInfo; + return (subServiceName == null || subServiceName.length() == 0) ? serviceName : serviceName + ":" + subServiceName; } - public String getUserForService(Bundle bundle, String serviceInfo) { + public String getServiceUserID(Bundle bundle, String subServiceName) { final String serviceName = getServiceName(bundle); // try with serviceInfo first for (Mapping mapping : this.serviceUserMappings) { - final String user = mapping.map(serviceName, serviceInfo); + final String user = mapping.map(serviceName, subServiceName); if (user != null) { return user; } Modified: sling/trunk/bundles/extensions/serviceusermapper/src/test/java/org/apache/sling/serviceusermapping/impl/MappingTest.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/serviceusermapper/src/test/java/org/apache/sling/serviceusermapping/impl/MappingTest.java?rev=1510413&r1=1499677&r2=1510413&view=diff ============================================================================== --- sling/trunk/bundles/extensions/serviceusermapper/src/test/java/org/apache/sling/serviceusermapping/impl/MappingTest.java (original) +++ sling/trunk/bundles/extensions/serviceusermapper/src/test/java/org/apache/sling/serviceusermapping/impl/MappingTest.java Mon Aug 5 10:08:50 2013 @@ -92,40 +92,40 @@ public class MappingTest { @Test public void test_constructor_and_map() { assertMapping("service", null, "user"); - assertMapping("service", "serviceInfo", "user"); + assertMapping("service", "subServiceName", "user"); } - private void assertMapping(final String serviceName, final String serviceInfo, final String userName) { + private void assertMapping(final String serviceName, final String subServiceName, final String userName) { StringBuilder spec = new StringBuilder(); spec.append(serviceName); - if (serviceInfo != null) { - spec.append(':').append(serviceInfo); + if (subServiceName != null) { + spec.append(':').append(subServiceName); } spec.append('=').append(userName); // spec analysis final Mapping mapping = new Mapping(spec.toString()); TestCase.assertEquals(getField(mapping, "serviceName"), serviceName); - TestCase.assertEquals(getField(mapping, "serviceInfo"), serviceInfo); + TestCase.assertEquals(getField(mapping, "subServiceName"), subServiceName); TestCase.assertEquals(getField(mapping, "userName"), userName); // mapping - TestCase.assertEquals(userName, mapping.map(serviceName, serviceInfo)); - if (serviceInfo == null) { - // Mapping without serviceInfo must not match request with any - // serviceInfo - TestCase.assertNull(mapping.map(serviceName, serviceInfo + "-garbage")); + TestCase.assertEquals(userName, mapping.map(serviceName, subServiceName)); + if (subServiceName == null) { + // Mapping without subServiceName must not match request with any + // subServiceName + TestCase.assertNull(mapping.map(serviceName, subServiceName + "-garbage")); } else { - // Mapping with serviceInfo must not match request without - // serviceInfo + // Mapping with subServiceName must not match request without + // subServiceName TestCase.assertNull(mapping.map(serviceName, null)); } // no match for different service name - TestCase.assertNull(mapping.map(serviceName + "-garbage", serviceInfo)); + TestCase.assertNull(mapping.map(serviceName + "-garbage", subServiceName)); // no match for null service name - TestCase.assertNull(mapping.map(null, serviceInfo)); + TestCase.assertNull(mapping.map(null, subServiceName)); } private String getField(final Object object, final String fieldName) { Modified: sling/trunk/bundles/extensions/serviceusermapper/src/test/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImplTest.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/serviceusermapper/src/test/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImplTest.java?rev=1510413&r1=1499677&r2=1510413&view=diff ============================================================================== --- sling/trunk/bundles/extensions/serviceusermapper/src/test/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImplTest.java (original) +++ sling/trunk/bundles/extensions/serviceusermapper/src/test/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImplTest.java Mon Aug 5 10:08:50 2013 @@ -82,7 +82,7 @@ public class ServiceUserMapperImplTest { }; @Test - public void test_getServiceName() { + public void test_getServiceID() { @SuppressWarnings("serial") Map config = new HashMap() { { @@ -99,16 +99,16 @@ public class ServiceUserMapperImplTest { final ServiceUserMapperImpl sum = new ServiceUserMapperImpl(); sum.configure(config); - TestCase.assertEquals(BUNDLE_SYMBOLIC1, sum.getServiceName(BUNDLE1, null)); - TestCase.assertEquals(SRV, sum.getServiceName(BUNDLE2, null)); - TestCase.assertEquals(BUNDLE_SYMBOLIC1, sum.getServiceName(BUNDLE1, "")); - TestCase.assertEquals(SRV, sum.getServiceName(BUNDLE2, "")); - TestCase.assertEquals(BUNDLE_SYMBOLIC1 + ":" + SUB, sum.getServiceName(BUNDLE1, SUB)); - TestCase.assertEquals(SRV + ":" + SUB, sum.getServiceName(BUNDLE2, SUB)); + TestCase.assertEquals(BUNDLE_SYMBOLIC1, sum.getServiceID(BUNDLE1, null)); + TestCase.assertEquals(SRV, sum.getServiceID(BUNDLE2, null)); + TestCase.assertEquals(BUNDLE_SYMBOLIC1, sum.getServiceID(BUNDLE1, "")); + TestCase.assertEquals(SRV, sum.getServiceID(BUNDLE2, "")); + TestCase.assertEquals(BUNDLE_SYMBOLIC1 + ":" + SUB, sum.getServiceID(BUNDLE1, SUB)); + TestCase.assertEquals(SRV + ":" + SUB, sum.getServiceID(BUNDLE2, SUB)); } @Test - public void test_getUserForService() { + public void test_getServiceUserID() { @SuppressWarnings("serial") Map config = new HashMap() { { @@ -125,11 +125,11 @@ public class ServiceUserMapperImplTest { final ServiceUserMapperImpl sum = new ServiceUserMapperImpl(); sum.configure(config); - TestCase.assertEquals(SAMPLE, sum.getUserForService(BUNDLE1, null)); - TestCase.assertEquals(ANOTHER, sum.getUserForService(BUNDLE2, null)); - TestCase.assertEquals(SAMPLE, sum.getUserForService(BUNDLE1, "")); - TestCase.assertEquals(ANOTHER, sum.getUserForService(BUNDLE2, "")); - TestCase.assertEquals(SAMPLE_SUB, sum.getUserForService(BUNDLE1, SUB)); - TestCase.assertEquals(ANOTHER_SUB, sum.getUserForService(BUNDLE2, SUB)); + TestCase.assertEquals(SAMPLE, sum.getServiceUserID(BUNDLE1, null)); + TestCase.assertEquals(ANOTHER, sum.getServiceUserID(BUNDLE2, null)); + TestCase.assertEquals(SAMPLE, sum.getServiceUserID(BUNDLE1, "")); + TestCase.assertEquals(ANOTHER, sum.getServiceUserID(BUNDLE2, "")); + TestCase.assertEquals(SAMPLE_SUB, sum.getServiceUserID(BUNDLE1, SUB)); + TestCase.assertEquals(ANOTHER_SUB, sum.getServiceUserID(BUNDLE2, SUB)); } } Propchange: sling/trunk/bundles/jcr/api/ ------------------------------------------------------------------------------ --- svn:mergeinfo (added) +++ svn:mergeinfo Mon Aug 5 10:08:50 2013 @@ -0,0 +1 @@ +/sling/whiteboard/fmeschbe/deprecate_login_administrative/jcr/api:1458693-1499668 Modified: sling/trunk/bundles/jcr/api/pom.xml URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/api/pom.xml?rev=1510413&r1=1510412&r2=1510413&view=diff ============================================================================== --- sling/trunk/bundles/jcr/api/pom.xml (original) +++ sling/trunk/bundles/jcr/api/pom.xml Mon Aug 5 10:08:50 2013 @@ -55,10 +55,6 @@ sling,jcr,jackrabbit - - - org.apache.sling.jcr.api;version=2.1.0 - @@ -71,6 +67,11 @@ jcr provided + + biz.aQute + bndlib + provided + Modified: sling/trunk/bundles/jcr/api/src/main/java/org/apache/sling/jcr/api/SlingRepository.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/api/src/main/java/org/apache/sling/jcr/api/SlingRepository.java?rev=1510413&r1=1510412&r2=1510413&view=diff ============================================================================== --- sling/trunk/bundles/jcr/api/src/main/java/org/apache/sling/jcr/api/SlingRepository.java (original) +++ sling/trunk/bundles/jcr/api/src/main/java/org/apache/sling/jcr/api/SlingRepository.java Mon Aug 5 10:08:50 2013 @@ -18,6 +18,7 @@ */ package org.apache.sling.jcr.api; +import javax.jcr.LoginException; import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.Session; @@ -39,7 +40,6 @@ import javax.jcr.Session; * implementations of the {@link NamespaceMapper} interface before * returning any {@link Session} to callers. This includes the methods * defined in the {@link Repository} interface. - * */ public interface SlingRepository extends Repository { @@ -51,19 +51,55 @@ public interface SlingRepository extends String getDefaultWorkspace(); /** - * Returns a session to the default workspace which has administrative - * powers. + * Returns a session to the given workspace which has administrative powers. *

* NOTE: This method is intended for use by infrastructure bundles to * access the repository and provide general services. This method MUST not * be used to handle client requests of whatever kinds. To handle client - * requests a regular authenticated session retrieved - * through {@link #login(javax.jcr.Credentials, String)} or + * requests a regular authenticated session retrieved through + * {@link #login(javax.jcr.Credentials, String)} or * {@link Session#impersonate(javax.jcr.Credentials)} must be used. + *

+ * This method is deprecated. Services running in the Sling system should + * use the {@link #loginService(String serviceInfo, String workspace)} + * method instead. Implementations of this method must throw + * {@code javax.jcr.LoginException} if they don't support it. + * + * @param workspace The name of the workspace to which to get an + * administrative session. If null the + * {@link #getDefaultWorkspace()} default workspace is assumed. + * @return The administrative Session + * @throws LoginException If this method is not supported or is disabled by + * the implementation. + * @throws RepositoryException If an error occurrs creating the + * administrative session + * @deprecated as of 2.2 (bundle version 2.2.0) because of inherent security + * issues. Services requiring specific permissions should use + * the {@link #loginService(String, String)} instead. + */ + @Deprecated + Session loginAdministrative(String workspace) throws LoginException, RepositoryException; + + /** + * Returns a session to the given workspace with privileges assigned to the + * service provided by the calling bundle. The {@code subServiceName} + * argument can be used to further specialize the service account to be + * used. * + * @param subServiceName Optional Subservice Name to specialize account + * selection for the service. This may be {@code null}. * @param workspace The name of the workspace to which to get an * administrative session. If null the * {@link #getDefaultWorkspace()} default workspace is assumed. + * @return A Session with appropriate permissions to execute the service. + * @throws LoginException If there is no service account defined for the + * calling bundle or the defined service account does not exist. + * @throws RepositoryException if an error occurrs. + * @since 2.2 (bundle version 2.2.0) to replace + * {@link #loginAdministrative(String)} + * @see Service + * Authentication */ - Session loginAdministrative(String workspace) throws RepositoryException; + Session loginService(String subServiceName, String workspace) throws LoginException, RepositoryException; } Added: sling/trunk/bundles/jcr/api/src/main/java/org/apache/sling/jcr/api/package-info.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/api/src/main/java/org/apache/sling/jcr/api/package-info.java?rev=1510413&view=auto ============================================================================== --- sling/trunk/bundles/jcr/api/src/main/java/org/apache/sling/jcr/api/package-info.java (added) +++ sling/trunk/bundles/jcr/api/src/main/java/org/apache/sling/jcr/api/package-info.java Mon Aug 5 10:08:50 2013 @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +@Version("2.2") +package org.apache.sling.jcr.api; + +import aQute.bnd.annotation.Version; + Propchange: sling/trunk/bundles/jcr/base/ ------------------------------------------------------------------------------ --- svn:mergeinfo (added) +++ svn:mergeinfo Mon Aug 5 10:08:50 2013 @@ -0,0 +1 @@ +/sling/whiteboard/fmeschbe/deprecate_login_administrative/jcr/base:1458693-1499669 Modified: sling/trunk/bundles/jcr/base/pom.xml URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/base/pom.xml?rev=1510413&r1=1510412&r2=1510413&view=diff ============================================================================== --- sling/trunk/bundles/jcr/base/pom.xml (original) +++ sling/trunk/bundles/jcr/base/pom.xml Mon Aug 5 10:08:50 2013 @@ -57,13 +57,6 @@ sling,jcr,jackrabbit - - org.apache.sling.jcr.base; - org.apache.sling.jcr.base.util;version=2.1.0 - - - org.apache.sling.jcr.base.internal.* - @@ -85,13 +78,9 @@ - org.apache.felix - org.apache.felix.scr.annotations - - org.apache.sling org.apache.sling.jcr.api - 2.1.0 + 2.1.1-SNAPSHOT provided @@ -117,6 +106,13 @@ 2.0.0 provided + + org.apache.sling + org.apache.sling.serviceusermapper + 0.0.1-SNAPSHOT + provided + + org.osgi @@ -129,6 +125,15 @@ + org.apache.felix + org.apache.felix.scr.annotations + + + biz.aQute + bndlib + + + org.slf4j slf4j-api Modified: sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepository.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepository.java?rev=1510413&r1=1510412&r2=1510413&view=diff ============================================================================== --- sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepository.java (original) +++ sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepository.java Mon Aug 5 10:08:50 2013 @@ -18,6 +18,10 @@ */ package org.apache.sling.jcr.base; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; import java.util.Dictionary; import javax.jcr.Credentials; @@ -35,18 +39,46 @@ import org.apache.felix.scr.annotations. import org.apache.felix.scr.annotations.Reference; import org.apache.sling.jcr.api.SlingRepository; import org.apache.sling.jcr.base.util.RepositoryAccessor; +import org.apache.sling.serviceusermapping.ServiceUserMapper; +import org.osgi.framework.Bundle; +import org.osgi.framework.ServiceFactory; import org.osgi.framework.ServiceRegistration; import org.osgi.service.component.ComponentContext; import org.osgi.service.log.LogService; +import org.slf4j.LoggerFactory; /** - * The AbstractSlingRepository is an abstract implementation of - * the {@link SlingRepository} interface which provides default support for - * attached repositories as well as ensuring live repository connection, - * reconnecting if needed. Implementations of the SlingRepository - * interface may wish to extend this class to benefit from a default - * implementation. - * + * The AbstractSlingRepository is an abstract implementation of the + * {@link SlingRepository} interface which provides default support for attached + * repositories as well as ensuring live repository connection, reconnecting if + * needed. Implementations of the SlingRepository interface may + * wish to extend this class to benefit from a default implementation. + *

+ * As of version 2.2 (bundle version 2.2.0) the registration of repository + * services based on this abstract base class works differently. To be able to + * know the calling bundle to implement the + * {@link #loginService(String, String)} method the service is registered as a + * service factory. Yet this component is registered as a non-service component + * with Declarative Services handling its registration itself so the the + * {@code ServiceFactory} cannot simply create instances of this class. The + * solution is for the service factory to create a proxy to the actual component + * object. All method calls are just routed through with the exception of the + * {@link #loginService(String, String)} method which is routed to a new + * internal method taking the calling bundle as an additional argument. + *

+ * The changes to support this new registration mechanism are as follows: + *

    + *
  • The {@link #registerService()} method is now final.
  • + *
  • The {@link #getServiceRegistrationInterfaces()} and + * {@link #getServiceRegistrationProperties()} methods have been added and can + * be overwritten by implementations of this class. The + * {@link #registerService()} method calls these new methods to get the + * interfaces and properties for the service registration.
  • + *
+ * Implementations of this class overwriting the {@link #registerService()} + * method must replace this overwritten method with overwriting the new + * {@link #getServiceRegistrationInterfaces()} and/or + * {@link #getServiceRegistrationProperties()} methods. */ @Component(componentAbstract=true) public abstract class AbstractSlingRepository @@ -61,6 +93,10 @@ public abstract class AbstractSlingRepos public static final String DEFAULT_ADMIN_PASS = "admin"; + // For backwards compatibility loginAdministrative is still enabled + // In future releases, this default may change to false. + public static final boolean DEFAULT_LOGIN_ADMIN_ENABLED = true; + @Property public static final String PROPERTY_DEFAULT_WORKSPACE = "defaultWorkspace"; @@ -76,6 +112,9 @@ public abstract class AbstractSlingRepos @Property(value=DEFAULT_ADMIN_PASS) public static final String PROPERTY_ADMIN_PASS = "admin.password"; + @Property(boolValue = DEFAULT_LOGIN_ADMIN_ENABLED) + public static final String PROPERTY_LOGIN_ADMIN_ENABLED = "admin.login.enabled"; + /** * The default value for the number of seconds to wait between two * consecutive checks while the repository is active (value is 10). @@ -100,6 +139,9 @@ public abstract class AbstractSlingRepos @Reference private LogService log; + @Reference() + private ServiceUserMapper serviceUserMapper; + private ComponentContext componentContext; private Repository repository; @@ -116,6 +158,8 @@ public abstract class AbstractSlingRepos private char[] adminPass; + private boolean disableLoginAdministrative; + // the poll interval used while the repository is not active private long pollTimeInActiveSeconds; @@ -165,10 +209,32 @@ public abstract class AbstractSlingRepos return this.login(null, null); } - public Session loginAdministrative(String workspace) - throws RepositoryException { - Credentials sc = getAdministrativeCredentials(this.adminUser); - return this.login(sc, workspace); + public final Session loginAdministrative(String workspace) throws RepositoryException { + if (this.disableLoginAdministrative) { + log(LogService.LOG_ERROR, "SlingRepository.loginAdministrative is disabled. Please use SlingRepository.loginService."); + throw new LoginException(); + } + + log(LogService.LOG_WARNING, + "SlingRepository.loginAdministrative is deprecated. Please use SlingRepository.loginService."); + return loginAdministrativeInternal(workspace); + } + + /** + * This method always throws {@code LoginException} because it does + * not directly have the calling bundle at its disposition to decide + * on the required service name. + *

+ * This method is final and cannot be overwritten by extensions. See the + * class comments for full details on how this works. + * + * @since 2.2 (bundle version 2.2.0) + */ + public final Session loginService(String subServiceName, String workspace) throws LoginException, + RepositoryException { + log(LogService.LOG_ERROR, + "loginService: Cannot get using Bundle because this SlingRepository service is not a ServiceFactory"); + throw new LoginException(); } public Session login(Credentials credentials) throws LoginException, @@ -236,6 +302,55 @@ public abstract class AbstractSlingRepos } /** + * Actual implementation of the {@link #loginService(String, String)} method + * taking into account the bundle calling this method. + *

+ * This method is final and cannot be overwritten by extensions. See the + * class comments for full details on how this works. + * + * @param usingBundle The bundle requesting access + * @param subServiceName Subservice name (may be {@code null}) + * @param workspace The workspace to access + * @return The session authenticated with the service user + * @throws LoginException If authentication fails or if no user is defined + * for the requesting service (bundle) + * @throws RepositoryException If a general error occurrs creating the + * session + * + * @since 2.2 (bundle version 2.2.0) + */ + final Session loginService(final Bundle usingBundle, final String subServiceName, final String workspace) + throws LoginException, RepositoryException { + final String userName = this.serviceUserMapper.getServiceUserID(usingBundle, subServiceName); + final SimpleCredentials creds = new SimpleCredentials(userName, new char[0]); + + Session admin = null; + try { + admin = this.loginAdministrativeInternal(workspace); + return admin.impersonate(creds); + } finally { + if (admin != null) { + admin.logout(); + } + } + } + + /** + * Actual (unprotected) implementation of administrative login. + *

+ * This methods is internally used to administratively login. + * + * @param workspace The workspace to login to (or {@code null} to use the + * {@link #getDefaultWorkspace() default workspace}. + * @return The administrative session + * @throws RepositoryException if an error occurrs. + */ + protected Session loginAdministrativeInternal(String workspace) throws RepositoryException { + Credentials sc = getAdministrativeCredentials(this.adminUser); + return this.login(sc, workspace); + } + + /** * @param anonUser the user name of the anon user. * @return a Credentials implementation that represents the anon user. */ @@ -427,25 +542,69 @@ public abstract class AbstractSlingRepos } /** - * Registers this component as an OSGi service with type - * javax.jcr.Repository and - * org.apache.sling.jcr.api.SlingRepository using the - * component properties as service registration properties. + * Registers this component as an OSGi service with the types provided by + * the {@link #getServiceRegistrationInterfaces()} method and properties + * provided by the {@link #getServiceRegistrationProperties()} method. *

- * This method may be overwritten to register the component with different - * types. + * As of version 2.2 (bundle version 2.2.0) this method is final and cannot + * be overwritten because the mechanism of service registration using a + * service factory is required to fully implement the + * {@link #loginService(String, String)} method. See the class comments for + * full details on how this works. * - * @return The OSGi ServiceRegistration object representing - * the registered service. + * @return The OSGi ServiceRegistration object representing the + * registered service. */ - protected ServiceRegistration registerService() { - @SuppressWarnings("unchecked") - Dictionary props = componentContext.getProperties(); - String[] interfaces = new String[] { SlingRepository.class.getName(), - Repository.class.getName() }; + protected final ServiceRegistration registerService() { + final Dictionary props = getServiceRegistrationProperties(); + final String[] interfaces = getServiceRegistrationInterfaces(); + + return componentContext.getBundleContext().registerService(interfaces, new ServiceFactory() { + public Object getService(Bundle bundle, ServiceRegistration registration) { + return SlingRepositoryProxyHandler.createProxy(interfaces, AbstractSlingRepository.this, bundle); + } - return componentContext.getBundleContext().registerService(interfaces, - this, props); + public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) { + // nothing to do (GC does the work for us) + } + }, props); + } + + /** + * Return the service registration properties to be used to register the + * repository service in {@link #registerService()}. + *

+ * This method may be overwritten to return additional service registration + * properties. But it is strongly recommended to always include the + * properties returned from this method. + * + * @return The service registration properties to be used to register the + * repository service in {@link #registerService()} + * + * @since 2.2 (bundle version 2.2.0) + */ + @SuppressWarnings("unchecked") + protected Dictionary getServiceRegistrationProperties() { + return componentContext.getProperties(); + } + + /** + * Returns the service types to be used to register the repository service + * in {@link #registerService()}. All interfaces returned must be accessible + * to the class loader of the class of this instance. + *

+ * This method may be overwritten to return additional types but the types + * returned from this base implementation must always be included. + * + * @return The service types to be used to register the repository service + * in {@link #registerService()} + * + * @since 2.2 (bundle version 2.2.0) + */ + protected String[] getServiceRegistrationInterfaces() { + return new String[] { + SlingRepository.class.getName(), Repository.class.getName() + }; } /** @@ -496,7 +655,7 @@ public abstract class AbstractSlingRepos if(pingRepository(repository)) { try { - final Session s = loginAdministrative(getDefaultWorkspace()); + final Session s = loginAdministrativeInternal(getDefaultWorkspace()); s.logout(); result = true; } catch(RepositoryException re) { @@ -572,6 +731,9 @@ public abstract class AbstractSlingRepos this.adminPass = this.getProperty(properties, PROPERTY_ADMIN_PASS, DEFAULT_ADMIN_PASS).toCharArray(); + this.disableLoginAdministrative = !this.getProperty(properties, PROPERTY_LOGIN_ADMIN_ENABLED, + DEFAULT_LOGIN_ADMIN_ENABLED); + setPollTimeActive(getIntProperty(properties, PROPERTY_POLL_ACTIVE)); setPollTimeInActive(getIntProperty(properties, PROPERTY_POLL_INACTIVE)); @@ -652,6 +814,17 @@ public abstract class AbstractSlingRepos return -1; } + private boolean getProperty(Dictionary properties, String name, boolean defaultValue) { + Object prop = properties.get(name); + if (prop instanceof Boolean) { + return ((Boolean) prop).booleanValue(); + } else if (prop instanceof String) { + return Boolean.valueOf((String) prop); + } + + return defaultValue; + } + private boolean createWorkspace(String workspace) { this.log(LogService.LOG_INFO, "createWorkspace: Requested workspace " + workspace + " does not exist, trying to create"); @@ -920,4 +1093,79 @@ public abstract class AbstractSlingRepos } } + /** + * The SlingRepositoryProxyHandler class implements a proxy for all + * service interfaces under which the {@link AbstractSlingRepository} + * implementation is registered. + *

+ * All calls a directly handed through to the object except for the + * {@code loginService} call which is routed through + * {@code AbstractSlingRepository.loginService(Bundle, String, String)} method + * to influence logging in by the calling bundle. + * + * @since 2.2 (bundle version 2.2.0) + */ + private static class SlingRepositoryProxyHandler implements InvocationHandler { + + // The name of the method to re-route + private static final String LOGIN_SERVICE_NAME = "loginService"; + + // The delegatee object to which all calls are routed + private final AbstractSlingRepository delegatee; + + // The bundle using this proxy service instance + private final Bundle usingBundle; + + /** + * Creates a new proxy instance for the given {@code delegatee} object. The + * proxy is handled by a new instance of this + * {@code SlingRepositoryProxyHandler} handler. + * + * @param interfaceNames The list of interfaces to implement and expose in + * the proxy + * @param delegatee The object to which to route all method calls + * @param usingBundle The bundle making use of the proxy + * @return The proxy to be used by client code or {@code null} if not all + * service interfaces can be loaded by the class loader of the + * {@code delegatee} object. + */ + static Object createProxy(final String[] interfaceNames, final AbstractSlingRepository delegatee, + final Bundle usingBundle) { + + // get the interface classes to create the proxy + final ClassLoader cl = delegatee.getClass().getClassLoader(); + final Class[] interfaces = new Class[interfaceNames.length]; + for (int i = 0; i < interfaces.length; i++) { + try { + interfaces[i] = cl.loadClass(interfaceNames[i]); + } catch (ClassNotFoundException e) { + LoggerFactory.getLogger(SlingRepositoryProxyHandler.class).error( + "createProxy: Cannot load interface class " + interfaceNames[i], e); + return null; + } + } + + // create the proxy + final InvocationHandler handler = new SlingRepositoryProxyHandler(delegatee, usingBundle); + return Proxy.newProxyInstance(cl, interfaces, handler); + } + + private SlingRepositoryProxyHandler(final AbstractSlingRepository delegatee, final Bundle usingBundle) { + this.delegatee = delegatee; + this.usingBundle = usingBundle; + } + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (SlingRepositoryProxyHandler.LOGIN_SERVICE_NAME.equals(method.getName()) && args != null && args.length == 2) { + return this.delegatee.loginService(this.usingBundle, (String) args[0], (String) args[1]); + } + + // otherwise forward to the AbstractSlingRepository implementation + try { + return method.invoke(this.delegatee, args); + } catch (InvocationTargetException ite) { + throw ite.getTargetException(); + } + } + } } Modified: sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/internal/loader/Loader.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/internal/loader/Loader.java?rev=1510413&r1=1510412&r2=1510413&view=diff ============================================================================== --- sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/internal/loader/Loader.java (original) +++ sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/internal/loader/Loader.java Mon Aug 5 10:08:50 2013 @@ -333,6 +333,7 @@ public class Loader implements Namespace } private Session getSession() throws RepositoryException { + // TODO: Should really use loginService !! return this.slingRepository.loginAdministrative(null); } Added: sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/package-info.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/package-info.java?rev=1510413&view=auto ============================================================================== --- sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/package-info.java (added) +++ sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/package-info.java Mon Aug 5 10:08:50 2013 @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +@Version("2.2") +package org.apache.sling.jcr.base; + +import aQute.bnd.annotation.Version; + Added: sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/util/package-info.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/util/package-info.java?rev=1510413&view=auto ============================================================================== --- sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/util/package-info.java (added) +++ sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/util/package-info.java Mon Aug 5 10:08:50 2013 @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +@Version("2.1") +package org.apache.sling.jcr.base.util; + +import aQute.bnd.annotation.Version; + Propchange: sling/trunk/bundles/jcr/jackrabbit-server/ ------------------------------------------------------------------------------ --- svn:mergeinfo (added) +++ svn:mergeinfo Mon Aug 5 10:08:50 2013 @@ -0,0 +1 @@ +/sling/whiteboard/fmeschbe/deprecate_login_administrative/jcr/jackrabbit-server:1499280-1499674 Modified: sling/trunk/bundles/jcr/jackrabbit-server/pom.xml URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/jackrabbit-server/pom.xml?rev=1510413&r1=1510412&r2=1510413&view=diff ============================================================================== --- sling/trunk/bundles/jcr/jackrabbit-server/pom.xml (original) +++ sling/trunk/bundles/jcr/jackrabbit-server/pom.xml Mon Aug 5 10:08:50 2013 @@ -201,7 +201,7 @@ org.apache.sling org.apache.sling.jcr.base - 2.1.0 + 2.1.3-SNAPSHOT compile @@ -219,6 +219,14 @@ compile + + + org.apache.sling + org.apache.sling.serviceusermapper + 0.0.1-SNAPSHOT + provided + + org.osgi Propchange: sling/trunk/bundles/jcr/jackrabbit-server/src/main/java/org/apache/sling/jcr/jackrabbit/server/impl/Activator.java ('svn:mergeinfo' removed) Modified: sling/trunk/bundles/jcr/jackrabbit-server/src/main/java/org/apache/sling/jcr/jackrabbit/server/impl/SlingServerRepository.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/jackrabbit-server/src/main/java/org/apache/sling/jcr/jackrabbit/server/impl/SlingServerRepository.java?rev=1510413&r1=1510412&r2=1510413&view=diff ============================================================================== --- sling/trunk/bundles/jcr/jackrabbit-server/src/main/java/org/apache/sling/jcr/jackrabbit/server/impl/SlingServerRepository.java (original) +++ sling/trunk/bundles/jcr/jackrabbit-server/src/main/java/org/apache/sling/jcr/jackrabbit/server/impl/SlingServerRepository.java Mon Aug 5 10:08:50 2013 @@ -286,26 +286,17 @@ public class SlingServerRepository exten } /** - * Overrides the registerService method of AbstractSlingRepository, in order to register - * org.apache.jackrabbit.api.management.RepositoryManager Service using the - * component properties as service registration properties. + * Returns the Jackrabbit {@code RepositoryManager} interface implemented by + * the Jackrabbit Repository in addition to the {@code SlingRepository} and + * {@code Repository} interfaces implemented by the base class. * - * @return The OSGi ServiceRegistration object representing - * the registered service. - * - * @see org.apache.sling.jcr.base.AbstractSlingRepository#registerService() + * @since bundle version 2.2.0 replacing the previously overwriting of the + * now final {@code AbstractSlingRepository.registerService} method. */ - @Override - protected ServiceRegistration registerService() { - - @SuppressWarnings("unchecked") - Dictionary props = getComponentContext().getProperties(); - - String[] interfaces = new String[] { - SlingRepository.class.getName(), Repository.class.getName(), RepositoryManager.class.getName() + protected String[] getServiceRegistrationInterfaces() { + return new String[] { + SlingRepository.class.getName(), Repository.class.getName(), RepositoryManager.class.getName() }; - - return getComponentContext().getBundleContext().registerService(interfaces, this, props); } //---------- Helper ------------------------------------------------------- Propchange: sling/trunk/bundles/jcr/jackrabbit-server/src/main/java/org/apache/sling/jcr/jackrabbit/server/impl/SlingServerRepository.java ('svn:mergeinfo' removed) Modified: sling/trunk/bundles/jcr/jackrabbit-server/src/main/resources/OSGI-INF/metatype/metatype.properties URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/jackrabbit-server/src/main/resources/OSGI-INF/metatype/metatype.properties?rev=1510413&r1=1510412&r2=1510413&view=diff ============================================================================== --- sling/trunk/bundles/jcr/jackrabbit-server/src/main/resources/OSGI-INF/metatype/metatype.properties (original) +++ sling/trunk/bundles/jcr/jackrabbit-server/src/main/resources/OSGI-INF/metatype/metatype.properties Mon Aug 5 10:08:50 2013 @@ -28,6 +28,12 @@ repository.description = Configuration t In addition, if the registration URL is not empty, the repository is registered \ as defined. +admin.login.enabled.name = Enable Administrator Login +admin.login.enabled.description = Whether to enable or disable the \ + SlingRepository.loginAdministrative method. The default is "true". See \ + http://sling.apache.org/documentation/the-sling-engine/service-authentication.html \ + for information on deprecating and disabling the loginAdministrative method. + admin.name.name = Administator admin.name.description = The user name of the administrative user. This user \ name is used to implement the SlingRepository.loginAdministrative(String) \ Propchange: sling/trunk/bundles/jcr/resource/ ------------------------------------------------------------------------------ --- svn:mergeinfo (added) +++ svn:mergeinfo Mon Aug 5 10:08:50 2013 @@ -0,0 +1 @@ +/sling/whiteboard/fmeschbe/deprecate_login_administrative/jcr/resource:1459328-1499675 Modified: sling/trunk/bundles/jcr/resource/pom.xml URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/pom.xml?rev=1510413&r1=1510412&r2=1510413&view=diff ============================================================================== --- sling/trunk/bundles/jcr/resource/pom.xml (original) +++ sling/trunk/bundles/jcr/resource/pom.xml Mon Aug 5 10:08:50 2013 @@ -146,7 +146,7 @@ org.apache.sling org.apache.sling.api - 2.4.0 + 2.4.3-SNAPSHOT provided @@ -158,7 +158,7 @@ org.apache.sling org.apache.sling.jcr.api - 2.0.6 + 2.1.1-SNAPSHOT provided Modified: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java?rev=1510413&r1=1510412&r2=1510413&view=diff ============================================================================== --- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java (original) +++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java Mon Aug 5 10:08:50 2013 @@ -106,11 +106,18 @@ public class JcrResourceResolverFactoryI } /** + * @see org.apache.sling.api.resource.ResourceResolverFactory#getServiceResourceResolver(Map) + */ + public ResourceResolver getServiceResourceResolver(Map authenticationInfo) throws LoginException { + return delegatee.getServiceResourceResolver(authenticationInfo); + } + + /** * @see org.apache.sling.api.resource.ResourceResolverFactory#getAdministrativeResourceResolver(java.util.Map) */ public ResourceResolver getAdministrativeResourceResolver( - final Map arg0) throws LoginException { - return delegatee.getAdministrativeResourceResolver(arg0); + final Map authenticationInfo) throws LoginException { + return delegatee.getAdministrativeResourceResolver(authenticationInfo); } /** Modified: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProvider.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProvider.java?rev=1510413&r1=1510412&r2=1510413&view=diff ============================================================================== --- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProvider.java (original) +++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProvider.java Mon Aug 5 10:08:50 2013 @@ -99,14 +99,14 @@ public class JcrResourceProvider private final Session session; private final ClassLoader dynamicClassLoader; - private final boolean closeSession; + private final RepositoryHolder repositoryHolder; public JcrResourceProvider(final Session session, final ClassLoader dynamicClassLoader, - final boolean closeSession) { + final RepositoryHolder repositoryHolder) { this.session = session; this.dynamicClassLoader = dynamicClassLoader; - this.closeSession = closeSession; + this.repositoryHolder = repositoryHolder; } // ---------- ResourceProvider interface ---------------------------------- @@ -234,9 +234,7 @@ public class JcrResourceProvider * @see org.apache.sling.api.resource.DynamicResourceProvider#close() */ public void close() { - if ( this.closeSession && !closed) { - session.logout(); - } + this.repositoryHolder.release(); this.closed = true; }