Service Authentication
Status: PROTOTYPE
Created: 4. April 2013
Author: fmeschbe
Issue: SLING-2944
Problem
Since the early days of Sling we had methods to get an administrative JCR Session and later an administrative ResourceResolver. These methods were intended to provide services with access to the repository with less restrictions than regular users and to also allow those services to access the Resource tree (and JCR Repository) without hard-coding a password in the code or even having the password as some plain text in configuration.
Over the years, it turned out that these loginAdministrative
methods have been abused.
The goal of this proposal is to come up with new API to replace the loginAdministrative
methods.
One example of a service, which currently uses administrative privileges but which would benefit from a carefully crafted service user is the Tenant Manager
Requirements
- Don't use administrative JCR Sessions or ResourceResolvers all over
- Allow services access to JCR Sessions and ResourceResolvers without requiring to hard-code or configure passwords
- Allow services to use "service users" which have been specially configured for service level access (as is usually done on unixish systems)
- Allow administrators to configure the assignment of service users to services
Solution
New loginService methods
Two new methods are introduced to replace loginAdministrative
methods:
ResourceResolver getServiceResourceResolver(Map<String, Object> authenticationInfo) throws LoginException;
Session loginService(String serviceInfo, String workspace) throws LoginException, RepositoryException;
The bundle identifying the actual service is not part of the new API. The bundle is taken from the call stack by leveraging the OSGi Service Factory mechanism: Each bundle using the ResourceResolverFactory
or SlingRepository
service actually gets an instance bound to the using bundle. That bundle is used to identify the service.
The serviceInfo
parameter or sling.service.info
property of the authenticationInfo
map may be used to provide additional information on the service. See the New ServiceUserMapper Service section below for information on additional service information.
Communicating Service Information to ResourceProviderFactories
The ResourceProviderFactory
interface is not extended for the new service login. Rather the required information – using bundle and additional service information – is passed to the getResourceProvider
method as part of the authenticationInfo
map:
ResourceResolverFactory.USER
– name of the service user (nevernull
)ResourceProviderFactory.SERVICE_BUNDLE
– the serviceBundle
object (nevernull
)ResourceResolverFactory.SERVICE_INFO
– additional service information (optional; may benull
)
In case the ResourceProviderFactory
makes use of another service to provide the ResourceProvider
the provided service bundle should be used to acquire the service to allow the service to support service logins using the ServiceUserMapper
service. An example of such an implementation would be the JCR based ResourceProviderFactory
which gets the SlingRepository
service using the service bundle.
New ServiceUserMapper Service
A service is introduced which allows to map a service to a user name. A service is identified by a service name related to the OSGi Bundle implementing the service and an additional service information string. For example a bundle implementing mail support may represent the MailServer service while the actual mail sender may identify itself with the sender information and some mail queue handler may identify itself with the queue information. This allows separate users to be used for sending messages and handling the message queue or using the same user for both services, depending on the requirements and needs of the system administrator.
The ServiceUserMapper
service has two methods:
String getServiceName(Bundle bundle, String serviceInfo);
– Returns the value of the service identification string to use for the bundle providing the service. In the above example of the message sender service, when call with the mail server bundle andserviceInfo="sender"
the returned value might beMailServer:sender
.String getUserForService(Bundle bundle, String serviceInfo);
– Returns the name of the user to be used for the given service.
This ServiceUserMapper
service is intended to be used by implementations of the new loginService
methods to allow mapping services to user names and to provide for a central point of configuring the mapping.
Deprecate loginAdministrative
The following methods are deprecated:
SlingRepository.loginAdministrative
ResourceResolverFactory.getAdministrativeResourceResolver
ResourceProviderFactory.getAdministrativeResourceProvider
The implementations we have in Sling's bundle will remain implemented but there will be a configuration switch to disable support for these methods: If the method is disabled, a LoginException
is always thrown from these methods. The JavaDoc of the methods is augmented with this information.
Prototype Implementation
A prototype implementation of this concept is available in the deprecate_login_administrative whiteboard.