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,68 @@ +/* + * 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; + +class Preconditions { + + private final Set preconditions = newHashSet(); + + private final Set candidates = newHashSet(); + + private boolean dirty = false; + + private boolean satisfied = true; + + public void addPrecondition(String precondition) { + if (preconditions.add(precondition)) { + dirty = true; + } + } + + public void clearPreconditions() { + preconditions.clear(); + dirty = false; + satisfied = true; + } + + public void addCandidate(String pid) { + if (candidates.add(pid)) { + dirty = true; + } + } + + public void removeCandidate(String pid) { + if (candidates.remove(pid)) { + dirty = false; + } + } + + 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/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,294 @@ +/* + * 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.felix.scr.annotations.Service; +import org.apache.jackrabbit.oak.commons.PropertiesUtil; +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.TokenConfiguration; +import org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration; +import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider; +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.action.AuthorizableActionProvider; +import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; +import org.osgi.framework.ServiceRegistration; + +import java.util.List; +import java.util.Map; + +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 + ) +}) +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 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 synchronized void bindPrincipalConfiguration(PrincipalConfiguration principalConfiguration, Map properties) { + principalConfigurations.add(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(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.addCandidate(getPid(properties)); + maybeDeactivate(); + } + + 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; + } + + // Register the SecurityProvider. + + registration = context.registerService(SecurityProvider.class.getName(), createSecurityProvider(), null); + } + + 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(); + } + + private void doDeactivate() { + registration.unregister(); + registration = null; + } + + private SecurityProvider createSecurityProvider() { + throw new UnsupportedOperationException("not implemented"); + } + + 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