This is an automated email from the ASF dual-hosted git repository. baedke pushed a commit to branch issue/oak-6756 in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
The following commit(s) were added to refs/heads/issue/oak-6756 by this push: new 44c79ad8ff OAK-6756: Convert oak-auth-external to OSGi R7 annotations 44c79ad8ff is described below commit 44c79ad8ff7f125e5000a900bf413cc51ce4ed76 Author: Manfred Baedke <manfred.bae...@gmail.com> AuthorDate: Wed Mar 20 15:55:13 2024 +0100 OAK-6756: Convert oak-auth-external to OSGi R7 annotations done. --- oak-auth-external/pom.xml | 6 +- .../external/impl/DefaultSyncConfigImpl.java | 353 ++++++++++++--------- .../external/impl/DefaultSyncHandler.java | 21 +- .../external/impl/ExternalIDPManagerImpl.java | 15 +- .../external/impl/ExternalLoginModuleFactory.java | 121 +++---- .../external/impl/SyncManagerImpl.java | 15 +- .../principal/ExternalPrincipalConfiguration.java | 88 +++-- .../external/impl/jmx/SynMBeanImplOSGiTest.java | 1 + 8 files changed, 354 insertions(+), 266 deletions(-) diff --git a/oak-auth-external/pom.xml b/oak-auth-external/pom.xml index d8f9d0b85f..581d7014fc 100644 --- a/oak-auth-external/pom.xml +++ b/oak-auth-external/pom.xml @@ -70,13 +70,13 @@ <scope>provided</scope> </dependency> <dependency> - <groupId>org.apache.felix</groupId> - <artifactId>org.apache.felix.jaas</artifactId> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.service.component.annotations</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.felix</groupId> - <artifactId>org.apache.felix.scr.annotations</artifactId> + <artifactId>org.apache.felix.jaas</artifactId> <scope>provided</scope> </dependency> <dependency> diff --git a/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncConfigImpl.java b/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncConfigImpl.java index 2a6ab154f6..07adb49fbe 100644 --- a/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncConfigImpl.java +++ b/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncConfigImpl.java @@ -20,140 +20,80 @@ package org.apache.jackrabbit.oak.spi.security.authentication.external.impl; import java.util.HashMap; import java.util.Map; -import org.apache.felix.scr.annotations.Component; -import org.apache.felix.scr.annotations.Property; import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters; import org.apache.jackrabbit.oak.spi.security.authentication.external.basic.DefaultSyncConfig; import org.jetbrains.annotations.NotNull; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; +import org.osgi.service.metatype.annotations.AttributeDefinition; /** * {@code DefaultSyncConfig} defines how users and groups from an external source are synced into the repository using * the {@link DefaultSyncHandler}. */ -@Component( - label = "Apache Jackrabbit Oak Default Sync Handler", - name = "org.apache.jackrabbit.oak.spi.security.authentication.external.impl.DefaultSyncHandler", - configurationFactory = true, - metatype = true, - ds = false -) public class DefaultSyncConfigImpl extends DefaultSyncConfig { /** - * @see #getName() + * @see DefaultSyncConfig#getName() */ - public static final String PARAM_NAME_DEFAULT = DefaultSyncConfig.DEFAULT_NAME; - - /** - * @see #getName() - */ - @Property( - label = "Sync Handler Name", - description = "Name of this sync configuration. This is used to reference this handler by the login modules.", - value = PARAM_NAME_DEFAULT - ) public static final String PARAM_NAME = "handler.name"; - /** - * @see DefaultSyncConfig.User#getExpirationTime() + * @see DefaultSyncConfig#getName() */ - public static final String PARAM_USER_EXPIRATION_TIME_DEFAULT = "1h"; + public static final String PARAM_NAME_DEFAULT = DefaultSyncConfig.DEFAULT_NAME; /** * @see DefaultSyncConfig.User#getExpirationTime() */ - @Property( - label = "User Expiration Time", - description = "Duration until a synced user gets expired (eg. '1h 30m' or '1d').", - value = PARAM_USER_EXPIRATION_TIME_DEFAULT - ) public static final String PARAM_USER_EXPIRATION_TIME = "user.expirationTime"; - /** - * @see DefaultSyncConfig.User#getAutoMembership() + * @see DefaultSyncConfig.User#getExpirationTime() */ - public static final String[] PARAM_USER_AUTO_MEMBERSHIP_DEFAULT = {}; + public static final String PARAM_USER_EXPIRATION_TIME_DEFAULT = "1h"; /** * @see DefaultSyncConfig.User#getAutoMembership() */ - @Property( - label = "User auto membership", - description = "List of groups that a synced user is added to automatically", - value = {}, - cardinality = Integer.MAX_VALUE - ) public static final String PARAM_USER_AUTO_MEMBERSHIP = "user.autoMembership"; - /** - * @see DefaultSyncConfig.User#getPropertyMapping() + * @see DefaultSyncConfig.User#getAutoMembership() */ - public static final String[] PARAM_USER_PROPERTY_MAPPING_DEFAULT = {"rep:fullname=cn"}; + public static final String[] PARAM_USER_AUTO_MEMBERSHIP_DEFAULT = {}; /** * @see DefaultSyncConfig.User#getPropertyMapping() */ - @Property( - label = "User property mapping", - description = "List mapping definition of local properties from external ones. eg: 'profile/email=mail'." + - "Use double quotes for fixed values. eg: 'profile/nt:primaryType=\"nt:unstructured\"", - value = {"rep:fullname=cn"}, - cardinality = Integer.MAX_VALUE - ) public static final String PARAM_USER_PROPERTY_MAPPING = "user.propertyMapping"; - /** - * @see DefaultSyncConfig.User#getPathPrefix() + * @see DefaultSyncConfig.User#getPropertyMapping() */ - public static final String PARAM_USER_PATH_PREFIX_DEFAULT = ""; + public static final String[] PARAM_USER_PROPERTY_MAPPING_DEFAULT = {"rep:fullname=cn"}; /** * @see DefaultSyncConfig.User#getPathPrefix() */ - @Property( - label = "User Path Prefix", - description = "The path prefix used when creating new users.", - value = PARAM_USER_PATH_PREFIX_DEFAULT - ) public static final String PARAM_USER_PATH_PREFIX = "user.pathPrefix"; - /** - * @see DefaultSyncConfig.User#getMembershipExpirationTime() + * @see DefaultSyncConfig.User#getPathPrefix() */ - public static final String PARAM_USER_MEMBERSHIP_EXPIRATION_TIME_DEFAULT = "1h"; + public static final String PARAM_USER_PATH_PREFIX_DEFAULT = ""; /** * @see DefaultSyncConfig.User#getMembershipExpirationTime() */ - @Property( - label = "User Membership Expiration", - description = "Time after which membership expires (eg. '1h 30m' or '1d'). Note however, that a membership sync is aways bound to a sync of the user.", - value = PARAM_USER_MEMBERSHIP_EXPIRATION_TIME_DEFAULT - ) public static final String PARAM_USER_MEMBERSHIP_EXPIRATION_TIME = "user.membershipExpTime"; - /** - * @see DefaultSyncConfig.User#getMembershipNestingDepth() + * @see DefaultSyncConfig.User#getMembershipExpirationTime() */ - public static final int PARAM_USER_MEMBERSHIP_NESTING_DEPTH_DEFAULT = 0; + public static final String PARAM_USER_MEMBERSHIP_EXPIRATION_TIME_DEFAULT = "1h"; /** * @see DefaultSyncConfig.User#getMembershipNestingDepth() */ - @Property( - label = "User membership nesting depth", - description = "Returns the maximum depth of group nesting when membership relations are synced. " + - "A value of 0 effectively disables group membership lookup. A value of 1 only adds the direct " + - "groups of a user. This value has no effect when syncing individual groups only when syncing a " + - "users membership ancestry.", - intValue = PARAM_USER_MEMBERSHIP_NESTING_DEPTH_DEFAULT - ) public static final String PARAM_USER_MEMBERSHIP_NESTING_DEPTH = "user.membershipNestingDepth"; - /** - * @see DefaultSyncConfig.User#getDynamicMembership() + * @see DefaultSyncConfig.User#getMembershipNestingDepth() */ - public static final boolean PARAM_USER_DYNAMIC_MEMBERSHIP_DEFAULT = false; + public static final int PARAM_USER_MEMBERSHIP_NESTING_DEPTH_DEFAULT = 0; /** * Configuration option to enable dynamic group membership. If enabled the @@ -168,18 +108,11 @@ public class DefaultSyncConfigImpl extends DefaultSyncConfig { * * @see DefaultSyncConfig.User#getDynamicMembership() */ - @Property( - label = "User Dynamic Membership", - description = "If enabled membership of external identities (user) is no longer fully reflected " + - "within the repositories user management.", - boolValue = PARAM_USER_DYNAMIC_MEMBERSHIP_DEFAULT - ) public static final String PARAM_USER_DYNAMIC_MEMBERSHIP = "user.dynamicMembership"; - /** - * @see DefaultSyncConfig.User#getEnforceDynamicMembership() + * @see DefaultSyncConfig.User#getDynamicMembership() */ - public static final boolean PARAM_USER_ENFORCE_DYNAMIC_MEMBERSHIP_DEFAULT = false; + public static final boolean PARAM_USER_DYNAMIC_MEMBERSHIP_DEFAULT = false; /** * Configuration option to enforce dynamic group membership upon user sync. If enabled the @@ -187,127 +120,241 @@ public class DefaultSyncConfigImpl extends DefaultSyncConfig { * * @see DefaultSyncConfig.User#getDynamicMembership() */ - @Property( - label = "User Enforce Dynamic Membership", - description = "If enabled dynamic membership will be enforced for previously synchronized users. Note, that this option has no effect if 'dynamic membership' is disabled.", - boolValue = PARAM_USER_ENFORCE_DYNAMIC_MEMBERSHIP_DEFAULT - ) public static final String PARAM_USER_ENFORCE_DYNAMIC_MEMBERSHIP = "user.enforceDynamicMembership"; - /** - * @see User#getDisableMissing() + * @see DefaultSyncConfig.User#getDynamicMembership() */ - public static final boolean PARAM_DISABLE_MISSING_USERS_DEFAULT = false; + public static final boolean PARAM_USER_ENFORCE_DYNAMIC_MEMBERSHIP_DEFAULT = false; /** * @see User#getDisableMissing() */ - @Property( - label = "Disable missing users", - description = "If true, users that no longer exist on the external provider will be locally disabled, " + - "and re-enabled if they become valid again. If false (default) they will be removed.", - boolValue = false - ) public static final String PARAM_DISABLE_MISSING_USERS = "user.disableMissing"; - /** - * @see DefaultSyncConfig.Group#getExpirationTime() + * @see User#getDisableMissing() */ - public static final String PARAM_GROUP_EXPIRATION_TIME_DEFAULT = "1d"; + public static final boolean PARAM_DISABLE_MISSING_USERS_DEFAULT = false; /** * @see DefaultSyncConfig.Group#getExpirationTime() */ - @Property( - label = "Group Expiration Time", - description = "Duration until a synced group expires (eg. '1h 30m' or '1d').", - value = PARAM_GROUP_EXPIRATION_TIME_DEFAULT - ) public static final String PARAM_GROUP_EXPIRATION_TIME = "group.expirationTime"; - /** - * @see DefaultSyncConfig.Group#getAutoMembership() + * @see DefaultSyncConfig.Group#getExpirationTime() */ - public static final String[] PARAM_GROUP_AUTO_MEMBERSHIP_DEFAULT = {}; + public static final String PARAM_GROUP_EXPIRATION_TIME_DEFAULT = "1d"; /** * @see DefaultSyncConfig.Group#getAutoMembership() */ - @Property( - label = "Group auto membership", - description = "List of groups that a synced group is added to automatically", - value = {}, - cardinality = Integer.MAX_VALUE - ) public static final String PARAM_GROUP_AUTO_MEMBERSHIP = "group.autoMembership"; - /** - * @see DefaultSyncConfig.Group#getPropertyMapping() + * @see DefaultSyncConfig.Group#getAutoMembership() */ - public static final String[] PARAM_GROUP_PROPERTY_MAPPING_DEFAULT = {}; + public static final String[] PARAM_GROUP_AUTO_MEMBERSHIP_DEFAULT = {}; /** * @see DefaultSyncConfig.Group#getPropertyMapping() */ - @Property( - label = "Group property mapping", - description = "List mapping definition of local properties from external ones.", - value = {}, - cardinality = Integer.MAX_VALUE - ) public static final String PARAM_GROUP_PROPERTY_MAPPING = "group.propertyMapping"; - /** - * @see DefaultSyncConfig.Group#getPathPrefix() + * @see DefaultSyncConfig.Group#getPropertyMapping() */ - public static final String PARAM_GROUP_PATH_PREFIX_DEFAULT = ""; + public static final String[] PARAM_GROUP_PROPERTY_MAPPING_DEFAULT = {}; /** * @see DefaultSyncConfig.Group#getPathPrefix() */ - @Property( - label = "Group Path Prefix", - description = "The path prefix used when creating new groups.", - value = PARAM_GROUP_PATH_PREFIX_DEFAULT - ) public static final String PARAM_GROUP_PATH_PREFIX = "group.pathPrefix"; - /** - * @see DefaultSyncConfig.Group#getDynamicGroups() + * @see DefaultSyncConfig.Group#getPathPrefix() */ - public static final boolean PARAM_GROUP_DYNAMIC_GROUPS_DEFAULT = false; - + public static final String PARAM_GROUP_PATH_PREFIX_DEFAULT = ""; + /** * @see DefaultSyncConfig.Group#getDynamicGroups() */ - @Property( - label = "Dynamic Groups", - description = "If enabled external identity groups are synchronized as dynamic groups i.e. members/membership " + - "is resolved dynamically by a DynamicMembershipProvider. Note: currently this option only takes effect " + - "if 'User Dynamic Membership' is enabled.", - boolValue = PARAM_GROUP_DYNAMIC_GROUPS_DEFAULT - ) public static final String PARAM_GROUP_DYNAMIC_GROUPS = "group.dynamicGroups"; - /** - * Default value for {@link #PARAM_ENABLE_RFC7613_USERCASE_MAPPED_PROFILE} + * @see DefaultSyncConfig.Group#getDynamicGroups() */ - public static final boolean PARAM_ENABLE_RFC7613_USERCASE_MAPPED_PROFILE_DEFAULT = false; + public static final boolean PARAM_GROUP_DYNAMIC_GROUPS_DEFAULT = false; /** * @see Authorizable#isApplyRFC7613UsernameCaseMapped() */ - @Property( - label = "RFC7613 Username Normalization Profile", - description = "Enable the UsercaseMappedProfile defined in RFC7613 for username normalization.", - boolValue = PARAM_ENABLE_RFC7613_USERCASE_MAPPED_PROFILE_DEFAULT - ) public static final String PARAM_ENABLE_RFC7613_USERCASE_MAPPED_PROFILE = "enableRFC7613UsercaseMappedProfile"; + /** + * @see Authorizable#isApplyRFC7613UsernameCaseMapped() + */ + public static final boolean PARAM_ENABLE_RFC7613_USERCASE_MAPPED_PROFILE_DEFAULT = false; private static final long MILLIS_PER_HOUR = 60 * 60 * 1000L; private static final ConfigurationParameters.Milliseconds ONE_HOUR = ConfigurationParameters.Milliseconds.of(MILLIS_PER_HOUR); private static final ConfigurationParameters.Milliseconds ONE_DAY = ConfigurationParameters.Milliseconds.of(24 * MILLIS_PER_HOUR); + @ObjectClassDefinition( + id = "org.apache.jackrabbit.oak.spi.security.authentication.external.impl.DefaultSyncHandler", + name = "Apache Jackrabbit Oak Default Sync Handler" + ) + @interface Configuration { + /** + * @see DefaultSyncConfig#getName() + */ + @AttributeDefinition( + name = "Sync Handler Name", + description = "Name of this sync configuration. This is used to reference this handler by the login modules." + ) + String handler_name() default PARAM_NAME_DEFAULT; + + /** + * @see DefaultSyncConfig.User#getExpirationTime() + */ + @AttributeDefinition( + name = "User Expiration Time", + description = "Duration until a synced user gets expired (eg. '1h 30m' or '1d')." + ) + String user_expirationTime() default PARAM_USER_EXPIRATION_TIME_DEFAULT; + + /** + * @see DefaultSyncConfig.User#getAutoMembership() + */ + @AttributeDefinition( + name = "User auto membership", + description = "List of groups that a synced user is added to automatically", + cardinality = Integer.MAX_VALUE + ) + String[] user_autoMembership(); + + /** + * @see DefaultSyncConfig.User#getPropertyMapping() + */ + @AttributeDefinition( + name = "User property mapping", + description = "List mapping definition of local properties from external ones. eg: 'profile/email=mail'." + + "Use double quotes for fixed values. eg: 'profile/nt:primaryType=\"nt:unstructured\"", + cardinality = Integer.MAX_VALUE + ) + String[] user_propertyMapping() default {"rep:fullname=cn"}; + + /** + * @see DefaultSyncConfig.User#getPathPrefix() + */ + @AttributeDefinition( + name = "User Path Prefix", + description = "The path prefix used when creating new users." + ) + String user_pathPrefix() default PARAM_USER_PATH_PREFIX_DEFAULT; + + /** + * @see DefaultSyncConfig.User#getMembershipExpirationTime() + */ + @AttributeDefinition( + name = "User Membership Expiration", + description = "Time after which membership expires (eg. '1h 30m' or '1d'). Note however, that a membership sync is aways bound to a sync of the user." + ) + String user_membershipExpTime() default PARAM_USER_MEMBERSHIP_EXPIRATION_TIME_DEFAULT; + + /** + * @see DefaultSyncConfig.User#getMembershipNestingDepth() + */ + @AttributeDefinition( + name = "User membership nesting depth", + description = "Returns the maximum depth of group nesting when membership relations are synced. " + + "A value of 0 effectively disables group membership lookup. A value of 1 only adds the direct " + + "groups of a user. This value has no effect when syncing individual groups only when syncing a " + + "users membership ancestry." + ) + int user_membershipNestingDepth() default PARAM_USER_MEMBERSHIP_NESTING_DEPTH_DEFAULT; + + /** + * @see DefaultSyncConfig.User#getDynamicMembership() + */ + @AttributeDefinition( + name = "User Dynamic Membership", + description = "If enabled membership of external identities (user) is no longer fully reflected " + + "within the repositories user management." + ) + boolean user_dynamicMembership() default PARAM_USER_DYNAMIC_MEMBERSHIP_DEFAULT; + + /** + * @see DefaultSyncConfig.User#getDynamicMembership() + */ + @AttributeDefinition( + name = "User Enforce Dynamic Membership", + description = "If enabled dynamic membership will be enforced for previously synchronized users. Note, that this option has no effect if 'dynamic membership' is disabled." + ) + boolean user_enforceDynamicMembership() default PARAM_USER_ENFORCE_DYNAMIC_MEMBERSHIP_DEFAULT; + + /** + * @see User#getDisableMissing() + */ + @AttributeDefinition( + name = "Disable missing users", + description = "If true, users that no longer exist on the external provider will be locally disabled, " + + "and re-enabled if they become valid again. If false (default) they will be removed." + ) + boolean user_disableMissing() default PARAM_DISABLE_MISSING_USERS_DEFAULT; + + /** + * @see DefaultSyncConfig.Group#getExpirationTime() + */ + @AttributeDefinition( + name = "Group Expiration Time", + description = "Duration until a synced group expires (eg. '1h 30m' or '1d')." + ) + String group_expirationTime() default PARAM_GROUP_EXPIRATION_TIME_DEFAULT; + + /** + * @see DefaultSyncConfig.Group#getAutoMembership() + */ + @AttributeDefinition( + name = "Group auto membership", + description = "List of groups that a synced group is added to automatically", + cardinality = Integer.MAX_VALUE + ) + String[] group_autoMembership(); + + /** + * @see DefaultSyncConfig.Group#getPropertyMapping() + */ + @AttributeDefinition( + name = "Group property mapping", + description = "List mapping definition of local properties from external ones.", + cardinality = Integer.MAX_VALUE + ) + String[] group_propertyMapping(); + + /** + * @see DefaultSyncConfig.Group#getPathPrefix() + */ + @AttributeDefinition( + name = "Group Path Prefix", + description = "The path prefix used when creating new groups." + ) + String group_pathPrefix() default PARAM_GROUP_PATH_PREFIX_DEFAULT; + + /** + * @see DefaultSyncConfig.Group#getDynamicGroups() + */ + @AttributeDefinition( + name = "Dynamic Groups", + description = "If enabled external identity groups are synchronized as dynamic groups i.e. members/membership " + + "is resolved dynamically by a DynamicMembershipProvider. Note: currently this option only takes effect " + + "if 'User Dynamic Membership' is enabled." + ) + boolean group_dynamicGroups() default PARAM_GROUP_DYNAMIC_GROUPS_DEFAULT; + + /** + * @see Authorizable#isApplyRFC7613UsernameCaseMapped() + */ + @AttributeDefinition( + name = "RFC7613 Username Normalization Profile", + description = "Enable the UsercaseMappedProfile defined in RFC7613 for username normalization." + ) + boolean enableRFC7613UsercaseMappedProfile() default PARAM_ENABLE_RFC7613_USERCASE_MAPPED_PROFILE_DEFAULT; + } + /** * Creates a new LDAP provider configuration based on the properties store in the given parameters. * @param params the configuration parameters. diff --git a/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandler.java b/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandler.java index d2051aa4c1..9d24a042a0 100644 --- a/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandler.java +++ b/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandler.java @@ -17,11 +17,10 @@ package org.apache.jackrabbit.oak.spi.security.authentication.external.impl; import org.apache.jackrabbit.guava.common.collect.Iterators; -import org.apache.felix.scr.annotations.Activate; -import org.apache.felix.scr.annotations.Component; -import org.apache.felix.scr.annotations.ConfigurationPolicy; -import org.apache.felix.scr.annotations.Deactivate; -import org.apache.felix.scr.annotations.Service; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.ConfigurationPolicy; import org.apache.jackrabbit.api.security.user.Authorizable; import org.apache.jackrabbit.api.security.user.Group; import org.apache.jackrabbit.api.security.user.UserManager; @@ -40,6 +39,7 @@ import org.apache.jackrabbit.oak.spi.whiteboard.AbstractServiceTracker; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.osgi.framework.BundleContext; +import org.osgi.service.metatype.annotations.Designate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,9 +59,16 @@ import java.util.Set; */ @Component( // note that the metatype information is generated from DefaultSyncConfig - policy = ConfigurationPolicy.REQUIRE + configurationPolicy = ConfigurationPolicy.REQUIRE, + service = { + SyncHandler.class, + AutoMembershipAware.class + } +) +@Designate( + ocd = DefaultSyncConfigImpl.Configuration.class, + factory = true ) -@Service public class DefaultSyncHandler implements SyncHandler, AutoMembershipAware { /** diff --git a/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalIDPManagerImpl.java b/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalIDPManagerImpl.java index a7d74ea962..9662084750 100644 --- a/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalIDPManagerImpl.java +++ b/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalIDPManagerImpl.java @@ -16,10 +16,6 @@ */ package org.apache.jackrabbit.oak.spi.security.authentication.external.impl; -import org.apache.felix.scr.annotations.Activate; -import org.apache.felix.scr.annotations.Component; -import org.apache.felix.scr.annotations.Deactivate; -import org.apache.felix.scr.annotations.Service; import org.apache.jackrabbit.oak.osgi.OsgiWhiteboard; import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentityProvider; import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentityProviderManager; @@ -27,14 +23,21 @@ import org.apache.jackrabbit.oak.spi.whiteboard.AbstractServiceTracker; import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard; import org.jetbrains.annotations.NotNull; import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Deactivate; /** * {@code ExternalIDPManagerImpl} is used to manage registered external identity provider. This class automatically * tracks the IDPs that are registered via OSGi but can also be used in non-OSGi environments by manually adding and * removing the providers. */ -@Component(immediate = true) -@Service +@Component( + immediate = true, + service = { + ExternalIdentityProviderManager.class + } +) public class ExternalIDPManagerImpl extends AbstractServiceTracker<ExternalIdentityProvider> implements ExternalIdentityProviderManager { /** diff --git a/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModuleFactory.java b/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModuleFactory.java index cebec28580..678079a44d 100644 --- a/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModuleFactory.java +++ b/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModuleFactory.java @@ -22,15 +22,6 @@ import javax.security.auth.spi.LoginModule; import org.apache.jackrabbit.guava.common.collect.ImmutableMap; import org.apache.felix.jaas.LoginModuleFactory; -import org.apache.felix.scr.annotations.Activate; -import org.apache.felix.scr.annotations.Component; -import org.apache.felix.scr.annotations.ConfigurationPolicy; -import org.apache.felix.scr.annotations.Deactivate; -import org.apache.felix.scr.annotations.Property; -import org.apache.felix.scr.annotations.Reference; -import org.apache.felix.scr.annotations.ReferenceCardinality; -import org.apache.felix.scr.annotations.ReferencePolicy; -import org.apache.felix.scr.annotations.Service; import org.apache.jackrabbit.oak.api.ContentRepository; import org.apache.jackrabbit.oak.commons.jmx.JmxUtil; import org.apache.jackrabbit.oak.osgi.OsgiWhiteboard; @@ -45,6 +36,16 @@ import org.apache.jackrabbit.oak.spi.whiteboard.Registration; import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard; import org.osgi.framework.BundleContext; import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.metatype.annotations.Designate; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; +import org.osgi.service.metatype.annotations.AttributeDefinition; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -53,62 +54,66 @@ import org.slf4j.LoggerFactory; * via OSGi config. */ @Component( - label = "Apache Jackrabbit Oak External Login Module", - metatype = true, - policy = ConfigurationPolicy.REQUIRE, - configurationFactory = true + configurationPolicy = ConfigurationPolicy.REQUIRE, + service = { + LoginModuleFactory.class, + SyncHandlerMapping.class + } +) +@Designate( + ocd = ExternalLoginModuleFactory.Configuration.class, + factory = true ) -@Service public class ExternalLoginModuleFactory implements LoginModuleFactory, SyncHandlerMapping { - private static final Logger log = LoggerFactory.getLogger(ExternalLoginModuleFactory.class); - - @SuppressWarnings("UnusedDeclaration") - @Property( - intValue = 150, - label = "JAAS Ranking", - description = "Specifying the ranking (i.e. sort order) of this login module entry. The entries are sorted " + - "in a descending order (i.e. higher value ranked configurations come first)." - ) - public static final String JAAS_RANKING = LoginModuleFactory.JAAS_RANKING; - - @SuppressWarnings("UnusedDeclaration") - @Property( - value = "SUFFICIENT", - label = "JAAS Control Flag", - description = "Property specifying whether or not a LoginModule is REQUIRED, REQUISITE, SUFFICIENT or " + - "OPTIONAL. Refer to the JAAS configuration documentation for more details around the meaning of " + - "these flags." - ) - public static final String JAAS_CONTROL_FLAG = LoginModuleFactory.JAAS_CONTROL_FLAG; - - @SuppressWarnings("UnusedDeclaration") - @Property( - label = "JAAS Realm", - description = "The realm name (or application name) against which the LoginModule is be registered. If no " + - "realm name is provided then LoginModule is registered with a default realm as configured in " + - "the Felix JAAS configuration." - ) - public static final String JAAS_REALM_NAME = LoginModuleFactory.JAAS_REALM_NAME; - - @Property( - label = "Identity Provider Name", - description = "Name of the identity provider (for example: 'ldap')." + @ObjectClassDefinition( + id = "org.apache.jackrabbit.oak.spi.security.authentication.external.impl.ExternalLoginModuleFactory", + name = "Apache Jackrabbit Oak External Login Module" ) - public static final String PARAM_IDP_NAME = SyncHandlerMapping.PARAM_IDP_NAME; + @interface Configuration { + @AttributeDefinition( + name = "JAAS Ranking", + description = "Specifying the ranking (i.e. sort order) of this login module entry. The entries are sorted " + + "in a descending order (i.e. higher value ranked configurations come first)." + ) + int jaas_ranking() default 150; + + @AttributeDefinition( + name = "JAAS Control Flag", + description = "Property specifying whether or not a LoginModule is REQUIRED, REQUISITE, SUFFICIENT or " + + "OPTIONAL. Refer to the JAAS configuration documentation for more details around the meaning of " + + "these flags." + ) + String jaas_controlFlag() default "SUFFICIENT"; + + @AttributeDefinition( + name = "JAAS Realm", + description = "The realm name (or application name) against which the LoginModule is be registered. If no " + + "realm name is provided then LoginModule is registered with a default realm as configured in " + + "the Felix JAAS configuration." + ) + String jaas_realmName(); + + @AttributeDefinition( + name = "Identity Provider Name", + description = "Name of the identity provider (for example: 'ldap')." + ) + String idp_name(); + + @AttributeDefinition( + name = "Sync Handler Name", + description = "Name of the sync handler." + ) + String sync_handlerName() default DefaultSyncConfig.DEFAULT_NAME; + } - @Property( - value = DefaultSyncConfig.DEFAULT_NAME, - label = "Sync Handler Name", - description = "Name of the sync handler." - ) - public static final String PARAM_SYNC_HANDLER_NAME = SyncHandlerMapping.PARAM_SYNC_HANDLER_NAME; + private static final Logger log = LoggerFactory.getLogger(ExternalLoginModuleFactory.class); - @Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY, policy = ReferencePolicy.DYNAMIC) - private SecurityProvider securityProvider; + @Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC) + private volatile SecurityProvider securityProvider; - @Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY, policy = ReferencePolicy.DYNAMIC) - private ContentRepository contentRepository; + @Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC) + private volatile ContentRepository contentRepository; @Reference private SyncManager syncManager; diff --git a/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/SyncManagerImpl.java b/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/SyncManagerImpl.java index 3599618f6c..5b3e337675 100644 --- a/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/SyncManagerImpl.java +++ b/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/SyncManagerImpl.java @@ -17,10 +17,6 @@ package org.apache.jackrabbit.oak.spi.security.authentication.external.impl; -import org.apache.felix.scr.annotations.Activate; -import org.apache.felix.scr.annotations.Component; -import org.apache.felix.scr.annotations.Deactivate; -import org.apache.felix.scr.annotations.Service; import org.apache.jackrabbit.oak.osgi.OsgiWhiteboard; import org.apache.jackrabbit.oak.spi.security.authentication.external.SyncHandler; import org.apache.jackrabbit.oak.spi.security.authentication.external.SyncManager; @@ -28,14 +24,21 @@ import org.apache.jackrabbit.oak.spi.whiteboard.AbstractServiceTracker; import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard; import org.jetbrains.annotations.NotNull; import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Deactivate; /** * {@code SyncManagerImpl} is used to manage registered sync handlers. This class automatically * tracks the SyncHandlers that are registered via OSGi but can also be used in non-OSGi environments by manually * adding and removing the handlers. */ -@Component(immediate = true) -@Service +@Component( + immediate = true, + service = { + SyncManager.class + } +) public class SyncManagerImpl extends AbstractServiceTracker<SyncHandler> implements SyncManager { /** diff --git a/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalPrincipalConfiguration.java b/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalPrincipalConfiguration.java index 0e31a70945..222fd291f4 100644 --- a/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalPrincipalConfiguration.java +++ b/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalPrincipalConfiguration.java @@ -17,13 +17,6 @@ package org.apache.jackrabbit.oak.spi.security.authentication.external.impl.principal; import org.apache.jackrabbit.guava.common.collect.ImmutableList; -import org.apache.felix.scr.annotations.Activate; -import org.apache.felix.scr.annotations.Component; -import org.apache.felix.scr.annotations.Deactivate; -import org.apache.felix.scr.annotations.Properties; -import org.apache.felix.scr.annotations.Property; -import org.apache.felix.scr.annotations.PropertyOption; -import org.apache.felix.scr.annotations.Service; import org.apache.jackrabbit.api.security.principal.PrincipalManager; import org.apache.jackrabbit.oak.api.Root; import org.apache.jackrabbit.oak.namepath.NamePathMapper; @@ -51,6 +44,13 @@ import org.apache.jackrabbit.oak.stats.StatisticsProvider; import org.jetbrains.annotations.NotNull; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.Designate; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; +import org.osgi.service.metatype.annotations.Option; import java.security.Principal; import java.util.Collections; @@ -58,7 +58,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import static org.apache.jackrabbit.oak.spi.security.RegistrationConstants.OAK_SECURITY_NAME; import static org.apache.jackrabbit.oak.spi.security.authentication.external.impl.ExternalIdentityConstants.PARAM_PROTECT_EXTERNAL_IDENTITIES; import static org.apache.jackrabbit.oak.spi.security.authentication.external.impl.ExternalIdentityConstants.VALUE_PROTECT_EXTERNAL_IDENTITIES_PROTECTED; import static org.apache.jackrabbit.oak.spi.security.authentication.external.impl.ExternalIdentityConstants.VALUE_PROTECT_EXTERNAL_IDENTITIES_NONE; @@ -75,34 +74,57 @@ import static org.apache.jackrabbit.oak.spi.security.authentication.external.imp * @see <a href="https://issues.apache.org/jira/browse/OAK-4101">OAK-4101</a> */ @Component( - metatype = true, - label = "Apache Jackrabbit Oak External PrincipalConfiguration", - immediate = true + immediate = true, + service = { + PrincipalConfiguration.class, + SecurityConfiguration.class + } +) +@Designate( + ocd = ExternalPrincipalConfiguration.Configuration.class ) -@Service({PrincipalConfiguration.class, SecurityConfiguration.class}) -@Properties({ - @Property(name = ExternalIdentityConstants.PARAM_PROTECT_EXTERNAL_IDS, - label = "External Identity Protection", - description = "If disabled rep:externalId properties won't be properly protected (backwards compatible behavior). NOTE: for security reasons it is strongly recommend to keep the protection enabled!", - boolValue = ExternalIdentityConstants.DEFAULT_PROTECT_EXTERNAL_IDS), - @Property(name = PARAM_PROTECT_EXTERNAL_IDENTITIES, - label = "External User and Group Protection", +public class ExternalPrincipalConfiguration extends ConfigurationBase implements PrincipalConfiguration { + + @ObjectClassDefinition( + id = "org.apache.jackrabbit.oak.spi.security.authentication.external.impl.principal.ExternalPrincipalConfiguration", + name = "Apache Jackrabbit Oak External PrincipalConfiguration" + ) + @interface Configuration { + @AttributeDefinition( + name = "External Identity Protection", + description = "If disabled rep:externalId properties won't be properly protected (backwards compatible behavior). NOTE: for security reasons it is strongly recommend to keep the protection enabled!" + ) + boolean protectExternalId() default ExternalIdentityConstants.DEFAULT_PROTECT_EXTERNAL_IDS; + + @AttributeDefinition( + name = "External User and Group Protection", description = "If 'None' is selected the synchronized external users/groups won't be protected (backwards compatible behavior) and can be edited like local users/groups. NOTE: in order to avoid having inconsistencies between the IDP that defines the external identities and local synced identities it is recommend to enable the protection. With option 'Warn' the protection is disabled but warnings will be logged.", options = { - @PropertyOption(name = VALUE_PROTECT_EXTERNAL_IDENTITIES_NONE, value = VALUE_PROTECT_EXTERNAL_IDENTITIES_NONE), - @PropertyOption(name = VALUE_PROTECT_EXTERNAL_IDENTITIES_WARN, value = VALUE_PROTECT_EXTERNAL_IDENTITIES_WARN), - @PropertyOption(name = VALUE_PROTECT_EXTERNAL_IDENTITIES_PROTECTED, value = VALUE_PROTECT_EXTERNAL_IDENTITIES_PROTECTED) - }), - @Property(name = ExternalIdentityConstants.PARAM_SYSTEM_PRINCIPAL_NAMES, - label = "System Principal Names", - description = "Names of additional 'SystemUserPrincipal' instances that are excluded from the protection check. Note that this configuration does not grant the required permission to perform the operation.", - value = {}, - cardinality = 10), - @Property(name = OAK_SECURITY_NAME, - propertyPrivate= true, - value = "org.apache.jackrabbit.oak.spi.security.authentication.external.impl.principal.ExternalPrincipalConfiguration") -}) -public class ExternalPrincipalConfiguration extends ConfigurationBase implements PrincipalConfiguration { + @Option( + label = VALUE_PROTECT_EXTERNAL_IDENTITIES_NONE, + value = VALUE_PROTECT_EXTERNAL_IDENTITIES_NONE + ), + @Option( + label = VALUE_PROTECT_EXTERNAL_IDENTITIES_WARN, + value = VALUE_PROTECT_EXTERNAL_IDENTITIES_WARN + ), + @Option( + label = VALUE_PROTECT_EXTERNAL_IDENTITIES_PROTECTED, + value = VALUE_PROTECT_EXTERNAL_IDENTITIES_PROTECTED + ) + } + ) + String protectExternalIdentities(); + + @AttributeDefinition( + name = "System Principal Names", + description = "Names of additional 'SystemUserPrincipal' instances that are excluded from the protection check. Note that this configuration does not grant the required permission to perform the operation.", + cardinality = 10 + ) + String[] systemPrincipalNames(); + + String oak_security_name() default "org.apache.jackrabbit.oak.spi.security.authentication.external.impl.principal.ExternalPrincipalConfiguration"; + } private SyncConfigTracker syncConfigTracker; private SyncHandlerMappingTracker syncHandlerMappingTracker; diff --git a/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/jmx/SynMBeanImplOSGiTest.java b/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/jmx/SynMBeanImplOSGiTest.java index 0b3bfa05d7..5f3d1e73a1 100644 --- a/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/jmx/SynMBeanImplOSGiTest.java +++ b/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/jmx/SynMBeanImplOSGiTest.java @@ -93,6 +93,7 @@ public class SynMBeanImplOSGiTest extends ExternalLoginTestBase { public void testContentRepositoryAndSecurityProviderServices() throws Exception { context.registerService(ContentRepository.class, getContentRepository()); context.registerService(SecurityProvider.class, getSecurityProvider()); + context.registerInjectActivateService(externalLoginModuleFactory); assertSyncBeanRegistration(externalLoginModuleFactory, true); }