Fork me on GitHub

Caching Results of Principal Resolution

General

Since Oak 1.3.4 this UserPrincipalProvider optionally allows for temporary caching of the principal resolution mainly to optimize login performance (OAK-3003).

This cache contains the result of the group principal resolution as performed by PrincipalProvider.getPrincipals(String userId)and PrincipalProvider.getGroupMembership(Principal) and will read from the cache upon subsequent calls for the configured expiration time.

Configuration

An administrator may enable the group principal caching via the org.apache.jackrabbit.oak.security.user.UserConfigurationImpl OSGi configuration. By default caching is disabled.

The following configuration option is supported:

  • Cache Expiration (cacheExpiration): Specifying a long greater 0 enables the caching.

NOTE: It is important that the configured expiration time balances between login performance and cache invalidation to reflect changes made to the group membership. An application that makes use of this cache, must be able to live with shot term diverging of principal resolution and user management upon repository login.

It is expected that the cache is used in scenarios where subsequent repository login calls can (or even should) result in the creation of a javax.security.auth.Subject with equal principal set irrespective of group membership changes. See section Invalidation below for further details.

How it works

Caching Principal Names

If the feature is enabled, evaluating UserPrincipalProvider.getPrincipals(String userId) and PrincipalProvider.getGroupMembership(Principal) as well as the corresponding calls on PrincipalManager will trigger the group principal names to be remembered in a cache if the following conditions are met:

  • a valid expiration time is configured (i.e. > 0),
  • the PrincipalProvider has been obtained for a system session (see below),
  • the tree to hold the cache belongs to a user (i.e. tree with primary type rep:User (i.e. no caches are created for groups)

The cache itself consists of a tree named rep:cache with the built-in node type rep:Cache, which defines a mandatory, protected rep:expiration property and may have additional protected, residual properties.

Subsequent calls will read the names of the group principals from the cache until the cache expires. Once expired the default resolution will be performed again in order to update the cache.

Limitation to System Calls

The creation and maintenance of this caches as well as the shortcut upon reading is limited to system internal sessions for security reasons: The cache must always be filled with the comprehensive list of group principals (as required upon login) as must any subsequent call never expose principal information that might not be accessible in the non-cache scenario where access to principals is protected by regular permission evalution.

Validation

The cache is system maintained, protected repository content that can only be created and updated by the implementation. Any attempt to manipulate these caches using JCR or Oak API calls will fail. Also the cache can only be created or updated using the internal system subject.

Also this validation is always enforce irrespective on whether the caching feature is enabled or not, to prevent unintended manipulation.

These constraints and the consistency of the cache structure is asserted by a dedicated CacheValidator. The corresponding errors are all of type Constraint with the following codes:

Code Message
0034 Attempt to create or change the system maintained cache.

Note however, that the cache tree might be removed by any session that has sufficient privileges to remove it.

Cache Invalidation

The caches hold with the different user trees get invalidated once the expiration time is reached. There is no explicit, forced invalidation if group membership as reflected by the user management implementation is being changed.

Consequently, system sessions which might read principal information from the cache (if enabled) can be provided with a set of principals (as stored in the cache) that might have diverged from the group membership stored in the repository for the time until the cache expires.

Applications that rely on principal resolution being always in sync with the revision associated with the system session that perform the repository login, must not enable the cache.

Similarly, applications that have due to their design have an extremely high turnover wrt group membership might not be able to profit from this cache in the expected way.

Interaction With User Management

The cache is created and maintained by the PrincipalProvider implementation as exposed by the optional UserConfiguration.getUserPrincipalProvider call and will therefore only effect the results provided by the principal management API.

Regular Jackrabbit user management API calls are not affected by this cache and vice versa; i.e. changes made using the user management API have no immediate effect on the cache and will not trigger it's invalidation.

In other words user management API calls will always read from the revision of the content repository that is associated with the give JCR Session (and Oak ContentSession). The same is true for principal management API calls of all non-system sessions.

See the introduction and section Invalidation above for the expected behavior for system sessions.

XML Import

When users are imported via JCR XML import, the protected cache structure will be ignored (i.e. will not be imported).