Fork me on GitHub

User and Group Synchronization : Dynamic Membership and Dynamic Groups

As of Oak 1.5.3 the default sync handler comes with an additional configuration option (see section Configuration that allows enabling dynamic group membership resolution for external users.

Enabling dynamic membership in the DefaultSyncConfig will change the way external groups are synchronized (see OAK-4101) and how automatic group membership is being handled (see OAK-4087)

The key benefits of dynamic membership resolution are:

  • avoiding duplicate user management effort wrt to membership handling both in the external IDP and the repository
  • avoid storing/updating auto-membership which is assigned to all external users
  • ease principal resolution upon repository login

SyncContext with Dynamic Membership

With the default SyncHandler this configuration option will show the following effects:

External Groups

  • If enabled the handler will use an alternative SyncContext to synchronize external groups (DynamicSyncContext).
  • Instead of synchronizing membership information alongside the group accounts, this DynamicSyncContext will set the property rep:externalPrincipalNames on the synchronized external user
  • rep:externalPrincipalNames is a system maintained multivalued property of type ‘STRING’ storing the names of the java.security.acl.Group-principals a given external user is member of (both declared and inherited according to the configured membership nesting depth)
  • By default, external groups will no longer be synchronized into the repository's user management but will only be available as Principals (see section User Management below).
  • If the Dynamic Groups option is enabled together with the Dynamic Membership, external groups will be synchronized into the user management but marked as dynamic. User-Group relationship for these dynamic external
    groups will be determined by a dedicated DynamicMembershipService that is registered if both options are enabled for a given SyncHandler mapping.

Note: as a further improvement the PrincipalNameResolver interface was introduced in Oak 1.6.1 to allow for optimized resolution of a principal names from a given ExternalIdentityRef. In order to benefit from that shortcut a given implementation of ExternalIdentityProvider needs to also implement PrincipalNameResolver. See also OAK-5210.

Automatic Membership

  • If enabled automatic membership assignment for existing, local groups will not longer be written to the repository
  • Instead, the ExternalPrincipalConfiguration (“Apache Jackrabbit Oak External PrincipalConfiguration”) will keep track of the mapping between registered SyncHandlers (i.e. auto-membership configuration) and ExternalIdentityProviders and determine auto-membership based on the rep:externalId stored with the user accounts.
  • The PrincipalProvider associated with this dedicated principal configuration will expand the collection of Principals generated for the following calls with the automatically assigned principals:
    • PrincipalProvider.getGroupMembership(Principal)
    • PrincipalProvider.getPrincipals(String)
  • Configured auto-membership groupIds that cannot be resolved to an existing o.a.j.api.security.user.Group will be ignored in accordance to the default behavior.
  • Consequently, the PrincipalProvider relies on other PrincipalProvider implementations to own these group principals and will not expose them upon other calls (e.g. PrincipalProvider.getPrincipal(String).
  • Any changes to the auto-membership configuration will be immediately reflected to new instances of the PrincipalProvider.
  • Note, that in the initial version (Oak 1.6) only the user.autoMembership configuration is respected (see also OAK-5194 and OAK-5195)
  • With OAK-9462 an implementation of DynamicMembershipProvider will be registered and reflect autoMembership for synchronized external users in the User Management API (see below). The same applies for the conditional auto-membership as introduced with OAK-9463.

Effect of Dynamic Membership on other Security Modules

Principal Management

The dynamic (principal) membership features comes with a dedicated PrincipalConfiguration implementation (i.e. [ExternalPrincipalConfiguration]) that is in charge of securing
the rep:externalPrincipalNames properties (see also section Validation and Configuration).

Additionally, the [ExternalPrincipalConfiguration] provides a PrincipalProvider implementation which makes external (group) principals available to the repository's authentication and authorization using the rep:externalPrincipalNames as a persistent cache to avoid an expensive lookup on the IDP. This also makes external Principals retrievable and searchable through the Jackrabbit principal management API (see section Principal Management for a comprehensive description).

Please note the following implementation detail wrt accessibility of group principals: A given external principal will be accessible though the principal management API if it can be read from any of the rep:externalPrincipalNames properties present using a dedicated query.

API Overview
  • extUserName : the principal name of an external user
  • extGroupName : the principal name of an external group
  • extUserPrincipal : the principal associated with a synchronized external user
  • extGroupPrincipal : the principal associated with a synchronized external group
API Call Default Sync Dynamic Membership Dynamic Membership + Dynamic Groups Comment
PrincipalManager.getPrincipal(extUserName) ok ok ok
PrincipalManager.getPrincipal(extGroupName) ok (ok) 1 ok 1 If the editing session can read any rep:externalPrincipalNames property containing the group principal name
PrincipalManager.getGroupMembership(extUserPrincipal) ok ok ok Dynamic group principals include both declared external groups and configured auto-membership principals (including inherited principals).
PrincipalManager.getGroupMembership(extGroupPrincipal) ok - 2 - 2,3 2 Group membership gets flattened and stored with the external user. Group-group relationship is not preserved.
3 For dynamic groups synced into the repository the configured auto-membership principals are resolved, see also user management API below.

User Management

User Management without Dynamic Groups Option

Unless the ‘Dynamic Groups’ option is set additionally, the dynamic membership option will effectively disable the synchronization of the external group account information into the repository's user management feature. It will instead limit the synchronized information to the group principal names and the membership relation between a given java.security.acl.Group principal and external user accounts.

The user management API will consequently no longer be knowledgeable of external group identities.

For groups that have been synchronized before dynamic membership got enabled, the following rules will apply:

  • if option user.enforceDynamicMembership is disabled (default), previously synced groups, and their member information will continue to be synchronized according to the sync configuration.
  • if option user.enforceDynamicMembership is enabled, previously synced membership will be migrated to become dynamic upon user synchronization. The synchronized group will be removed once it not longer has any declared members.

While this behavior does not affect default authentication and authorization modules (see below) it will have an impact on applications that rely on full synchronization of external identities. Those application won't be able to benefit from the dynamic membership feature until dynamic groups can be created with the Jackrabbit User Management API (see OAK-2687).

Note however, that with OAK-9462 groups listed in the autoMembership configuration parameters as well as the optional AutoMembershipConfig will have dynamic group membership of external user identities reflected in the corresponding API calls, most notably Group.isMember, Group.isDeclaredMember, Group.getMembers, Group.getDeclaredMembers as well as Authorizable.memberOf and Authorizable.declaredMemberOf().

User Management with Dynamic Groups Option enabled

If the ‘Dynamic Groups’ flag is turned on in addition, external group accounts will continue to be synchronized into the repository's user management. However, membership information will not be stored together with the groups but instead will be dynamically calculated from the rep:externalPrincipalNames property caching the membership information with the user accounts. This is achieved by means of a dedicated implementation of the DynamicMembershipProvider interface.

For groups that have been synchronized prior to enabling dynamic membership, the following rules will apply:

  • if option user.enforceDynamicMembership is disabled (default), previously synced groups, and their member information will continue to be synchronized according to the sync configuration.
  • if option user.enforceDynamicMembership is enabled, previously synced membership will be migrated to become dynamic upon user synchronization. The synchronized group will not be removed once it not longer has any declared members.

Note, that manually adding members to these dynamic external groups using Group.addMember, Group.addMembers or equivalent Oak API operations will be prevented by a dedicated validator that is enabled as soon as the Dynamic Groups option is present together with Dynamic Membership.

API Overview
  • extUserId : the ID of a synchronized external user
  • extGroupId : the ID of a synchronized external group
  • extUser : a synchronized external user as org.apache.jackrabbit.api.security.user.User
  • extGroup : a synchronized external group as org.apache.jackrabbit.api.security.user.Group
  • autoGroup : a local group configured in the auto-membership option of the DefaultSyncConfig
API Call Default Sync Dynamic Membership Dynamic Membership + Dynamic Groups Comment
UserManager.getAuthorizable(extUserId) ok ok ok Same applies for
UserManager.getAuthorizable(extUserId, User.class),
UserManager.getAuthorizable(extUserPrincipal),
UserManager.getAuthorizableByPath(extUserPath)
UserManager.getAuthorizable(extGroupId) ok - ok Same applies for
UserManager.getAuthorizable(extGroupId, Group.class),
UserManager.getAuthorizable(extGroupPrincipal),
UserManager.getAuthorizableByPath(extGroupPath)
extUser.declaredMemberOf() ok - 3 (ok) 4 3 Only auto-membership to local groups, external groups not synced.
4 Same as User.memberOf() as nested group membership gets flattened upon dynamic sync. Configured auto-membership is reflected through dynamic AutoMembershipProvider.
extUser.memberOf() ok - 3 ok
extGroup.declaredMemberOf() ok - 5 - 6 5 External groups not synced!
6 Only (conditional) automembership as upon dynamic sync nested group membership gets flattened
extGroup.memberOf() ok - 5 - 6
extGroup.getDeclaredMembers() ok - 5 (ok) 7 7 Same as Group.getMembers()
extGroup.getMembers() ok - 5 (ok) 8 8 Only includes external users as nested membership gets flattened upon dynamic sync.
extGroup.isDeclaredMember(extUser) ok - 5 (ok) 9 9 Same as Group.isMember(extUser)
extGroup.isMember(extUser) ok - 5 ok
extGroup.isDeclaredMember(extGroup) ok - 5 - 10 10 No group-group relations as nested membership gets flattened
extGroup.isMember(extGroup) ok - 5 - 10
extGroup.addMember(Authorizable) ok - 5 - 11 11 Adding members to dynamic groups will fail upon commit.
extGroup.addMembers(String...) ok - 5 - 11
extGroup.removeMember(Authorizable) ok - 5 ok
extGroup.removeMembers(String...) ok - 5 ok
autoGroup.isDeclaredMember(extUser) ok ok 12 ok 12 12 Through AutoMembershipProvider but not stored with local group node that is listed in ‘auto-membership’ config.
autoGroup.isMember(extUser) ok ok 12 ok 12
autoGroup.isDeclaredMember(extGroup) ok - 5 ok 12
autoGroup.isMember(extGroup) ok - 5 ok 12
autoGroup.getDeclaredMembers() ok (ok) 5,12 ok 12
autoGroup.getMembers() ok (ok) 5,12 ok 12

Authentication

The authentication setup provided by Oak is not affected by the dynamic membership handling as long as the configured LoginModule implementations rely on the PrincipalProvider for principal resolution and the ExternalPrincipalConfiguration (“Apache Jackrabbit Oak External PrincipalConfiguration”) is properly registered with the SecurityProvider (see section Configuration).

Authorization

The authorization modules shipped with Oak only depend on Principals (and not on user management functionality) and are therefore not affected by the dynamic membership configuration.