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 1703384)
+++ 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,117 @@
+/*
+ * 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;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("Preconditions(preconditions = %s, candidates = %s)", preconditions, candidates);
+ }
+
+}
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 1703384)
+++ 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,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.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 org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.collect.Lists.newCopyOnWriteArrayList;
+
+@Component(
+ immediate = true,
+ metatype = true,
+ label = "Apache Jackrabbit Oak SecurityProvider",
+ description = "The default SecurityProvider embedded in Apache Jackrabbit Oak"
+)
+@Properties({
+ @Property(
+ name = "requiredServicePids",
+ label = "Required service PIDs",
+ description = "The SecurityProvider will not register itself " +
+ "unless the services identified by these PIDs are " +
+ "registered first. Only the PIDs of implementations of " +
+ "the following interfaces are checked: " +
+ "PrincipalConfiguration, TokenConfiguration, " +
+ "AuthorizableNodeName, AuthorizableActionProvider, " +
+ "RestrictionProvider and UserAuthenticationFactory.",
+ value = {
+ "org.apache.jackrabbit.oak.security.principal.PrincipalConfigurationImpl",
+ "org.apache.jackrabbit.oak.security.authentication.token.TokenConfigurationImpl",
+ "org.apache.jackrabbit.oak.security.user.RandomAuthorizableNodeName",
+ "org.apache.jackrabbit.oak.spi.security.user.action.DefaultAuthorizableActionProvider",
+ "org.apache.jackrabbit.oak.security.authorization.restriction.RestrictionProviderImpl",
+ "org.apache.jackrabbit.oak.security.user.UserAuthenticationFactoryImpl"
+ },
+ 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 {
+
+ private static final Logger log = LoggerFactory.getLogger(SecurityProviderRegistration.class);
+
+ @Reference
+ private AuthorizationConfiguration authorizationConfiguration;
+
+ @Reference
+ private AuthenticationConfiguration authenticationConfiguration;
+
+ @Reference
+ private PrivilegeConfiguration privilegeConfiguration;
+
+ @Reference
+ private UserConfiguration userConfiguration;
+
+ private BundleContext context;
+
+ private ServiceRegistration registration;
+
+ private boolean registering;
+
+ private final Preconditions preconditions = new Preconditions();
+
+ private final List principalConfigurations = newCopyOnWriteArrayList();
+
+ private final List tokenConfigurations = newCopyOnWriteArrayList();
+
+ private final List authorizableNodeNames = newCopyOnWriteArrayList();
+
+ private final List authorizableActionProviders = newCopyOnWriteArrayList();
+
+ private final List restrictionProviders = newCopyOnWriteArrayList();
+
+ private final List userAuthenticationFactories = newCopyOnWriteArrayList();
+
+ @Activate
+ public void activate(BundleContext context, Map configuration) {
+ String[] requiredServicePids = getRequiredServicePids(configuration);
+
+ synchronized (this) {
+ for (String pid : requiredServicePids) {
+ preconditions.addPrecondition(pid);
+ }
+
+ this.context = context;
+ }
+
+ maybeRegister();
+ }
+
+ @Modified
+ public void modified(Map configuration) {
+ String[] requiredServicePids = getRequiredServicePids(configuration);
+
+ synchronized (this) {
+ preconditions.clearPreconditions();
+
+ for (String pid : requiredServicePids) {
+ preconditions.addPrecondition(pid);
+ }
+ }
+
+ maybeUnregister();
+ maybeRegister();
+ }
+
+ @Deactivate
+ public void deactivate() {
+ ServiceRegistration registration;
+
+ synchronized (this) {
+ registration = this.registration;
+
+ this.registration = null;
+ this.registering = false;
+ this.context = null;
+
+ this.preconditions.clearPreconditions();
+ }
+
+ if (registration != null) {
+ registration.unregister();
+ }
+ }
+
+ public void bindAuthorizationConfiguration(AuthorizationConfiguration authorizationConfiguration) {
+ this.authorizationConfiguration = authorizationConfiguration;
+ }
+
+ public void unbindAuthorizationConfiguration(AuthorizationConfiguration authorizationConfiguration) {
+ this.authorizationConfiguration = null;
+ }
+
+ public void bindAuthenticationConfiguration(AuthenticationConfiguration authenticationConfiguration) {
+ this.authenticationConfiguration = authenticationConfiguration;
+ }
+
+ public void unbindAuthenticationConfiguration(AuthenticationConfiguration authenticationConfiguration) {
+ this.authenticationConfiguration = null;
+ }
+
+ public void bindPrivilegeConfiguration(PrivilegeConfiguration privilegeConfiguration) {
+ this.privilegeConfiguration = privilegeConfiguration;
+ }
+
+ public void unbindPrivilegeConfiguration(PrivilegeConfiguration privilegeConfiguration) {
+ this.privilegeConfiguration = null;
+ }
+
+ public void bindUserConfiguration(UserConfiguration userConfiguration) {
+ this.userConfiguration = userConfiguration;
+ }
+
+ public void unbindUserConfiguration(UserConfiguration userConfiguration) {
+ this.userConfiguration = null;
+ }
+
+ public void bindPrincipalConfiguration(PrincipalConfiguration principalConfiguration, Map properties) {
+ synchronized (this) {
+ principalConfigurations.add(principalConfiguration);
+ addCandidate(properties);
+ }
+
+ maybeRegister();
+ }
+
+ public void unbindPrincipalConfiguration(PrincipalConfiguration principalConfiguration, Map properties) {
+ synchronized (this) {
+ principalConfigurations.remove(principalConfiguration);
+ removeCandidate(properties);
+ }
+
+ maybeUnregister();
+ }
+
+ public void bindTokenConfiguration(TokenConfiguration tokenConfiguration, Map properties) {
+ synchronized (this) {
+ tokenConfigurations.add(tokenConfiguration);
+ addCandidate(properties);
+ }
+
+ maybeRegister();
+ }
+
+ public void unbindTokenConfiguration(TokenConfiguration tokenConfiguration, Map properties) {
+ synchronized (this) {
+ tokenConfigurations.remove(tokenConfiguration);
+ removeCandidate(properties);
+ }
+
+ maybeUnregister();
+ }
+
+ public void bindAuthorizableNodeName(AuthorizableNodeName authorizableNodeName, Map properties) {
+ synchronized (this) {
+ authorizableNodeNames.add(authorizableNodeName);
+ addCandidate(properties);
+ }
+
+ maybeRegister();
+ }
+
+ public void unbindAuthorizableNodeName(AuthorizableNodeName authorizableNodeName, Map properties) {
+ synchronized (this) {
+ authorizableNodeNames.remove(authorizableNodeName);
+ removeCandidate(properties);
+ }
+
+ maybeUnregister();
+ }
+
+ public void bindAuthorizableActionProvider(AuthorizableActionProvider authorizableActionProvider, Map properties) {
+ synchronized (this) {
+ authorizableActionProviders.add(authorizableActionProvider);
+ addCandidate(properties);
+ }
+
+ maybeRegister();
+ }
+
+ public void unbindAuthorizableActionProvider(AuthorizableActionProvider authorizableActionProvider, Map properties) {
+ synchronized (this) {
+ authorizableActionProviders.remove(authorizableActionProvider);
+ removeCandidate(properties);
+ }
+
+ maybeUnregister();
+ }
+
+ public void bindRestrictionProvider(RestrictionProvider restrictionProvider, Map properties) {
+ synchronized (this) {
+ restrictionProviders.add(restrictionProvider);
+ addCandidate(properties);
+ }
+
+ maybeRegister();
+ }
+
+ public void unbindRestrictionProvider(RestrictionProvider restrictionProvider, Map properties) {
+ synchronized (this) {
+ restrictionProviders.remove(restrictionProvider);
+ removeCandidate(properties);
+ }
+
+ maybeUnregister();
+ }
+
+ public void bindUserAuthenticationFactory(UserAuthenticationFactory userAuthenticationFactory, Map properties) {
+ synchronized (this) {
+ userAuthenticationFactories.add(userAuthenticationFactory);
+ addCandidate(properties);
+ }
+
+ maybeRegister();
+ }
+
+ public void unbindUserAuthenticationFactory(UserAuthenticationFactory userAuthenticationFactory, Map properties) {
+ synchronized (this) {
+ userAuthenticationFactories.remove(userAuthenticationFactory);
+ removeCandidate(properties);
+ }
+
+ maybeUnregister();
+ }
+
+ private void maybeRegister() {
+ BundleContext context;
+
+ log.info("Trying to register a SecurityProvider...");
+
+ synchronized (this) {
+
+ // The component is not activated, yet. We have no means of registering
+ // the SecurityProvider. This method will be called again after
+ // activation completes.
+
+ if (this.context == null) {
+ log.info("Aborting: no BundleContext is available");
+ 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()) {
+ log.info("Aborting: preconditions are not satisfied: {}", preconditions);
+ 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) {
+ log.info("Aborting: a SecurityProvider is already registered");
+ return;
+ }
+
+ // If the component is in the process of registering an instance of
+ // SecurityProvider, return. This check is necessary because we don't
+ // want to call createSecurityProvider() more than once. That method,
+ // in fact, changes the state of the bound dependencies (it sets a
+ // back-reference from the security configurations to the new
+ // SecurityProvider). We want those dependencies to change state only
+ // when we are sure that we will register the SecurityProvider we
+ // are creating.
+
+ if (registering) {
+ log.info("Aborting: a SecurityProvider is already being registered");
+ return;
+ }
+
+ // Mark the start of a registration process.
+
+ registering = true;
+
+ // Save the BundleContext for local usage.
+
+ context = this.context;
+ }
+
+ // Register the SecurityProvider.
+
+ ServiceRegistration registration = context.registerService(
+ SecurityProvider.class.getName(),
+ createSecurityProvider(context),
+ null
+ );
+
+ synchronized (this) {
+ this.registration = registration;
+ this.registering = false;
+ }
+
+ log.info("SecurityProvider instance registered");
+ }
+
+ private void maybeUnregister() {
+ ServiceRegistration registration;
+
+ log.info("Trying to unregister the SecurityProvider...");
+
+ synchronized (this) {
+
+ // If there is nothing to register, we obviously have nothing to do.
+
+ if (this.registration == null) {
+ log.info("Aborting: no SecurityProvider is registered");
+ return;
+ }
+
+ // The preconditions are not satisfied. This may happen when a
+ // dependency is unbound from the current component.
+
+ if (preconditions.areSatisfied()) {
+ log.info("Aborting: preconditions are satisfied");
+ return;
+ }
+
+ // Save the ServiceRegistration for local use.
+
+ registration = this.registration;
+ this.registration = null;
+ }
+
+ registration.unregister();
+
+ log.info("SecurityProvider instance unregistered");
+ }
+
+ private SecurityProvider createSecurityProvider(BundleContext context) {
+ SecurityProviderImpl securityProvider = new SecurityProviderImpl();
+
+ // Static, mandatory references
+
+ securityProvider.setAuthenticationConfiguration(initializeConfiguration(securityProvider, authenticationConfiguration));
+ securityProvider.setAuthorizationConfiguration(initializeConfiguration(securityProvider, authorizationConfiguration));
+ securityProvider.setUserConfiguration(initializeConfiguration(securityProvider, userConfiguration));
+ securityProvider.setPrivilegeConfiguration(initializeConfiguration(securityProvider, privilegeConfiguration));
+
+ // Multiple, dynamic references
+
+ securityProvider.setPrincipalConfiguration(createCompositePrincipalConfiguration(securityProvider));
+ securityProvider.setTokenConfiguration(createCompositeTokenConfiguration(securityProvider));
+
+ // Whiteboard
+
+ securityProvider.setWhiteboard(new OsgiWhiteboard(context));
+
+ return securityProvider;
+ }
+
+ private PrincipalConfiguration createCompositePrincipalConfiguration(SecurityProvider securityProvider) {
+ return new CompositePrincipalConfiguration(securityProvider) {
+
+ @Override
+ protected List getConfigurations() {
+ ArrayList configurations = newArrayList(newArrayList(principalConfigurations));
+
+ for (PrincipalConfiguration configuration : configurations) {
+ initializeConfiguration(getSecurityProvider(), configuration);
+ }
+
+ return configurations;
+ }
+
+ };
+ }
+
+ private TokenConfiguration createCompositeTokenConfiguration(SecurityProvider securityProvider) {
+ return new CompositeTokenConfiguration(securityProvider) {
+
+ @Override
+ protected List getConfigurations() {
+ List configurations = newArrayList(tokenConfigurations);
+
+ for (TokenConfiguration configuration : configurations) {
+ initializeConfiguration(getSecurityProvider(), configuration);
+ }
+
+ return configurations;
+ }
+
+ };
+ }
+
+ private AuthorizationConfiguration initializeConfiguration(SecurityProvider securityProvider, AuthorizationConfiguration authorizationConfiguration) {
+ return initializeConfiguration(securityProvider, authorizationConfiguration, ConfigurationParameters.of(
+ AccessControlConstants.PARAM_RESTRICTION_PROVIDER, createCompositeRestrictionProvider()
+ ));
+ }
+
+ private UserConfiguration initializeConfiguration(SecurityProvider securityProvider, UserConfiguration userConfiguration) {
+ return initializeConfiguration(securityProvider, userConfiguration, ConfigurationParameters.of(
+ ConfigurationParameters.of(UserConstants.PARAM_AUTHORIZABLE_ACTION_PROVIDER, createCompositeAuthorizableActionProvider()),
+ ConfigurationParameters.of(UserConstants.PARAM_AUTHORIZABLE_NODE_NAME, createCompositeAuthorizableNodeName()),
+ ConfigurationParameters.of(UserConstants.PARAM_USER_AUTHENTICATION_FACTORY, createCompositeUserAuthenticationFactory())
+ ));
+ }
+
+ private T initializeConfiguration(SecurityProvider securityProvider, T configuration) {
+ return initializeConfiguration(securityProvider, configuration, ConfigurationParameters.EMPTY);
+ }
+
+ private T initializeConfiguration(SecurityProvider securityProvider, T configuration, ConfigurationParameters parameters) {
+ if (configuration instanceof ConfigurationBase) {
+ ConfigurationBase base = (ConfigurationBase) configuration;
+ base.setSecurityProvider(securityProvider);
+ base.setParameters(ConfigurationParameters.of(parameters, base.getParameters()));
+ }
+
+ return configuration;
+ }
+
+ private RestrictionProvider createCompositeRestrictionProvider() {
+ return new WhiteboardRestrictionProvider() {
+
+ @Override
+ protected List getServices() {
+ return newArrayList(restrictionProviders);
+ }
+
+ };
+ }
+
+ private AuthorizableActionProvider createCompositeAuthorizableActionProvider() {
+ return new WhiteboardAuthorizableActionProvider() {
+
+ @Override
+ protected List getServices() {
+ return newArrayList(authorizableActionProviders);
+ }
+
+ };
+ }
+
+ private AuthorizableNodeName createCompositeAuthorizableNodeName() {
+ return new WhiteboardAuthorizableNodeName() {
+
+ @Override
+ protected List getServices() {
+ return newArrayList(authorizableNodeNames);
+ }
+
+ };
+ }
+
+ private UserAuthenticationFactory createCompositeUserAuthenticationFactory() {
+ return new WhiteboardUserAuthenticationFactory(UserConfigurationImpl.getDefaultAuthenticationFactory()) {
+
+ @Override
+ protected List getServices() {
+ 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/authentication/token/TokenConfigurationImpl.java
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenConfigurationImpl.java (revision 1703384)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenConfigurationImpl.java (working copy)
@@ -44,7 +44,7 @@
/**
* Default implementation for the {@code TokenConfiguration} interface.
*/
-@Component(metatype = true, label = "Apache Jackrabbit Oak TokenConfiguration")
+@Component(metatype = true, label = "Apache Jackrabbit Oak TokenConfiguration", immediate = true)
@Service({TokenConfiguration.class, SecurityConfiguration.class})
@Properties({
@Property(name = TokenProvider.PARAM_TOKEN_EXPIRATION,
Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/restriction/RestrictionProviderImpl.java
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/restriction/RestrictionProviderImpl.java (revision 1703384)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/restriction/RestrictionProviderImpl.java (working copy)
@@ -56,7 +56,7 @@
* is {@link org.apache.jackrabbit.oak.api.Type#STRINGS}.
*
*/
-@Component
+@Component(immediate = true)
@Service(RestrictionProvider.class)
public class RestrictionProviderImpl extends AbstractRestrictionProvider {
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 1703384)
+++ 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/security/principal/PrincipalConfigurationImpl.java
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/security/principal/PrincipalConfigurationImpl.java (revision 1703384)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/principal/PrincipalConfigurationImpl.java (working copy)
@@ -38,7 +38,7 @@
/**
* Default implementation of the {@code PrincipalConfiguration}
*/
-@Component()
+@Component(immediate = true)
@Service({PrincipalConfiguration.class, SecurityConfiguration.class})
public class PrincipalConfigurationImpl extends ConfigurationBase implements PrincipalConfiguration {
Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/RandomAuthorizableNodeName.java
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/RandomAuthorizableNodeName.java (revision 1703384)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/RandomAuthorizableNodeName.java (working copy)
@@ -33,7 +33,7 @@
* Implementation of the {@code AuthorizableNodeName} that generates a random
* node name that doesn't reveal the ID of the authorizable.
*/
-@Component(metatype = true, label = "Apache Jackrabbit Oak Random Authorizable Node Name", description = "Generates a random name for the authorizable node.", policy = ConfigurationPolicy.REQUIRE)
+@Component(metatype = true, label = "Apache Jackrabbit Oak Random Authorizable Node Name", description = "Generates a random name for the authorizable node.", immediate = true)
@Service(AuthorizableNodeName.class)
public class RandomAuthorizableNodeName implements AuthorizableNodeName {
Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserAuthenticationFactoryImpl.java
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserAuthenticationFactoryImpl.java (revision 1703384)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserAuthenticationFactoryImpl.java (working copy)
@@ -26,7 +26,7 @@
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-@Component
+@Component(immediate = true)
@Service
public class UserAuthenticationFactoryImpl implements UserAuthenticationFactory {
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 1703384)
+++ 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 1703384)
+++ 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 1703384)
+++ 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 1703384)
+++ 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-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/DefaultAuthorizableActionProvider.java
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/DefaultAuthorizableActionProvider.java (revision 1703384)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/DefaultAuthorizableActionProvider.java (working copy)
@@ -38,7 +38,7 @@
* Default implementation of the {@link AuthorizableActionProvider} interface
* that allows to config all actions provided by the OAK.
*/
-@Component(metatype = true, label = "Apache Jackrabbit Oak AuthorizableActionProvider")
+@Component(metatype = true, label = "Apache Jackrabbit Oak AuthorizableActionProvider", immediate = true)
@Service(AuthorizableActionProvider.class)
@Properties({
@Property(name = DefaultAuthorizableActionProvider.ENABLED_ACTIONS,
Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/package-info.java
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/package-info.java (revision 1703384)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/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.2")
+@Version("1.0.3")
@Export(optional = "provide:=true")
package org.apache.jackrabbit.oak.spi.security.user.action;
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,424 @@
+/*
+ * 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 != null
+ }
+
+ /**
+ * 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())
+ }
+
+ /**
+ * A SecurityProvider should be registered only if every every prerequisite
+ * is satisfied.
+ */
+ @Test
+ public void testMultipleRequiredServices() {
+
+ // Set up the SecurityProvider to require three services
+
+ setRequiredServicePids("test.RequiredPrincipalConfiguration", "test.RequiredTokenConfiguration", "test.AuthorizableNodeName")
+ TimeUnit.MILLISECONDS.sleep(500)
+ assert securityProviderServiceReferences == null
+
+ // Start the services and verify that only at the end the
+ // SecurityProvider registers itself
+
+ registry.registerService(PrincipalConfiguration.class.name, newPrincipalConfiguration(), dict("service.pid": "test.RequiredPrincipalConfiguration"))
+ assert securityProviderServiceReferences == null
+
+ registry.registerService(TokenConfiguration.class.name, newTokenConfiguration(), dict("service.pid": "test.RequiredTokenConfiguration"))
+ assert securityProviderServiceReferences == null
+
+ registry.registerService(TokenConfiguration.class.name, newTokenConfiguration(), dict("service.pid": "test.AuthorizableNodeName"))
+ assert securityProviderServiceReferences != null
+ }
+
+ 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.
+
+ def registration = registry.registerService(serviceClass.name, service, dict("service.pid": "test.Required" + serviceClass.simpleName))
+ 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.
+
+ setRequiredServicePids()
+ 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 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 Dictionary dict(Map map) {
+ return new Hashtable(map);
+ }
+
+ 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
+ }
+
+ }
+ }
+
+}