Solving the Authentication Handler Credential Validation Problem
Excerpt |
|
|
| Define a mechanism to allow an Authentication Handler to validate the user's identity and signal that to the ResourceResolverFactory in the authentication information.(DRAFT) |
Status: DRAFT
Created: 27. September 2013
Author: fmeschbe
JIRA: Implement solution to the Authentication Handler Credential Validation Problem, AbstractSlingRepository#login violates JCR spec
References: –
Updated: –
Table of Contents |
|
|
Problem
There does not currently exist a good and transparent way for an Authentication Handler to signal to the ResourceResovlerFactory, that the identity of a user has been established and validated and that no further checks are required. For example an SSO authentication handler will get the identity of a user provided by the SSO handler or an OAuth 2 authentication handler proves the identity of the user by with the help of the OAuth 2 provider.
...
A new predefined property of the AuthenticationInfo map is defined which can be set by the authentication handler to indicate that the user's identity has been verified and can be guaranteed:
Code Block |
|
|
public interface ResourceResolverFactory {
....
/**
* Name of the authentication information property used to indicate that the
* identity of the user indicated by the {@link #USER} property has already
* been validated by other means such as OAuth2, OpenID or similar SSO
* functionality. As a consequence password-less access to a
* {@link ResourceResolver} should be granted.
* <p>
* The non-empty string value of this property identifies the party having
* validated the user's identity. It may be used by implementations of this
* and the {@link ResourceProviderFactory} interfaces in log messages.
* <p>
* The type of this property, if present, is <code>String</code>.
*
* @since 2.4 (bundle version 2.5.0)
*/
String IDENTIFIED = "user.identified";
....
}
|
...
The JCR Resource Provider will check for the property and create a Subject used for establishing the session's owner:
Code Block |
|
|
if (authenticationInfo.get("user.identified") != null) {
// pre-identified user access
final String userName = (String) authenticationInfo.get(ResourceResolverFactory.USER);
final String identifier = (String) authenticationInfo.get("user.identified");
log.info("getResourceProviderInternal: Logging in user {} identified by {}", userName, identifier);
Session tmp = null;
try {
tmp = session = repository.loginAdministrative(workspace);
Authorizable auth = ((JackrabbitSession) tmp).getUserManager().getAuthorizable(userName);
Subject s = new Subject();
s.getPrincipals().add(auth.getPrincipal());
session = Subject.doAs(s, new PrivilegedExceptionAction<Session>() {
public Session run() throws Exception {
return repository.login(workspace);
}
});
} catch (PrivilegedActionException pae) {
throw pae.getCause();
} finally {
if (tmp != null) {
tmp.logout();
}
}
}
|
...
One approach to mitigate this problem would be to leverage the ServiceUserMapper service which is also used in the context of the service authentication mechanism: a sub service name user.identified is defined and each consumer of this mechanism must have a user mapping for this subservice to the mock user *.
This way, the JCR Resource Provider sketched above would add this check:
Code Block |
|
|
if (authenticationInfo.get("user.identified") != null) {
if (!"*".equals(serviceUserMapper.getServiceUserID(callingBundle, "user.identified"))) {
log.info("Missing privilege to use pre-authenticated login");
throw new LoginException();
}
...
}
|
...
So the Abstract Sling Repository implementation of the login(String, String) method must be fixed along these lines:
Code Block |
|
|
if (credentials == null) {
if (Subject.getSubject(AccessController.getContext()) != null) {
return getRepository().login(null, workspace);
} else {
// TODO: getAnonCredentials(this.anonUser) should not be used for anonymous access
return getRepository().login(new GuestCredentials(), workspace);
}
} else {
return getRepository().login(credentials, workspace);
}
|