Fork me on GitHub

Token Authentication and Token Management

General

The token based authentication has been completely refactor in Oak and has the following general characteristics.

  • Dedicated API for managing login tokens defined in the package org.apache.jackrabbit.oak.spi.security.authentication.token.
  • Pluggable configuration of the new token management API
  • Complete separation of token based authentication into a separate LoginModule.

Token Authentication

As of Oak the token based authentication is handled by a dedicated TokenLoginModule. It is both responsible for creating new login tokens and validating TokenCredentials passed to the repository login.

This token specific login module implementation obtains the TokenProvider from the security configuration as defined for the content repository. The token management implementation present with a given repository can be changed or extended at runtime (see section Configuration below).

TokenLoginModule

The TokenLoginModuledesigned to support and issue TokenCredentials. The authentication phases behave as follows:

Phase 1: Login

  • if no TokenProvider is available returns false
  • if a TokenProvider has been configured it retrieves JCR credentials from the CallbackHandler using the CredentialsCallback
  • in case of TokenCredentials validates these credentials: if it succeeds it pushes the users ID to the shared state and returns true; otherwise throws LoginException
  • for other credentials the method returns false

Phase 1: Commit

  • if phase 1 succeeded the subject is populated and the method returns true
  • in case phase 1 did not succeed this method will test if the shared state contain credentials that ask for a new token being created; if this succeeds it will create a new instance of TokenCredentials, push the public attributes to the shared stated and update the subject with the new credentials; finally the commit call returns false
Example JAAS Configuration
jackrabbit.oak {
     org.apache.jackrabbit.oak.security.authentication.token.TokenLoginModule sufficient;
     org.apache.jackrabbit.oak.security.authentication.user.LoginModuleImpl required;
 };

Token Management API

Oak 1.0 defines the following interfaces used to manage login tokens:

In addition Oak comes with a default implementation of the provider interface that is able to aggregate multiple TokenProviders:

  • CompositeTokenConfiguration: Extension of the CompositeConfiguration to combined different token management implementations.
  • CompositeTokenProvider: Aggregation of the TokenProvider implementations defined by the configurations contained the CompositeTokenConfiguration

See section Pluggability for an example.

Characteristics of the Default Implementation

The characteristics of the default token management implementation is described in section Token Management : The Default Implementation.

Configuration

The configuration options of the default implementation are described in the Configuration section.

Pluggability

The default security setup as present with Oak 1.0 is able to deal with custom token management implementations and will collect multiple implementations within CompositeTokenConfiguration present with the SecurityProvider. The CompositeTokenConfiguration itself will combine the different TokenProvider implementations using the CompositeTokenProvider.

In an OSGi setup the following steps are required in order to add a custom token provider implementation:

  • implement TokenProvider interface
  • expose the custom provider by your custom TokenConfiguration service
  • make the configuration available to the Oak repository.
  • make sure the TokenConfiguration is listed as required service with the SecurityProvider (see also Introduction)
Examples
Example TokenConfiguration
@Component()
@Service({TokenConfiguration.class, SecurityConfiguration.class})
public class MyTokenConfiguration extends ConfigurationBase implements TokenConfiguration {

    public TokenConfigurationImpl() {
        super();
    }

    public TokenConfigurationImpl(SecurityProvider securityProvider) {
        super(securityProvider, securityProvider.getParameters(NAME));
    }

    @Activate
    private void activate(Map<String, Object> properties) {
        setParameters(ConfigurationParameters.of(properties));
    }

    //----------------------------------------------< SecurityConfiguration >---
    @Nonnull
    @Override
    public String getName() {
        return NAME;
    }

    //-------------------------------------------------< TokenConfiguration >---
    @Nonnull
    @Override
    public TokenProvider getTokenProvider(Root root) {
        return new MyTokenProvider(root, getParameters());
    }
}