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 sync options 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:
See also FAQ for frequently asked questions about the dynamic sync.
With the default SyncHandler
this configuration option will show the following effects:
DynamicSyncContext
).DynamicSyncContext
will set the property rep:externalPrincipalNames
on the synchronized external userrep: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)Principal
s (see section User Management below).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 externalDynamicMembershipService
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.
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.PrincipalProvider
associated with this dedicated principal configuration will expand the collection of Principal
s generated for the following calls with the automatically assigned principals:PrincipalProvider.getGroupMembership(Principal)
PrincipalProvider.getPrincipals(String)
o.a.j.api.security.user.Group
will be ignored in accordance to the default behavior.PrincipalProvider
relies on other PrincipalProvider
implementations to own these group principals and will not expose them upon other calls (e.g. PrincipalProvider.getPrincipal(String)
.PrincipalProvider
.user.autoMembership
configuration is respected (see also OAK-5194 and OAK-5195)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.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 Principal
s 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.
extUserName
: the principal name of an external userextGroupName
: the principal name of an external groupextUserPrincipal
: the principal associated with a synchronized external userextGroupPrincipal
: the principal associated with a synchronized external groupAPI 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. |
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:
user.enforceDynamicMembership
is disabled (default), previously synced groups, and their member information will continue to be synchronized according to the sync configuration.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()
.
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:
user.enforceDynamicMembership
is disabled (default), previously synced groups, and their member information will continue to be synchronized according to the sync configuration.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.
extUserId
: the ID of a synchronized external userextGroupId
: the ID of a synchronized external groupextUser
: 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 forUserManager.getAuthorizable(extUserId, User.class) ,UserManager.getAuthorizable(extUserPrincipal) ,UserManager.getAuthorizableByPath(extUserPath) |
UserManager.getAuthorizable(extGroupId) | ok | - | ok | Same applies forUserManager.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 |
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).
The authorization modules shipped with Oak only depend on Principal
s (and not on user management functionality) and are therefore not affected by the dynamic membership configuration.