Index: oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugSecurityProvider.java =================================================================== --- oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugSecurityProvider.java (revision 1702510) +++ oak-authorization-cug/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/cug/impl/CugSecurityProvider.java (working copy) @@ -33,12 +33,8 @@ composite.setDefaultConfig(authorizationConfiguration); composite.addConfiguration(new CugConfiguration(this)); composite.addConfiguration(authorizationConfiguration); - ((CugSecurityProvider) this).bindAuthorizationConfiguration(composite); + setAuthorizationConfiguration(composite); } } - @Override - protected void bindAuthorizationConfiguration(@Nonnull AuthorizationConfiguration reference) { - super.bindAuthorizationConfiguration(reference); - } } \ No newline at end of file Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/Preconditions.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/security/Preconditions.java (revision 0) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/Preconditions.java (working copy) @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.oak.security; + +import java.util.Set; + +import static com.google.common.collect.Sets.newHashSet; + +/** + * Represents a preconditions set that may be satisfied by adding the right + * candidates. + *

+ * Initially, a set of preconditions is empty. An empty set of preconditions is + * always satisfied. If candidates are added, but the precondition set is empty, + * the preconditions are considered satisfied. + *

+ * When some preconditions are added, the preconditions set may enter into the + * unsatisfied state. In this case, the preconditions set may be come satisfied + * again only with the addition of the right candidates. + *

+ * This class doesn't admit duplicates for preconditions or candidates. Adding + * the same precondition (or candidate) twice doesn't have any effect on the + * state of the preconditions set. + */ +class Preconditions { + + private final Set preconditions = newHashSet(); + + private final Set candidates = newHashSet(); + + private boolean dirty = false; + + private boolean satisfied = true; + + /** + * Add a precondition to this preconditions set. If the precondition already + * belongs to this set, this operation has no effect. + * + * @param precondition The precondition to be added. + */ + public void addPrecondition(String precondition) { + if (preconditions.add(precondition)) { + dirty = true; + } + } + + /** + * Remove all the preconditions to this set. This makes the set of + * preconditions empty and, as such, satisfied. + */ + public void clearPreconditions() { + preconditions.clear(); + dirty = false; + satisfied = true; + } + + /** + * Add a candidate to this preconditions set. If the candidate already + * belongs to this set, this operation has no effect. + * + * @param candidate The candidate to be added. + */ + public void addCandidate(String candidate) { + if (candidates.add(candidate)) { + dirty = true; + } + } + + /** + * Remove a candidate from this preconditions set. If the candidate doesn't + * belong to this set, this operation has no effect. + * + * @param candidate The candidate to be removed. + */ + public void removeCandidate(String candidate) { + if (candidates.remove(candidate)) { + dirty = false; + } + } + + /** + * Check if the preconditions set are satisfied. + * + * @return {@code true} if the preconditions set is satisfied, {@code false} + * otherwise. + */ + public boolean areSatisfied() { + if (dirty) { + Set unsatisfied = newHashSet(preconditions); + unsatisfied.removeAll(candidates); + satisfied = unsatisfied.isEmpty(); + dirty = false; + } + + return satisfied; + } + +} Property changes on: oak-core/src/main/java/org/apache/jackrabbit/oak/security/Preconditions.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/SecurityProviderImpl.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/security/SecurityProviderImpl.java (revision 1702510) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/SecurityProviderImpl.java (working copy) @@ -16,118 +16,96 @@ */ package org.apache.jackrabbit.oak.security; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import com.google.common.collect.ImmutableMap; -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.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.osgi.OsgiWhiteboard; import org.apache.jackrabbit.oak.security.authentication.AuthenticationConfigurationImpl; import org.apache.jackrabbit.oak.security.authentication.token.TokenConfigurationImpl; import org.apache.jackrabbit.oak.security.authorization.AuthorizationConfigurationImpl; import org.apache.jackrabbit.oak.security.principal.PrincipalConfigurationImpl; import org.apache.jackrabbit.oak.security.privilege.PrivilegeConfigurationImpl; import org.apache.jackrabbit.oak.security.user.UserConfigurationImpl; -import org.apache.jackrabbit.oak.spi.security.ConfigurationBase; import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters; import org.apache.jackrabbit.oak.spi.security.SecurityConfiguration; import org.apache.jackrabbit.oak.spi.security.SecurityProvider; import org.apache.jackrabbit.oak.spi.security.authentication.AuthenticationConfiguration; -import org.apache.jackrabbit.oak.spi.security.authentication.token.CompositeTokenConfiguration; import org.apache.jackrabbit.oak.spi.security.authentication.token.TokenConfiguration; import org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration; -import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants; -import org.apache.jackrabbit.oak.spi.security.principal.CompositePrincipalConfiguration; import org.apache.jackrabbit.oak.spi.security.principal.PrincipalConfiguration; import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConfiguration; import org.apache.jackrabbit.oak.spi.security.user.UserConfiguration; -import org.apache.jackrabbit.oak.spi.security.user.UserConstants; import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard; -import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardAuthorizableActionProvider; -import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardAuthorizableNodeName; import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardAware; -import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardRestrictionProvider; -import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardUserAuthenticationFactory; -import org.osgi.framework.BundleContext; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Sets.newHashSet; -@Component -@Service(value = {SecurityProvider.class}) public class SecurityProviderImpl implements SecurityProvider, WhiteboardAware { - @Reference - private volatile AuthorizationConfiguration authorizationConfiguration; + private AuthenticationConfiguration authenticationConfiguration; - @Reference - private volatile AuthenticationConfiguration authenticationConfiguration; + private AuthorizationConfiguration authorizationConfiguration; - @Reference - private volatile PrivilegeConfiguration privilegeConfiguration; + private UserConfiguration userConfiguration; - @Reference - private volatile UserConfiguration userConfiguration; + private PrincipalConfiguration principalConfiguration; - @Reference(referenceInterface = PrincipalConfiguration.class, - name = "principalConfiguration", - bind = "bindPrincipalConfiguration", - unbind = "unbindPrincipalConfiguration", - policy = ReferencePolicy.DYNAMIC, - cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE) - private final CompositePrincipalConfiguration principalConfiguration = new CompositePrincipalConfiguration(this); + private PrivilegeConfiguration privilegeConfiguration; - @Reference(referenceInterface = TokenConfiguration.class, - name = "tokenConfiguration", - bind = "bindTokenConfiguration", - unbind = "unbindTokenConfiguration", - policy = ReferencePolicy.DYNAMIC, - cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE) - private final CompositeTokenConfiguration tokenConfiguration = new CompositeTokenConfiguration(this); + private TokenConfiguration tokenConfiguration; - private final WhiteboardAuthorizableNodeName authorizableNodeName = new WhiteboardAuthorizableNodeName(); - private final WhiteboardAuthorizableActionProvider authorizableActionProvider = new WhiteboardAuthorizableActionProvider(); - private final WhiteboardRestrictionProvider restrictionProvider = new WhiteboardRestrictionProvider(); - private final WhiteboardUserAuthenticationFactory userAuthenticationFactory = new WhiteboardUserAuthenticationFactory(UserConfigurationImpl.getDefaultAuthenticationFactory()); - private ConfigurationParameters configuration; private Whiteboard whiteboard; /** - * Default constructor used in OSGi environments. + * Default constructor using an empty configuration and default + * implementations for the security configurations. */ public SecurityProviderImpl() { this(ConfigurationParameters.EMPTY); } /** - * Create a new {@code SecurityProvider} instance with the given configuration - * parameters. + * Create a new {@code SecurityProvider} instance with the given + * configuration parameters. * * @param configuration security configuration */ public SecurityProviderImpl(@Nonnull ConfigurationParameters configuration) { - checkNotNull(configuration); - this.configuration = configuration; + this.configuration = checkNotNull(configuration); + this.authenticationConfiguration = new AuthenticationConfigurationImpl(this); + this.authorizationConfiguration = new AuthorizationConfigurationImpl(this); + this.userConfiguration = new UserConfigurationImpl(this); + this.principalConfiguration = new PrincipalConfigurationImpl(this); + this.privilegeConfiguration = new PrivilegeConfigurationImpl(); + this.tokenConfiguration = new TokenConfigurationImpl(this); + } - authenticationConfiguration = new AuthenticationConfigurationImpl(this); - authorizationConfiguration = new AuthorizationConfigurationImpl(this); - userConfiguration = new UserConfigurationImpl(this); - privilegeConfiguration = new PrivilegeConfigurationImpl(); + protected void setAuthenticationConfiguration(AuthenticationConfiguration authenticationConfiguration) { + this.authenticationConfiguration = checkNotNull(authenticationConfiguration); + } - principalConfiguration.setDefaultConfig(new PrincipalConfigurationImpl(this)); - tokenConfiguration.setDefaultConfig(new TokenConfigurationImpl(this)); + protected void setAuthorizationConfiguration(AuthorizationConfiguration authorizationConfiguration) { + this.authorizationConfiguration = authorizationConfiguration; } + protected void setUserConfiguration(UserConfiguration userConfiguration) { + this.userConfiguration = userConfiguration; + } + + protected void setPrincipalConfiguration(PrincipalConfiguration principalConfiguration) { + this.principalConfiguration = principalConfiguration; + } + + protected void setPrivilegeConfiguration(PrivilegeConfiguration privilegeConfiguration) { + this.privilegeConfiguration = privilegeConfiguration; + } + + protected void setTokenConfiguration(TokenConfiguration tokenConfiguration) { + this.tokenConfiguration = tokenConfiguration; + } + @Override public void setWhiteboard(@Nonnull Whiteboard whiteboard) { this.whiteboard = whiteboard; @@ -144,7 +122,9 @@ if (name == null) { return configuration; } + ConfigurationParameters params = configuration.getConfigValue(name, ConfigurationParameters.EMPTY); + for (SecurityConfiguration sc : getConfigurations()) { if (sc != null && sc.getName().equals(name)) { return ConfigurationParameters.of(params, sc.getParameters()); @@ -156,14 +136,14 @@ @Nonnull @Override public Iterable getConfigurations() { - Set scs = new HashSet(); - scs.add(authenticationConfiguration); - scs.add(authorizationConfiguration); - scs.add(userConfiguration); - scs.add(principalConfiguration); - scs.add(privilegeConfiguration); - scs.add(tokenConfiguration); - return scs; + return newHashSet( + authenticationConfiguration, + authorizationConfiguration, + userConfiguration, + principalConfiguration, + privilegeConfiguration, + tokenConfiguration + ); } @SuppressWarnings("unchecked") @@ -187,89 +167,4 @@ } } - //----------------------------------------------------------------< SCR >--- - @Activate - protected void activate(BundleContext context) { - whiteboard = new OsgiWhiteboard(context); - authorizableActionProvider.start(whiteboard); - authorizableNodeName.start(whiteboard); - restrictionProvider.start(whiteboard); - userAuthenticationFactory.start(whiteboard); - - initializeConfigurations(); - } - - @Deactivate - protected void deactivate() { - authorizableActionProvider.stop(); - authorizableNodeName.stop(); - restrictionProvider.stop(); - userAuthenticationFactory.stop(); - } - - @SuppressWarnings("UnusedDeclaration") - protected void bindPrincipalConfiguration(@Nonnull PrincipalConfiguration reference) { - principalConfiguration.addConfiguration(initConfiguration(reference)); - } - - @SuppressWarnings("UnusedDeclaration") - protected void unbindPrincipalConfiguration(@Nonnull PrincipalConfiguration reference) { - principalConfiguration.removeConfiguration(reference); - } - - @SuppressWarnings("UnusedDeclaration") - protected void bindTokenConfiguration(@Nonnull TokenConfiguration reference) { - tokenConfiguration.addConfiguration(initConfiguration(reference)); - } - - @SuppressWarnings("UnusedDeclaration") - protected void unbindTokenConfiguration(@Nonnull TokenConfiguration reference) { - tokenConfiguration.removeConfiguration(reference); - } - - @SuppressWarnings("UnusedDeclaration") - protected void bindAuthorizationConfiguration(@Nonnull AuthorizationConfiguration reference) { - authorizationConfiguration = initConfiguration(reference); - // TODO (OAK-1268): authorizationConfiguration.addConfiguration(initConfiguration(reference)); - } - - @SuppressWarnings("UnusedDeclaration") - protected void unbindAuthorizationConfiguration(@Nonnull AuthorizationConfiguration reference) { - authorizationConfiguration = new AuthorizationConfigurationImpl(this); - // TODO (OAK-1268): authorizationConfiguration.removeConfiguration(reference); - } - - //------------------------------------------------------------< private >--- - private void initializeConfigurations() { - initConfiguration(authorizationConfiguration, ConfigurationParameters.of( - AccessControlConstants.PARAM_RESTRICTION_PROVIDER, restrictionProvider) - ); - - Map userMap = ImmutableMap.of( - UserConstants.PARAM_AUTHORIZABLE_ACTION_PROVIDER, authorizableActionProvider, - UserConstants.PARAM_AUTHORIZABLE_NODE_NAME, authorizableNodeName, - UserConstants.PARAM_USER_AUTHENTICATION_FACTORY, userAuthenticationFactory); - initConfiguration(userConfiguration, ConfigurationParameters.of(userMap)); - - initConfiguration(authenticationConfiguration); - initConfiguration(privilegeConfiguration); - } - - private T initConfiguration(@Nonnull T config) { - if (config instanceof ConfigurationBase) { - ConfigurationBase cfg = (ConfigurationBase) config; - cfg.setSecurityProvider(this); - cfg.setParameters(ConfigurationParameters.of(ConfigurationParameters.EMPTY, cfg.getParameters())); - } - return config; - } - - private T initConfiguration(@Nonnull T config, @Nonnull ConfigurationParameters params) { - if (config instanceof ConfigurationBase) { - ConfigurationBase cfg = (ConfigurationBase) config; - cfg.setSecurityProvider(this); - cfg.setParameters(ConfigurationParameters.of(params, cfg.getParameters())); - } - return config; - } } Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/SecurityProviderRegistration.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/security/SecurityProviderRegistration.java (revision 0) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/SecurityProviderRegistration.java (working copy) @@ -0,0 +1,622 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.oak.security; + +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.PropertyUnbounded; +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.References; +import org.apache.jackrabbit.oak.commons.PropertiesUtil; +import org.apache.jackrabbit.oak.security.user.UserConfigurationImpl; +import org.apache.jackrabbit.oak.spi.security.ConfigurationBase; +import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters; +import org.apache.jackrabbit.oak.spi.security.SecurityConfiguration; +import org.apache.jackrabbit.oak.spi.security.SecurityProvider; +import org.apache.jackrabbit.oak.spi.security.authentication.AuthenticationConfiguration; +import org.apache.jackrabbit.oak.spi.security.authentication.token.CompositeTokenConfiguration; +import org.apache.jackrabbit.oak.spi.security.authentication.token.TokenConfiguration; +import org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration; +import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants; +import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider; +import org.apache.jackrabbit.oak.spi.security.principal.CompositePrincipalConfiguration; +import org.apache.jackrabbit.oak.spi.security.principal.PrincipalConfiguration; +import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConfiguration; +import org.apache.jackrabbit.oak.spi.security.user.AuthorizableNodeName; +import org.apache.jackrabbit.oak.spi.security.user.UserAuthenticationFactory; +import org.apache.jackrabbit.oak.spi.security.user.UserConfiguration; +import org.apache.jackrabbit.oak.spi.security.user.UserConstants; +import org.apache.jackrabbit.oak.spi.security.user.action.AuthorizableActionProvider; +import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardAuthorizableActionProvider; +import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardAuthorizableNodeName; +import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardRestrictionProvider; +import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardUserAuthenticationFactory; +import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; +import org.osgi.framework.ServiceRegistration; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; +import java.util.Map; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.collect.Lists.newArrayList; + +@Component( + immediate = true, + metatype = true +) +@Properties({ + @Property( + name = "requiredConfigurationPids", + unbounded = PropertyUnbounded.ARRAY + ) +}) +@References({ + @Reference( + name = "principalConfiguration", + referenceInterface = PrincipalConfiguration.class, + cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, + policy = ReferencePolicy.DYNAMIC + ), + @Reference( + name = "tokenConfiguration", + referenceInterface = TokenConfiguration.class, + cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, + policy = ReferencePolicy.DYNAMIC + ), + @Reference( + name = "authorizableNodeName", + referenceInterface = TokenConfiguration.class, + cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, + policy = ReferencePolicy.DYNAMIC + ), + @Reference( + name = "authorizableActionProvider", + referenceInterface = AuthorizableActionProvider.class, + cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, + policy = ReferencePolicy.DYNAMIC + ), + @Reference( + name = "restrictionProvider", + referenceInterface = RestrictionProvider.class, + cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, + policy = ReferencePolicy.DYNAMIC + ), + @Reference( + name = "userAuthenticationFactory", + referenceInterface = UserAuthenticationFactory.class, + cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, + policy = ReferencePolicy.DYNAMIC + ) +}) +public class SecurityProviderRegistration { + + @Reference + private AuthorizationConfiguration authorizationConfiguration; + + @Reference + private AuthenticationConfiguration authenticationConfiguration; + + @Reference + private PrivilegeConfiguration privilegeConfiguration; + + @Reference + private UserConfiguration userConfiguration; + + private BundleContext context; + + private ServiceRegistration registration; + + private SecurityProvider securityProvider; + + private final Preconditions preconditions = new Preconditions(); + + private final List principalConfigurations = newArrayList(); + + private final List tokenConfigurations = newArrayList(); + + private final List authorizableNodeNames = newArrayList(); + + private final List authorizableActionProviders = newArrayList(); + + private final List restrictionProviders = newArrayList(); + + private final List userAuthenticationFactories = newArrayList(); + + @Activate + public synchronized void activate(BundleContext context, Map configuration) { + for (String pid : getRequiredConfigurationPids(configuration)) { + preconditions.addPrecondition(pid); + } + + this.context = context; + + maybeActivate(); + } + + @Deactivate + public synchronized void deactivate() { + doDeactivate(); + preconditions.clearPreconditions(); + context = null; + } + + public void bindAuthorizationConfiguration(AuthorizationConfiguration authorizationConfiguration) { + this.authorizationConfiguration = initializeConfiguration(authorizationConfiguration); + } + + public void unbindAuthorizationConfiguration() { + this.authorizationConfiguration = null; + } + + public void bindAuthenticationConfiguration(AuthenticationConfiguration authenticationConfiguration) { + this.authenticationConfiguration = initializeConfiguration(authenticationConfiguration); + } + + public void unbindAuthenticationConfiguration() { + this.authenticationConfiguration = null; + } + + public void bindPrivilegeConfiguration(PrivilegeConfiguration privilegeConfiguration) { + this.privilegeConfiguration = initializeConfiguration(privilegeConfiguration); + } + + public void unbindPrivilegeConfiguration() { + this.privilegeConfiguration = null; + } + + public void bindUserConfiguration(UserConfiguration userConfiguration) { + this.userConfiguration = initializeConfiguration(userConfiguration); + } + + public void unbindUserConfiguration() { + this.userConfiguration = null; + } + + public synchronized void bindPrincipalConfiguration(PrincipalConfiguration principalConfiguration, Map properties) { + principalConfigurations.add(initializeConfiguration(principalConfiguration)); + preconditions.addCandidate(getPid(properties)); + maybeActivate(); + } + + public synchronized void unbindPrincipalConfiguration(PrincipalConfiguration principalConfiguration, Map properties) { + principalConfigurations.remove(principalConfiguration); + preconditions.removeCandidate(getPid(properties)); + maybeDeactivate(); + } + + public synchronized void bindTokenConfiguration(TokenConfiguration tokenConfiguration, Map properties) { + tokenConfigurations.add(initializeConfiguration(tokenConfiguration)); + preconditions.addCandidate(getPid(properties)); + maybeActivate(); + } + + public synchronized void unbindTokenConfiguration(TokenConfiguration tokenConfiguration, Map properties) { + tokenConfigurations.remove(tokenConfiguration); + preconditions.removeCandidate(getPid(properties)); + maybeDeactivate(); + } + + public synchronized void bindAuthorizableNodeName(AuthorizableNodeName authorizableNodeName, Map properties) { + authorizableNodeNames.add(authorizableNodeName); + preconditions.addCandidate(getPid(properties)); + maybeActivate(); + } + + public synchronized void unbindAuthorizableNodeName(AuthorizableNodeName authorizableNodeName, Map properties) { + authorizableNodeNames.remove(authorizableNodeName); + preconditions.removeCandidate(getPid(properties)); + maybeDeactivate(); + } + + public synchronized void bindAuthorizableActionProvider(AuthorizableActionProvider authorizableActionProvider, Map properties) { + authorizableActionProviders.add(authorizableActionProvider); + preconditions.addCandidate(getPid(properties)); + maybeActivate(); + } + + public synchronized void unbindAuthorizableActionProvider(AuthorizableActionProvider authorizableActionProvider, Map properties) { + authorizableActionProviders.remove(authorizableActionProvider); + preconditions.removeCandidate(getPid(properties)); + maybeDeactivate(); + } + + public synchronized void bindRestrictionProvider(RestrictionProvider restrictionProvider, Map properties) { + restrictionProviders.add(restrictionProvider); + preconditions.addCandidate(getPid(properties)); + maybeActivate(); + } + + public synchronized void unbindRestrictionProvider(RestrictionProvider restrictionProvider, Map properties) { + restrictionProviders.remove(restrictionProvider); + preconditions.removeCandidate(getPid(properties)); + maybeDeactivate(); + } + + public synchronized void bindUserAuthenticationFactory(UserAuthenticationFactory userAuthenticationFactory, Map properties) { + userAuthenticationFactories.add(userAuthenticationFactory); + preconditions.addCandidate(getPid(properties)); + maybeActivate(); + } + + public synchronized void unbindUserAuthenticationFactory(UserAuthenticationFactory userAuthenticationFactory, Map properties) { + userAuthenticationFactories.remove(userAuthenticationFactory); + preconditions.removeCandidate(getPid(properties)); + maybeDeactivate(); + } + + /** + * Create a new instance of {@code SecurityProvider} and register it as a + * service if some conditions hold. + *

+ * A new service is registered if (1) this component is activated, (2) the + * preconditions specified via OSGi configuration are satisfied, and (3) a + * {@code SecurityProvider} service was not already registered by a previous + * invocation of this method. + */ + private void maybeActivate() { + + // The component is not activated, yet. We have no means of registering + // the SecurityProvider. This method will be called again after + // activation completes. + + if (context == null) { + return; + } + + // The preconditions are not satisifed. This may happen when this + // component is activated but not enough mandatory services are bound + // to it. + + if (!preconditions.areSatisfied()) { + return; + } + + // The SecurityProvider is already registered. This may happen when a + // new dependency is added to this component, but the requirements are + // already satisfied. + + if (registration != null) { + return; + } + + // Create a new instance of the SecurityProvider. + + securityProvider = createSecurityProvider(); + + // Register the SecurityProvider. + + registration = context.registerService(SecurityProvider.class.getName(), securityProvider, null); + } + + /** + * Unregister a previously registered {@code SecurityProvider} service if + * the preconditions specified via OSGi configuration are satisfied. + */ + private void maybeDeactivate() { + + // If there is nothing to register, we obviously have nothing to do. + + if (registration == null) { + return; + } + + // The preconditions are not satisfied. This may happen when a + // dependency is unbound from the current component. + + if (preconditions.areSatisfied()) { + return; + } + + // Deregister the SecurityProvider. + + doDeactivate(); + } + + /** + * Unregister a previously registered {@code SecurityProvider} service. + */ + private void doDeactivate() { + securityProvider = null; + + registration.unregister(); + registration = null; + } + + /** + * Initialize a referenced {@code AuthorizationConfiguration} service. The + * service will be linked to the {@code SecurityProvider} managed by this + * component and to the {@code RestrictionProvider} services registered into + * the framework. + * + * @param authorizationConfiguration A {@code AuthorizationConfiguration} + * service referenced by this component. + * @return The same {@code AuthorizationConfiguration} service passed as a + * parameter after being initialized. + */ + private AuthorizationConfiguration initializeConfiguration(AuthorizationConfiguration authorizationConfiguration) { + return initializeConfiguration(authorizationConfiguration, ConfigurationParameters.of( + AccessControlConstants.PARAM_RESTRICTION_PROVIDER, createDelegatingRestrictionProvider() + )); + } + + /** + * Initialize a referenced {@code UserConfiguration} service. The service + * will be linked to the {@code SecurityProvider} managed by this component + * and to the {@code AuthorizableActionProvider}, {@code + * AuthorizableNodeName} and {@code UserAuthenticationFactory} registered + * into the framework. + * + * @param userConfiguration A {@code UserConfiguration} service referenced + * by this component. + * @return The same {@code UserConfiguration} service passed as a parameter + * after being initialized. + */ + private UserConfiguration initializeConfiguration(UserConfiguration userConfiguration) { + return initializeConfiguration(userConfiguration, ConfigurationParameters.of( + ConfigurationParameters.of(UserConstants.PARAM_AUTHORIZABLE_ACTION_PROVIDER, createDelegatingAuthorizableActionProvider()), + ConfigurationParameters.of(UserConstants.PARAM_AUTHORIZABLE_NODE_NAME, createDelegatingAuthorizableNodeName()), + ConfigurationParameters.of(UserConstants.PARAM_USER_AUTHENTICATION_FACTORY, createDelegatingUserAuthenticationFactory()) + )); + } + + + private T initializeConfiguration(T configuration) { + return initializeConfiguration(configuration, ConfigurationParameters.EMPTY); + } + + /** + * Initialize a referenced {@code SecurityConfiguration} services. The + * service will be linked to the {@code SecurityProvider} managed by this + * component, and its parameters will be merged with the parameters passed + * to this method. + * + * @param configuration An instance of {@code SecurityConfiguration} to + * initialize. + * @param parameters The parameters to merge with the ones already hold + * by the configuration. + * @param The type of the {@code SecurityConfiguration} + * instance. + * @return The same {@code SecurityConfiguration} after being initialized. + */ + private T initializeConfiguration(T configuration, ConfigurationParameters parameters) { + if (configuration instanceof ConfigurationBase) { + ConfigurationBase base = (ConfigurationBase) configuration; + base.setSecurityProvider(createDelegatingSecurityProvider()); + base.setParameters(ConfigurationParameters.of(parameters, base.getParameters())); + } + + return configuration; + } + + /** + * Create a {@code SecurityProvider} that references its configurations from + * the OSGi framework. + * + * @return An instance of {@code SecurityProvider}. + */ + private SecurityProvider createSecurityProvider() { + SecurityProviderImpl securityProvider = new SecurityProviderImpl(); + + securityProvider.setAuthenticationConfiguration(authenticationConfiguration); + securityProvider.setAuthorizationConfiguration(authorizationConfiguration); + securityProvider.setUserConfiguration(userConfiguration); + securityProvider.setPrivilegeConfiguration(privilegeConfiguration); + securityProvider.setPrincipalConfiguration(createDelegatingPrincipalConfiguration()); + securityProvider.setTokenConfiguration(createDelegatingTokenConfiguration()); + + return securityProvider; + } + + /** + * Create a {@code PrincipalConfiguration} that aggregates every {@code + * PrincipalConfiguration} service referenced by this component. + * + * @return An instance of {@code PrincipalConfiguration}. + */ + private PrincipalConfiguration createDelegatingPrincipalConfiguration() { + return new CompositePrincipalConfiguration(createDelegatingSecurityProvider()) { + + @Override + protected List getConfigurations() { + synchronized (SecurityProviderRegistration.this) { + return newArrayList(principalConfigurations); + } + } + + }; + } + + /** + * Create a {@code TokenConfiguration} that aggregates every {@code + * TokenConfiguration} service referenced by this component. + * + * @return An instance of {@code TokenConfiguration}. + */ + private TokenConfiguration createDelegatingTokenConfiguration() { + return new CompositeTokenConfiguration(createDelegatingSecurityProvider()) { + + @Override + protected List getConfigurations() { + synchronized (SecurityProviderRegistration.this) { + return newArrayList(tokenConfigurations); + } + } + + }; + } + + /** + * Create an instance of {@code SecurityProvider} that delegates its call to + * the {@code SecurityProvider} registered by this component. If no {@code + * SecurityProvider} is registered yet, the returned instance will just + * throw {@code IllegalStateException}. + *

+ * This delegate is necessary because some configurations require a {@code + * SecurityProvider} at construction time. The delegate can be considered a + * "promise" that a {@code SecurityProvider} will be registered when the + * right conditions are met. + * + * @return An instance of {@code SecurityProvider} + */ + private SecurityProvider createDelegatingSecurityProvider() { + return new SecurityProvider() { + + @Nonnull + @Override + public ConfigurationParameters getParameters(@Nullable String name) { + SecurityProvider delegate; + + synchronized (SecurityProviderRegistration.this) { + delegate = securityProvider; + } + + checkState(delegate != null); + + return delegate.getParameters(name); + } + + @Nonnull + @Override + public Iterable getConfigurations() { + SecurityProvider delegate; + + synchronized (SecurityProviderRegistration.this) { + delegate = securityProvider; + } + + checkState(delegate != null); + + return delegate.getConfigurations(); + } + + @Nonnull + @Override + public T getConfiguration(@Nonnull Class configClass) { + SecurityProvider delegate; + + synchronized (SecurityProviderRegistration.this) { + delegate = securityProvider; + } + + checkState(delegate != null); + + return checkNotNull(delegate).getConfiguration(configClass); + } + + }; + } + + /** + * Create a {@code RestrictionProvider} that aggregates every {@code + * RestrictionProvider} service referenced by this component. + * + * @return An instance of {@code RestrictionProvider}. + */ + private RestrictionProvider createDelegatingRestrictionProvider() { + return new WhiteboardRestrictionProvider() { + + @Override + protected List getServices() { + synchronized (SecurityProviderRegistration.this) { + return newArrayList(restrictionProviders); + } + } + + }; + } + + /** + * Create a {@code AuthorizableActionProvider} that aggregates every {@code + * AuthorizableActionProvider} service referenced by this component. + * + * @return An instance of {@code RestrictionProvider}. + */ + private AuthorizableActionProvider createDelegatingAuthorizableActionProvider() { + return new WhiteboardAuthorizableActionProvider() { + + @Override + protected List getServices() { + synchronized (SecurityProviderRegistration.this) { + return newArrayList(authorizableActionProviders); + } + } + + }; + } + + /** + * Create a {@code AuthorizableNodeName} that aggregates every {@code + * AuthorizableNodeName} service referenced by this component. + * + * @return An instance of {@code AuthorizableNodeName}. + */ + private AuthorizableNodeName createDelegatingAuthorizableNodeName() { + return new WhiteboardAuthorizableNodeName() { + + @Override + protected List getServices() { + synchronized (SecurityProviderRegistration.this) { + return newArrayList(authorizableNodeNames); + } + } + + }; + } + + /** + * Create a {@code UserAuthenticationFactory} that aggregates every {@code + * UserAuthenticationFactory} service referenced by this component. + * + * @return An instance of {@code UserAuthenticationFactory}. + */ + private UserAuthenticationFactory createDelegatingUserAuthenticationFactory() { + return new WhiteboardUserAuthenticationFactory(UserConfigurationImpl.getDefaultAuthenticationFactory()) { + + @Override + protected List getServices() { + synchronized (SecurityProviderRegistration.this) { + return newArrayList(userAuthenticationFactories); + } + } + + }; + } + + private String getPid(Map properties) { + String pid = PropertiesUtil.toString(properties.get(Constants.SERVICE_PID), null); + + if (pid == null) { + throw new IllegalArgumentException("Unable to find the service PID"); + } + + return pid; + } + + private String[] getRequiredConfigurationPids(Map configuration) { + return PropertiesUtil.toStringArray(configuration.get("requiredConfigurationPids"), new String[]{}); + } + +} Property changes on: oak-core/src/main/java/org/apache/jackrabbit/oak/security/SecurityProviderRegistration.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/package-info.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/security/package-info.java (revision 1702510) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/package-info.java (working copy) @@ -20,7 +20,7 @@ * * See README.md for more details. */ -@Version("1.0.1") +@Version("2.0.0") @Export(optional = "provide:=true") package org.apache.jackrabbit.oak.security; Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/token/CompositeTokenConfiguration.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/token/CompositeTokenConfiguration.java (revision 1702510) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/token/CompositeTokenConfiguration.java (working copy) @@ -28,7 +28,7 @@ /** * {@link TokenConfiguration} that combines different token provider implementations. */ -public final class CompositeTokenConfiguration extends CompositeConfiguration implements TokenConfiguration { +public class CompositeTokenConfiguration extends CompositeConfiguration implements TokenConfiguration { public CompositeTokenConfiguration(@Nonnull SecurityProvider securityProvider) { super(TokenConfiguration.NAME, securityProvider); Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/token/package-info.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/token/package-info.java (revision 1702510) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/token/package-info.java (working copy) @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@Version("1.1.0") +@Version("1.2.0") @Export(optional = "provide:=true") package org.apache.jackrabbit.oak.spi.security.authentication.token; Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/principal/CompositePrincipalConfiguration.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/principal/CompositePrincipalConfiguration.java (revision 1702510) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/principal/CompositePrincipalConfiguration.java (working copy) @@ -30,7 +30,7 @@ * {@link PrincipalConfiguration} that combines different principal provider * implementations that share a common principal manager implementation. */ -public final class CompositePrincipalConfiguration extends CompositeConfiguration implements PrincipalConfiguration { +public class CompositePrincipalConfiguration extends CompositeConfiguration implements PrincipalConfiguration { public CompositePrincipalConfiguration(@Nonnull SecurityProvider securityProvider) { super(PrincipalConfiguration.NAME, securityProvider); Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/principal/package-info.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/principal/package-info.java (revision 1702510) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/principal/package-info.java (working copy) @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@Version("1.0") +@Version("1.1.0") @Export(optional = "provide:=true") package org.apache.jackrabbit.oak.spi.security.principal;