You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by pa...@apache.org on 2021/01/28 13:29:15 UTC

[sling-org-apache-sling-serviceusermapper] branch issues/SLING-10099 updated: SLING-10099 : Validators should all agree for a service user to be valid and should be configurable

This is an automated email from the ASF dual-hosted git repository.

pauls pushed a commit to branch issues/SLING-10099
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-serviceusermapper.git


The following commit(s) were added to refs/heads/issues/SLING-10099 by this push:
     new 14dbc32  SLING-10099 : Validators should all agree for a service user to be valid and should be configurable
14dbc32 is described below

commit 14dbc3248c4f3795d25d62dfc7b32d265d2514d1
Author: Karl Pauls <ka...@gmail.com>
AuthorDate: Thu Jan 28 14:29:02 2021 +0100

    SLING-10099 : Validators should all agree for a service user to be valid and should be configurable
---
 pom.xml                                            |   4 +-
 .../serviceusermapping/ServiceUserMapped.java      |   2 +-
 .../serviceusermapping/ServiceUserMapper.java      |   4 +
 .../impl/ServiceUserMapperImpl.java                | 103 ++++++++++++++-------
 .../sling/serviceusermapping/package-info.java     |   2 +-
 .../impl/ServiceUserMapperImplTest.java            |  13 +--
 6 files changed, 83 insertions(+), 45 deletions(-)

diff --git a/pom.xml b/pom.xml
index ddb54e6..9ba02a4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,12 +23,12 @@
     <parent>
         <groupId>org.apache.sling</groupId>
         <artifactId>sling-bundle-parent</artifactId>
-        <version>36</version>
+        <version>40</version>
         <relativePath />
     </parent>
 
     <artifactId>org.apache.sling.serviceusermapper</artifactId>
-    <version>1.4.7-SNAPSHOT</version>
+    <version>1.5.0-SNAPSHOT</version>
 
     <name>Apache Sling Service User Mapper</name>
     <description>
diff --git a/src/main/java/org/apache/sling/serviceusermapping/ServiceUserMapped.java b/src/main/java/org/apache/sling/serviceusermapping/ServiceUserMapped.java
index e100661..7b0b4a3 100644
--- a/src/main/java/org/apache/sling/serviceusermapping/ServiceUserMapped.java
+++ b/src/main/java/org/apache/sling/serviceusermapping/ServiceUserMapped.java
@@ -45,6 +45,6 @@ public interface ServiceUserMapped {
     /**
      * The name of the osgi property holding the sub service name.
      */
-    static String SUBSERVICENAME = "subServiceName";
+    String SUBSERVICENAME = "subServiceName";
 
 }
diff --git a/src/main/java/org/apache/sling/serviceusermapping/ServiceUserMapper.java b/src/main/java/org/apache/sling/serviceusermapping/ServiceUserMapper.java
index 303c2d6..d65cab8 100644
--- a/src/main/java/org/apache/sling/serviceusermapping/ServiceUserMapper.java
+++ b/src/main/java/org/apache/sling/serviceusermapping/ServiceUserMapper.java
@@ -58,6 +58,10 @@ import org.osgi.framework.Bundle;
  */
 @ProviderType
 public interface ServiceUserMapper {
+	/**
+	 * Property to add as a unique id to a service registration.
+	 */
+	String VALIDATOR_ID = "validator.id";
 
 	/**
 	 * Returns the ID of a user to access the data store on behalf of the
diff --git a/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImpl.java b/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImpl.java
index 56165df..1fbfa10 100644
--- a/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImpl.java
+++ b/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImpl.java
@@ -18,19 +18,7 @@
  */
 package org.apache.sling.serviceusermapping.impl;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Dictionary;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Map;
-import java.util.SortedMap;
-import java.util.SortedSet;
-import java.util.TreeMap;
-import java.util.TreeSet;
+import java.util.*;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -85,7 +73,13 @@ public class ServiceUserMapperImpl implements ServiceUserMapper {
                      "default mapping is applied which uses the service user \"serviceuser--\" + bundleId + [\"--\" + subServiceName]")
         boolean user_enable_default_mapping() default true;
 
+        @AttributeDefinition(name = "Require Validation",
+                description = "Do validators have to be present and validate the service users?")
         boolean require_validation() default false;
+
+        @AttributeDefinition(name = "Required Validators",
+                description = "A list of required validators ids. If not present and require validation is on not user will be valid")
+        String[] required_validators() default {};
     }
 
     /** default log */
@@ -115,6 +109,10 @@ public class ServiceUserMapperImpl implements ServiceUserMapper {
 
     private volatile boolean requireValidation = false;
 
+    private final Set<String> requiredValidators = new HashSet<>();
+
+    private final List<String> presentValidators = new CopyOnWriteArrayList<>();
+
     @Activate
     public ServiceUserMapperImpl(final BundleContext bundleContext, final Config config) {
         this(bundleContext, config, Executors.newSingleThreadExecutor());
@@ -155,6 +153,9 @@ public class ServiceUserMapperImpl implements ServiceUserMapper {
         this.useDefaultMapping = config.user_enable_default_mapping();
         this.requireValidation = config.require_validation();
 
+        if (config.required_validators() != null) {
+            requiredValidators.addAll(Arrays.asList(config.required_validators()));
+        }
         RegistrationSet registrationSet = this.updateMappings();
 
         this.executeServiceRegistrationsAsync(registrationSet);
@@ -180,9 +181,13 @@ public class ServiceUserMapperImpl implements ServiceUserMapper {
      * @param serviceUserValidator
      */
     @Reference(cardinality=ReferenceCardinality.MULTIPLE, policy= ReferencePolicy.DYNAMIC)
-    protected synchronized void bindServiceUserValidator(final ServiceUserValidator serviceUserValidator) {
+    protected synchronized void bindServiceUserValidator(final ServiceUserValidator serviceUserValidator, final Map<String, ?> props) {
         userValidators.add(serviceUserValidator);
-        if (!requireValidation || !principalsValidators.isEmpty()) {
+        Object id = props.get(VALIDATOR_ID);
+        if (id instanceof String) {
+            presentValidators.add((String) id);
+        }
+        if (!requireValidation || !getPrincipalsValidators().isEmpty()) {
             restartAllActiveServiceUserMappedServices();
         }
     }
@@ -191,8 +196,12 @@ public class ServiceUserMapperImpl implements ServiceUserMapper {
      * unbind the serviceUserValidator
      * @param serviceUserValidator
      */
-    protected synchronized void unbindServiceUserValidator(final ServiceUserValidator serviceUserValidator) {
+    protected synchronized void unbindServiceUserValidator(final ServiceUserValidator serviceUserValidator, final Map<String, ?> props) {
         userValidators.remove(serviceUserValidator);
+        Object id = props.get(VALIDATOR_ID);
+        if (id instanceof String) {
+            presentValidators.remove(id);
+        }
         restartAllActiveServiceUserMappedServices();
     }
 
@@ -201,9 +210,13 @@ public class ServiceUserMapperImpl implements ServiceUserMapper {
      * @param servicePrincipalsValidator
      */
     @Reference(cardinality=ReferenceCardinality.MULTIPLE, policy= ReferencePolicy.DYNAMIC)
-    protected synchronized void bindServicePrincipalsValidator(final ServicePrincipalsValidator servicePrincipalsValidator) {
+    protected synchronized void bindServicePrincipalsValidator(final ServicePrincipalsValidator servicePrincipalsValidator, final Map<String, ?> props) {
         principalsValidators.add(servicePrincipalsValidator);
-        if (!requireValidation || !userValidators.isEmpty()) {
+        Object id = props.get(VALIDATOR_ID);
+        if (id instanceof String) {
+            presentValidators.add((String) id);
+        }
+        if (!requireValidation || !getUserValidators().isEmpty()) {
             restartAllActiveServiceUserMappedServices();
         }
     }
@@ -212,8 +225,12 @@ public class ServiceUserMapperImpl implements ServiceUserMapper {
      * unbind the servicePrincipalsValidator
      * @param servicePrincipalsValidator
      */
-    protected synchronized void unbindServicePrincipalsValidator(final ServicePrincipalsValidator servicePrincipalsValidator) {
+    protected synchronized void unbindServicePrincipalsValidator(final ServicePrincipalsValidator servicePrincipalsValidator, final Map<String, ?> props) {
         principalsValidators.remove(servicePrincipalsValidator);
+        Object id = props.get(VALIDATOR_ID);
+        if (id instanceof String) {
+            presentValidators.remove(id);
+        }
         restartAllActiveServiceUserMappedServices();
     }
 
@@ -455,19 +472,19 @@ public class ServiceUserMapperImpl implements ServiceUserMapper {
             log.debug("isValidUser: userId is null -> invalid");
             return false;
         }
-        if ( !userValidators.isEmpty()  || require) {
-            for (final ServiceUserValidator validator : userValidators) {
-                if ( validator.isValid(userId, serviceName, subServiceName) ) {
-                    log.debug("isValidUser: Validator {} accepts userId [{}] -> valid", validator, userId);
-                    return true;
+        List<ServiceUserValidator> validators = getUserValidators();
+        if (!validators.isEmpty()) {
+            for (final ServiceUserValidator validator : validators) {
+                if (!validator.isValid(userId, serviceName, subServiceName)) {
+                    log.debug("isValidUser: Validator {} doesn't accept userId [{}] -> invalid", validator, userId);
+                    return false;
                 }
             }
-            log.debug("isValidUser: No validator accepted userId [{}] -> invalid", userId);
-            return false;
+            log.debug("isValidUser: All validators accepted userId [{}] -> valid", userId);
         } else {
             log.debug("isValidUser: No active validators for userId [{}] -> valid", userId);
-            return true;
         }
+        return require ? !validators.isEmpty() : true;
     }
 
     private boolean areValidPrincipals(final Iterable<String> principalNames, final String serviceName, final String subServiceName, boolean require) {
@@ -475,18 +492,34 @@ public class ServiceUserMapperImpl implements ServiceUserMapper {
             log.debug("areValidPrincipals: principalNames are null -> invalid");
             return false;
         }
-        if ( !principalsValidators.isEmpty() || require ) {
-            for (final ServicePrincipalsValidator validator : principalsValidators) {
-                if ( validator.isValid(principalNames, serviceName, subServiceName) ) {
-                    log.debug("areValidPrincipals: Validator {} accepts principal names [{}] -> valid", validator, principalNames);
-                    return true;
+        List<ServicePrincipalsValidator> validators = getPrincipalsValidators();
+        if (!validators.isEmpty() || require) {
+            for (final ServicePrincipalsValidator validator : validators) {
+                if (!validator.isValid(principalNames, serviceName, subServiceName)) {
+                    log.debug("areValidPrincipals: Validator {} doesn't accept principal names [{}] -> invalid", validator, principalNames);
+                    return false;
                 }
             }
-            log.debug("areValidPrincipals: No validator accepted principal names [{}] -> invalid", principalNames);
-            return false;
+            log.debug("areValidPrincipals: All validators accepted principal names [{}] -> valid", principalNames);
         } else {
             log.debug("areValidPrincipals: No active validators for principal names [{}] -> valid", principalNames);
-            return true;
+        }
+        return require ? !validators.isEmpty() : true;
+    }
+
+    private List<ServiceUserValidator> getUserValidators() {
+        if (presentValidators.containsAll(requiredValidators)) {
+            return userValidators;
+        } else {
+            return Collections.emptyList();
+        }
+    }
+
+    private List<ServicePrincipalsValidator> getPrincipalsValidators() {
+        if (presentValidators.containsAll(requiredValidators)) {
+            return principalsValidators;
+        } else {
+            return Collections.emptyList();
         }
     }
 
diff --git a/src/main/java/org/apache/sling/serviceusermapping/package-info.java b/src/main/java/org/apache/sling/serviceusermapping/package-info.java
index 547a6af..2a6e541 100644
--- a/src/main/java/org/apache/sling/serviceusermapping/package-info.java
+++ b/src/main/java/org/apache/sling/serviceusermapping/package-info.java
@@ -17,6 +17,6 @@
  * under the License.
  */
 
-@org.osgi.annotation.versioning.Version("1.4.0")
+@org.osgi.annotation.versioning.Version("1.5.0")
 package org.apache.sling.serviceusermapping;
 
diff --git a/src/test/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImplTest.java b/src/test/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImplTest.java
index f94b8af..560fe88 100644
--- a/src/test/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImplTest.java
+++ b/src/test/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImplTest.java
@@ -26,6 +26,7 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Dictionary;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -195,7 +196,7 @@ public class ServiceUserMapperImplTest {
                 return true;
             }
         };
-        sum.bindServiceUserValidator(serviceUserValidator);
+        sum.bindServiceUserValidator(serviceUserValidator, Collections.emptyMap());
 
         TestCase.assertEquals(null, sum.getServiceUserID(BUNDLE1, null));
         TestCase.assertEquals(ANOTHER, sum.getServiceUserID(BUNDLE2, null));
@@ -219,10 +220,10 @@ public class ServiceUserMapperImplTest {
 
         final ServiceUserMapperImpl sum = new ServiceUserMapperImpl(null, config);
         ServiceUserValidator sampleInvalid = (serviceUserId, serviceName, subServiceName) -> !SAMPLE.equals(serviceUserId);
-        sum.bindServiceUserValidator(sampleInvalid);
+        sum.bindServiceUserValidator(sampleInvalid, Collections.emptyMap());
 
         ServiceUserValidator anotherInvalid = (serviceUserId, serviceName, subServiceName) -> !ANOTHER.equals(serviceUserId);
-        sum.bindServiceUserValidator(anotherInvalid);
+        sum.bindServiceUserValidator(anotherInvalid, Collections.emptyMap());
 
         assertNull(sum.getServiceUserID(BUNDLE1, null));
         assertNull(sum.getServiceUserID(BUNDLE2, null));
@@ -312,7 +313,7 @@ public class ServiceUserMapperImplTest {
         ServicePrincipalsValidator validator = (servicePrincipalNames, serviceName, subServiceName) -> {
             return StreamSupport.stream(servicePrincipalNames.spliterator(), false).noneMatch(SAMPLE::equals);
         };
-        sum.bindServicePrincipalsValidator(validator);
+        sum.bindServicePrincipalsValidator(validator, Collections.emptyMap());
 
         assertNull(sum.getServicePrincipalNames(BUNDLE1, null));
         assertNull(sum.getServicePrincipalNames(BUNDLE2, null));
@@ -334,12 +335,12 @@ public class ServiceUserMapperImplTest {
         ServicePrincipalsValidator sampleInvalid = (servicePrincipalNames, serviceName, subServiceName) -> {
             return StreamSupport.stream(servicePrincipalNames.spliterator(), false).noneMatch(SAMPLE::equals);
         };
-        sum.bindServicePrincipalsValidator(sampleInvalid);
+        sum.bindServicePrincipalsValidator(sampleInvalid, Collections.emptyMap());
 
         ServicePrincipalsValidator anotherInvalid = (servicePrincipalNames, serviceName, subServiceName) -> {
             return StreamSupport.stream(servicePrincipalNames.spliterator(), false).noneMatch(ANOTHER::equals);
         };
-        sum.bindServicePrincipalsValidator(anotherInvalid);
+        sum.bindServicePrincipalsValidator(anotherInvalid, Collections.emptyMap());
 
         assertNull(sum.getServicePrincipalNames(BUNDLE1, null));
         assertNull(sum.getServicePrincipalNames(BUNDLE2, null));