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 1702914)
+++ 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 = true;
+ }
+ }
+
+ /**
+ * 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 1702914)
+++ 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 extends SecurityConfiguration> 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,651 @@
+/*
+ * 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.Modified;
+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.osgi.OsgiWhiteboard;
+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 = "requiredServicePids",
+ 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 = AuthorizableNodeName.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 : getRequiredServicePids(configuration)) {
+ preconditions.addPrecondition(pid);
+ }
+
+ this.context = context;
+
+ maybeActivate();
+ }
+
+ @Modified
+ public synchronized void modified(Map configuration) {
+ preconditions.clearPreconditions();
+
+ for (String pid : getRequiredServicePids(configuration)) {
+ preconditions.addPrecondition(pid);
+ }
+
+ maybeDeactivate();
+ maybeActivate();
+ }
+
+ @Deactivate
+ public synchronized void deactivate() {
+ doDeactivate();
+ preconditions.clearPreconditions();
+ context = null;
+ }
+
+ public void bindAuthorizationConfiguration(AuthorizationConfiguration authorizationConfiguration) {
+ this.authorizationConfiguration = initializeConfiguration(authorizationConfiguration);
+ }
+
+ public void unbindAuthorizationConfiguration(AuthorizationConfiguration authorizationConfiguration) {
+ this.authorizationConfiguration = null;
+ }
+
+ public void bindAuthenticationConfiguration(AuthenticationConfiguration authenticationConfiguration) {
+ this.authenticationConfiguration = initializeConfiguration(authenticationConfiguration);
+ }
+
+ public void unbindAuthenticationConfiguration(AuthenticationConfiguration authenticationConfiguration) {
+ this.authenticationConfiguration = null;
+ }
+
+ public void bindPrivilegeConfiguration(PrivilegeConfiguration privilegeConfiguration) {
+ this.privilegeConfiguration = initializeConfiguration(privilegeConfiguration);
+ }
+
+ public void unbindPrivilegeConfiguration(PrivilegeConfiguration privilegeConfiguration) {
+ this.privilegeConfiguration = null;
+ }
+
+ public void bindUserConfiguration(UserConfiguration userConfiguration) {
+ this.userConfiguration = initializeConfiguration(userConfiguration);
+ }
+
+ public void unbindUserConfiguration(UserConfiguration userConfiguration) {
+ this.userConfiguration = null;
+ }
+
+ public synchronized void bindPrincipalConfiguration(PrincipalConfiguration principalConfiguration, Map properties) {
+ principalConfigurations.add(initializeConfiguration(principalConfiguration));
+ addCandidate(properties);
+ maybeActivate();
+ }
+
+ public synchronized void unbindPrincipalConfiguration(PrincipalConfiguration principalConfiguration, Map properties) {
+ principalConfigurations.remove(principalConfiguration);
+ removeCandidate(properties);
+ maybeDeactivate();
+ }
+
+ public synchronized void bindTokenConfiguration(TokenConfiguration tokenConfiguration, Map properties) {
+ tokenConfigurations.add(initializeConfiguration(tokenConfiguration));
+ addCandidate(properties);
+ maybeActivate();
+ }
+
+ public synchronized void unbindTokenConfiguration(TokenConfiguration tokenConfiguration, Map properties) {
+ tokenConfigurations.remove(tokenConfiguration);
+ removeCandidate(properties);
+ maybeDeactivate();
+ }
+
+ public synchronized void bindAuthorizableNodeName(AuthorizableNodeName authorizableNodeName, Map properties) {
+ authorizableNodeNames.add(authorizableNodeName);
+ addCandidate(properties);
+ maybeActivate();
+ }
+
+ public synchronized void unbindAuthorizableNodeName(AuthorizableNodeName authorizableNodeName, Map properties) {
+ authorizableNodeNames.remove(authorizableNodeName);
+ removeCandidate(properties);
+ maybeDeactivate();
+ }
+
+ public synchronized void bindAuthorizableActionProvider(AuthorizableActionProvider authorizableActionProvider, Map properties) {
+ authorizableActionProviders.add(authorizableActionProvider);
+ addCandidate(properties);
+ maybeActivate();
+ }
+
+ public synchronized void unbindAuthorizableActionProvider(AuthorizableActionProvider authorizableActionProvider, Map properties) {
+ authorizableActionProviders.remove(authorizableActionProvider);
+ removeCandidate(properties);
+ maybeDeactivate();
+ }
+
+ public synchronized void bindRestrictionProvider(RestrictionProvider restrictionProvider, Map properties) {
+ restrictionProviders.add(restrictionProvider);
+ addCandidate(properties);
+ maybeActivate();
+ }
+
+ public synchronized void unbindRestrictionProvider(RestrictionProvider restrictionProvider, Map properties) {
+ restrictionProviders.remove(restrictionProvider);
+ removeCandidate(properties);
+ maybeDeactivate();
+ }
+
+ public synchronized void bindUserAuthenticationFactory(UserAuthenticationFactory userAuthenticationFactory, Map properties) {
+ userAuthenticationFactories.add(userAuthenticationFactory);
+ addCandidate(properties);
+ maybeActivate();
+ }
+
+ public synchronized void unbindUserAuthenticationFactory(UserAuthenticationFactory userAuthenticationFactory, Map properties) {
+ userAuthenticationFactories.remove(userAuthenticationFactory);
+ removeCandidate(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());
+ securityProvider.setWhiteboard(new OsgiWhiteboard(context));
+
+ 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 extends SecurityConfiguration> 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 void addCandidate(Map properties) {
+ String pid = getServicePid(properties);
+
+ if (pid == null) {
+ return;
+ }
+
+ preconditions.addCandidate(pid);
+ }
+
+ private void removeCandidate(Map properties) {
+ String pid = getServicePid(properties);
+
+ if (pid == null) {
+ return;
+ }
+
+ preconditions.removeCandidate(pid);
+ }
+
+ private String getServicePid(Map properties) {
+ return PropertiesUtil.toString(properties.get(Constants.SERVICE_PID), null);
+ }
+
+ private String[] getRequiredServicePids(Map configuration) {
+ return PropertiesUtil.toStringArray(configuration.get("requiredServicePids"), 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 1702914)
+++ 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 1702914)
+++ 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 1702914)
+++ 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 1702914)
+++ 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 1702914)
+++ 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;
Index: oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/SecurityProviderRegistrationTest.groovy
===================================================================
--- oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/SecurityProviderRegistrationTest.groovy (revision 0)
+++ oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/SecurityProviderRegistrationTest.groovy (working copy)
@@ -0,0 +1,402 @@
+/*
+ * 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.run.osgi
+
+import org.apache.felix.connect.launch.PojoServiceRegistry
+import org.apache.jackrabbit.api.security.principal.PrincipalManager
+import org.apache.jackrabbit.oak.api.Root
+import org.apache.jackrabbit.oak.api.Tree
+import org.apache.jackrabbit.oak.namepath.NamePathMapper
+import org.apache.jackrabbit.oak.spi.commit.CommitHook
+import org.apache.jackrabbit.oak.spi.commit.MoveTracker
+import org.apache.jackrabbit.oak.spi.commit.ValidatorProvider
+import org.apache.jackrabbit.oak.spi.lifecycle.RepositoryInitializer
+import org.apache.jackrabbit.oak.spi.lifecycle.WorkspaceInitializer
+import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters
+import org.apache.jackrabbit.oak.spi.security.Context
+import org.apache.jackrabbit.oak.spi.security.SecurityProvider
+import org.apache.jackrabbit.oak.spi.security.authentication.Authentication
+import org.apache.jackrabbit.oak.spi.security.authentication.token.TokenConfiguration
+import org.apache.jackrabbit.oak.spi.security.authentication.token.TokenProvider
+import org.apache.jackrabbit.oak.spi.security.authorization.restriction.Restriction
+import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionDefinition
+import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionPattern
+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.principal.PrincipalProvider
+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.AuthorizableAction
+import org.apache.jackrabbit.oak.spi.security.user.action.AuthorizableActionProvider
+import org.apache.jackrabbit.oak.spi.xml.ProtectedItemImporter
+import org.junit.Before
+import org.junit.Test
+import org.osgi.framework.ServiceReference
+import org.osgi.service.cm.ConfigurationAdmin
+
+import javax.annotation.Nonnull
+import javax.annotation.Nullable
+import javax.jcr.RepositoryException
+import javax.jcr.Value
+import javax.jcr.security.AccessControlException
+import java.security.Principal
+import java.util.concurrent.TimeUnit
+
+class SecurityProviderRegistrationTest extends AbstractRepositoryFactoryTest {
+
+ private PojoServiceRegistry registry;
+
+ @Before
+ public void initializeRegistry() {
+ registry = repositoryFactory.initializeServiceRegistry(config)
+ }
+
+ /**
+ * Test that, without any additional configuration, a SecurityProvider
+ * service is registered by default.
+ */
+ @Test
+ public void testDefaultSetup() {
+ assert securityProviderServiceReferences.length == 1
+ }
+
+ /**
+ * A SecurityProvider shouldn't start without a required
+ * PrincipalConfiguration service.
+ */
+ @Test
+ public void testRequiredPrincipalConfigurationNotAvailable() {
+ testRequiredService(PrincipalConfiguration, newPrincipalConfiguration())
+ }
+
+ /**
+ * A SecurityProvider shouldn't start without a required TokenConfiguration
+ * service.
+ */
+ @Test
+ public void testRequiredTokenConfigurationNotAvailable() {
+ testRequiredService(TokenConfiguration, newTokenConfiguration())
+ }
+
+ /**
+ * A SecurityProvider shouldn't start without a required
+ * AuthorizableNodeName service.
+ */
+ @Test
+ public void testRequiredAuthorizableNodeNameNotAvailable() {
+ testRequiredService(AuthorizableNodeName, newAuthorizableNodeName())
+ }
+
+ /**
+ * A SecurityProvider shouldn't start without a required
+ * AuthorizableActionProvider service.
+ */
+ @Test
+ public void testRequiredAuthorizableActionProviderNotAvailable() {
+ testRequiredService(AuthorizableActionProvider, newAuthorizableActionProvider())
+ }
+
+ /**
+ * A SecurityProvider shouldn't start without a required RestrictionProvider
+ * service.
+ */
+ @Test
+ public void testRequiredRestrictionProviderNotAvailable() {
+ testRequiredService(RestrictionProvider, newRestrictionProvider())
+ }
+
+ /**
+ * A SecurityProvider shouldn't start without a required
+ * UserAuthenticationFactory service.
+ */
+ @Test
+ public void testRequiredUserAuthenticationFactoryNotAvailable() {
+ testRequiredService(UserAuthenticationFactory, newUserAuthenticationFactory())
+ }
+
+ private void testRequiredService(Class serviceClass, T service) {
+
+ // Adding a new precondition on a missing service PID forces the
+ // SecurityProvider to unregister.
+
+ setRequiredServicePids("test.Required" + serviceClass.simpleName)
+ TimeUnit.MILLISECONDS.sleep(500);
+ assert securityProviderServiceReferences == null
+
+ // If a service is registered, and if the PID of the service matches the
+ // precondition, the SecurityProvider is registered again.
+
+ Properties properties = new Properties()
+ properties.put("service.pid", "test.Required" + serviceClass.simpleName)
+ def registration = registry.registerService(serviceClass.name, service, properties)
+ assert securityProviderServiceReferences != null
+
+ // If the service is unregistered, but the precondition is still in
+ // place, the SecurityProvider unregisters again.
+
+ registration.unregister()
+ assert securityProviderServiceReferences == null
+
+ // Removing the precondition allows the SecurityProvider to register.
+
+ clearRequiredServicePids()
+ TimeUnit.MILLISECONDS.sleep(500)
+ assert securityProviderServiceReferences != null
+ }
+
+ private ServiceReference>[] getSecurityProviderServiceReferences() {
+ return registry.getServiceReferences(SecurityProvider.class.name, null)
+ }
+
+ private void setRequiredServicePids(String... pids) {
+ setConfiguration([
+ "org.apache.jackrabbit.oak.security.SecurityProviderRegistration": [
+ "requiredServicePids": pids
+ ]
+ ])
+ }
+
+ private void clearRequiredServicePids() {
+ setConfiguration([
+ "org.apache.jackrabbit.oak.security.SecurityProviderRegistration": [:]
+ ])
+ }
+
+ private void setConfiguration(Map> configuration) {
+ getConfigurationInstaller().installConfigs(configuration)
+ }
+
+ private ConfigInstaller getConfigurationInstaller() {
+ return new ConfigInstaller(getConfigurationAdmin(), registry.bundleContext)
+ }
+
+ private ConfigurationAdmin getConfigurationAdmin() {
+ return registry.getService(registry.getServiceReference(ConfigurationAdmin.class.name)) as ConfigurationAdmin
+ }
+
+ private static PrincipalConfiguration newPrincipalConfiguration() {
+ return new PrincipalConfiguration() {
+
+ @Override
+ PrincipalManager getPrincipalManager(Root root, NamePathMapper namePathMapper) {
+ return null
+ }
+
+ @Override
+ PrincipalProvider getPrincipalProvider(Root root, NamePathMapper namePathMapper) {
+ return null
+ }
+
+ @Override
+ String getName() {
+ return null
+ }
+
+ @Override
+ ConfigurationParameters getParameters() {
+ return null
+ }
+
+ @Override
+ WorkspaceInitializer getWorkspaceInitializer() {
+ return null
+ }
+
+ @Override
+ RepositoryInitializer getRepositoryInitializer() {
+ return null
+ }
+
+ @Override
+ List extends CommitHook> getCommitHooks(
+ @Nonnull String workspaceName) {
+ return null
+ }
+
+ @Override
+ List extends ValidatorProvider> getValidators(
+ @Nonnull String workspaceName,
+ @Nonnull Set principals,
+ @Nonnull MoveTracker moveTracker) {
+ return null
+ }
+
+ @Override
+ List getProtectedItemImporters() {
+ return null
+ }
+
+ @Override
+ Context getContext() {
+ return null
+ }
+
+ }
+ }
+
+ private static TokenConfiguration newTokenConfiguration() {
+ return new TokenConfiguration() {
+
+ @Override
+ TokenProvider getTokenProvider(Root root) {
+ return null
+ }
+
+ @Override
+ String getName() {
+ return null
+ }
+
+ @Override
+ ConfigurationParameters getParameters() {
+ return null
+ }
+
+ @Override
+ WorkspaceInitializer getWorkspaceInitializer() {
+ return null
+ }
+
+ @Override
+ RepositoryInitializer getRepositoryInitializer() {
+ return null
+ }
+
+ @Override
+ List extends CommitHook> getCommitHooks(
+ @Nonnull String workspaceName) {
+ return null
+ }
+
+ @Override
+ List extends ValidatorProvider> getValidators(
+ @Nonnull String workspaceName,
+ @Nonnull Set principals,
+ @Nonnull MoveTracker moveTracker) {
+ return null
+ }
+
+ @Override
+ List getProtectedItemImporters() {
+ return null
+ }
+
+ @Override
+ Context getContext() {
+ return null
+ }
+
+ }
+ }
+
+ private static AuthorizableNodeName newAuthorizableNodeName() {
+ return new AuthorizableNodeName() {
+
+ @Override
+ String generateNodeName(@Nonnull String authorizableId) {
+ return null
+ }
+
+ }
+ }
+
+ private static AuthorizableActionProvider newAuthorizableActionProvider() {
+ return new AuthorizableActionProvider() {
+
+ @Override
+ List extends AuthorizableAction> getAuthorizableActions(
+ @Nonnull SecurityProvider securityProvider) {
+ return null
+ }
+
+ }
+ }
+
+ private static RestrictionProvider newRestrictionProvider() {
+ new RestrictionProvider() {
+
+ @Override
+ Set getSupportedRestrictions(
+ @Nullable String oakPath) {
+ return null
+ }
+
+ @Override
+ Restriction createRestriction(
+ @Nullable String oakPath,
+ @Nonnull String oakName,
+ @Nonnull Value value) throws AccessControlException, RepositoryException {
+ return null
+ }
+
+ @Override
+ Restriction createRestriction(
+ @Nullable String oakPath,
+ @Nonnull String oakName,
+ @Nonnull Value... values) throws AccessControlException, RepositoryException {
+ return null
+ }
+
+ @Override
+ Set readRestrictions(
+ @Nullable String oakPath, @Nonnull Tree aceTree) {
+ return null
+ }
+
+ @Override
+ void writeRestrictions(String oakPath, Tree aceTree, Set restrictions) throws RepositoryException {
+
+ }
+
+ @Override
+ void validateRestrictions(
+ @Nullable String oakPath,
+ @Nonnull Tree aceTree) throws AccessControlException, RepositoryException {
+
+ }
+
+ @Override
+ RestrictionPattern getPattern(
+ @Nullable String oakPath, @Nonnull Tree tree) {
+ return null
+ }
+
+ @Override
+ RestrictionPattern getPattern(
+ @Nullable String oakPath,
+ @Nonnull Set restrictions) {
+ return null
+ }
+
+ }
+ }
+
+ private static UserAuthenticationFactory newUserAuthenticationFactory() {
+ return new UserAuthenticationFactory() {
+
+ @Override
+ Authentication getAuthentication(
+ @Nonnull UserConfiguration configuration,
+ @Nonnull Root root, @Nullable String userId) {
+ return null
+ }
+
+ }
+ }
+
+}