You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by js...@apache.org on 2016/11/16 11:56:47 UTC

svn commit: r1769962 - in /sling/trunk/bundles/jcr: base/src/main/java/org/apache/sling/jcr/base/ base/src/main/java/org/apache/sling/jcr/base/internal/ base/src/test/java/org/apache/sling/jcr/base/internal/ base/src/test/java/org/apache/sling/jcr/base...

Author: jsedding
Date: Wed Nov 16 11:56:46 2016
New Revision: 1769962

URL: http://svn.apache.org/viewvc?rev=1769962&view=rev
Log:
SLING-6285 - Implement LoginAdminWhitelist in JCR Base

- move implementation from o.a.s.jcr.oak.server to o.a.s.jcr.base
- move and refactor tests to work with moved implementation
- support @Modified callback on LoginAdminWhitelist to avoid restarting repositories on configuratin change
- improved error handling, i.e. set a message for LoginExceptions

Added:
    sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/internal/LoginAdminWhitelist.java
      - copied, changed from r1769656, sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/internal/LoginAdminWhitelist.java
    sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/internal/LoginAdminWhitelistConfiguration.java
      - copied, changed from r1769656, sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/internal/LoginAdminWhitelistConfiguration.java
    sling/trunk/bundles/jcr/base/src/test/java/org/apache/sling/jcr/base/internal/LoginAdminWhitelistTest.java
      - copied, changed from r1769656, sling/trunk/bundles/jcr/oak-server/src/test/java/org/apache/sling/jcr/oak/server/internal/LoginAdminWhitelistTest.java
    sling/trunk/bundles/jcr/base/src/test/java/org/apache/sling/jcr/base/util/ConfigAnnotationUtil.java   (with props)
Removed:
    sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/internal/LoginAdminWhitelist.java
    sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/internal/LoginAdminWhitelistConfiguration.java
    sling/trunk/bundles/jcr/oak-server/src/test/java/org/apache/sling/jcr/oak/server/internal/LoginAdminWhitelistTest.java
Modified:
    sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepository2.java
    sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepositoryManager.java
    sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/package-info.java
    sling/trunk/bundles/jcr/oak-server/pom.xml
    sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/internal/OakSlingRepositoryManager.java
    sling/trunk/bundles/jcr/oak-server/src/test/java/org/apache/sling/jcr/oak/server/it/OakServerTestSupport.java

Modified: sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepository2.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepository2.java?rev=1769962&r1=1769961&r2=1769962&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepository2.java (original)
+++ sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepository2.java Wed Nov 16 11:56:46 2016
@@ -373,11 +373,12 @@ public abstract class AbstractSlingRepos
         final boolean whitelisted = getSlingRepositoryManager().allowLoginAdministrativeForBundle(usingBundle);
 
         if(!whitelisted) {
-            logger.error("Bundle {} is NOT whitelisted to use SlingRepository.loginAdministrative", usingBundle.getSymbolicName());
-            throw new LoginException();
+            final String symbolicName = usingBundle.getSymbolicName();
+            logger.error("Bundle {} is NOT whitelisted to use SlingRepository.loginAdministrative", symbolicName);
+            throw new LoginException("Bundle " + symbolicName +" is NOT whitelisted");
         } else if (this.getSlingRepositoryManager().isDisableLoginAdministrative()) {
             logger.error("SlingRepository.loginAdministrative is disabled. Please use SlingRepository.loginService.");
-            throw new LoginException();
+            throw new LoginException("SlingRepository.loginAdministrative is disabled.");
         }
 
         logger.debug("SlingRepository.loginAdministrative is deprecated. Please use SlingRepository.loginService.");

Modified: sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepositoryManager.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepositoryManager.java?rev=1769962&r1=1769961&r2=1769962&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepositoryManager.java (original)
+++ sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/AbstractSlingRepositoryManager.java Wed Nov 16 11:56:46 2016
@@ -18,6 +18,7 @@
  */
 package org.apache.sling.jcr.base;
 
+import java.lang.reflect.Method;
 import java.util.Arrays;
 import java.util.Dictionary;
 
@@ -26,6 +27,7 @@ import javax.jcr.Repository;
 import org.apache.sling.jcr.api.SlingRepository;
 import org.apache.sling.jcr.api.SlingRepositoryInitializer;
 import org.apache.sling.jcr.base.internal.loader.Loader;
+import org.apache.sling.jcr.base.internal.LoginAdminWhitelist;
 import org.apache.sling.serviceusermapping.ServiceUserMapper;
 import org.osgi.annotation.versioning.ProviderType;
 import org.osgi.framework.Bundle;
@@ -101,6 +103,10 @@ public abstract class AbstractSlingRepos
 
     private volatile Loader loader;
 
+    private volatile ServiceReference<LoginAdminWhitelist> whitelistRef;
+
+    private volatile LoginAdminWhitelist whitelist;
+
     private final Object repoInitLock = new Object();
 
     /**
@@ -151,7 +157,9 @@ public abstract class AbstractSlingRepos
      * @return A boolean value indicating whether or not the bundle is allowed
      *         to use {@code loginAdministrative}.
      */
-    protected abstract boolean allowLoginAdministrativeForBundle(final Bundle bundle);
+    protected boolean allowLoginAdministrativeForBundle(final Bundle bundle) {
+        return whitelist.allowLoginAdministrative(bundle);
+    }
 
     /**
      * Creates the backing JCR repository instances. It is expected for this
@@ -322,6 +330,15 @@ public abstract class AbstractSlingRepos
         this.defaultWorkspace = defaultWorkspace;
         this.disableLoginAdministrative = disableLoginAdministrative;
 
+        boolean enableWhitelist = !isAllowLoginAdministrativeForBundleOverridden();
+        if (enableWhitelist) {
+            this.whitelistRef = bundleContext.getServiceReference(LoginAdminWhitelist.class);
+            if (whitelistRef == null) {
+                throw new IllegalStateException("Whitelist must not be null");
+            }
+            this.whitelist = bundleContext.getService(whitelistRef);
+        }
+
         this.repoInitializerTracker = new ServiceTracker<SlingRepositoryInitializer, SlingRepositoryInitializerInfo>(bundleContext, SlingRepositoryInitializer.class,
                 new ServiceTrackerCustomizer<SlingRepositoryInitializer, SlingRepositoryInitializerInfo>() {
 
@@ -407,6 +424,23 @@ public abstract class AbstractSlingRepos
         return false;
     }
 
+    // find out whether allowLoginAdministrativeForBundle is overridden
+    private boolean isAllowLoginAdministrativeForBundleOverridden() {
+        Class<?> clazz = getClass();
+        while (clazz != AbstractSlingRepositoryManager.class) {
+            final Method[] declaredMethods = clazz.getDeclaredMethods();
+            for (final Method method : declaredMethods) {
+                if (method.getName().equals("allowLoginAdministrativeForBundle")
+                        && method.getParameterTypes().length == 1
+                        && method.getParameterTypes()[0] == Bundle.class) {
+                    return true;
+                }
+            }
+            clazz = clazz.getSuperclass();
+        }
+        return false;
+    }
+
     private void executeRepositoryInitializers(final SlingRepository repo) throws Exception {
         final SlingRepositoryInitializerInfo [] infos = repoInitializerTracker.getServices(new SlingRepositoryInitializerInfo[0]);
         if (infos == null || infos.length == 0) {
@@ -424,6 +458,12 @@ public abstract class AbstractSlingRepos
      * This method must be called if overwritten by implementations !!
      */
     protected final void stop() {
+        if (whitelistRef != null) {
+            whitelist = null;
+            bundleContext.ungetService(whitelistRef);
+            whitelistRef = null;
+        }
+
         if(repoInitializerTracker != null) {
             repoInitializerTracker.close();
             repoInitializerTracker = null;

Copied: sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/internal/LoginAdminWhitelist.java (from r1769656, sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/internal/LoginAdminWhitelist.java)
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/internal/LoginAdminWhitelist.java?p2=sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/internal/LoginAdminWhitelist.java&p1=sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/internal/LoginAdminWhitelist.java&r1=1769656&r2=1769962&rev=1769962&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/internal/LoginAdminWhitelist.java (original)
+++ sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/internal/LoginAdminWhitelist.java Wed Nov 16 11:56:46 2016
@@ -16,10 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sling.jcr.oak.server.internal;
+package org.apache.sling.jcr.base.internal;
 
 import java.util.Arrays;
-import java.util.Set;
 import java.util.TreeSet;
 import java.util.regex.Pattern;
 
@@ -28,6 +27,7 @@ import org.osgi.framework.Bundle;
 import org.osgi.framework.Constants;
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Modified;
 import org.osgi.service.metatype.annotations.Designate;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -51,60 +51,70 @@ import org.slf4j.LoggerFactory;
 )
 public class LoginAdminWhitelist {
 
-    private final Logger log = LoggerFactory.getLogger(getClass());
+    private static final Logger LOG = LoggerFactory.getLogger(LoginAdminWhitelist.class);
 
-    private boolean bypassWhitelist;
+    private volatile ConfigurationState config;
 
-    private Pattern whitelistRegexp;
-
-    private Set<String> whitelistedBsn;
-
-    @Activate
-    void activate(LoginAdminWhitelistConfiguration config) {
-        whitelistedBsn = new TreeSet<String>();
-
-        if (config.whitelist_bundles_default() != null) {
-            whitelistedBsn.addAll(Arrays.asList(config.whitelist_bundles_default()));
-        }
-        if (config.whitelist_bundles_additional() != null) { // null check due to FELIX-5404
-            whitelistedBsn.addAll(Arrays.asList(config.whitelist_bundles_additional()));
-        }
-
-        final String regexp = config.whitelist_bundles_regexp();
-        if(regexp.trim().length() > 0) {
-            whitelistRegexp = Pattern.compile(regexp);
-            log.warn("A whitelist.bundles.regexp is configured, this is NOT RECOMMENDED for production: {}", whitelistRegexp);
-        } else {
-            whitelistRegexp = null;
-        }
-
-        bypassWhitelist = config.whitelist_bypass();
-        if(bypassWhitelist) {
-            log.info("bypassWhitelist=true, whitelisted BSNs=<ALL>");
-            log.warn(
-                "All bundles are allowed to use loginAdministrative due to the 'bypass whitelist' configuration"
-                + " of this service. This is NOT RECOMMENDED, for security reasons."
-            );
-        } else {
-            log.info("bypassWhitelist=false, whitelisted BSNs({})={}", whitelistedBsn.size(), whitelistedBsn);
-        }
+    @Activate @Modified
+    void configure(LoginAdminWhitelistConfiguration configuration) {
+        this.config = new ConfigurationState(configuration);
     }
 
-    boolean allowLoginAdministrative(Bundle b) {
-        if(bypassWhitelist) {
-            log.debug("Whitelist is bypassed, all bundles allowed to use loginAdministrative");
+    public boolean allowLoginAdministrative(Bundle b) {
+        if (config == null) {
+            throw new IllegalStateException("LoginAdminWhitelist has no configuration.");
+        }
+        // create local copy of ConfigurationState to avoid reading mixed configurations during an configure
+        final ConfigurationState localConfig = this.config;
+        if(localConfig.bypassWhitelist) {
+            LOG.debug("Whitelist is bypassed, all bundles allowed to use loginAdministrative");
             return true;
         }
 
         final String bsn = b.getSymbolicName();
-        if(whitelistRegexp != null && whitelistRegexp.matcher(bsn).matches()) {
-            log.debug("{} is whitelisted to use loginAdministrative, by regexp", bsn);
+        if(localConfig.whitelistRegexp != null && localConfig.whitelistRegexp.matcher(bsn).matches()) {
+            LOG.debug("{} is whitelisted to use loginAdministrative, by regexp", bsn);
             return true;
-        } else if(whitelistedBsn.contains(bsn)) {
-            log.debug("{} is whitelisted to use loginAdministrative, by explicit whitelist", bsn);
+        } else if(localConfig.whitelistedBsn.contains(bsn)) {
+            LOG.debug("{} is whitelisted to use loginAdministrative, by explicit whitelist", bsn);
             return true;
         }
-        log.debug("{} is not whitelisted to use loginAdministrative", bsn);
+        LOG.debug("{} is not whitelisted to use loginAdministrative", bsn);
         return false;
     }
+
+    // encapsulate configuration state for atomic configuration updates
+    private static class ConfigurationState {
+        private final TreeSet<String> whitelistedBsn;
+        private final Pattern whitelistRegexp;
+        private final boolean bypassWhitelist;
+
+        private ConfigurationState(final LoginAdminWhitelistConfiguration config) {
+            whitelistedBsn = new TreeSet<String>();
+            if (config.whitelist_bundles_default() != null) { // null check due to FELIX-5404
+                whitelistedBsn.addAll(Arrays.asList(config.whitelist_bundles_default()));
+            }
+            if (config.whitelist_bundles_additional() != null) {
+                whitelistedBsn.addAll(Arrays.asList(config.whitelist_bundles_additional()));
+            }
+
+            final String regexp = config.whitelist_bundles_regexp();
+            if(regexp.trim().length() > 0) {
+                whitelistRegexp = Pattern.compile(regexp);
+                LOG.warn("A whitelist.bundles.regexp is configured, this is NOT RECOMMENDED for production: {}", whitelistRegexp);
+            } else {
+                whitelistRegexp = null;
+            }
+
+            bypassWhitelist = config.whitelist_bypass();
+            if(bypassWhitelist) {
+                LOG.info("bypassWhitelist=true, whitelisted BSNs=<ALL>");
+                LOG.warn("All bundles are allowed to use loginAdministrative due to the 'bypass whitelist' " +
+                        "configuration of this service. This is NOT RECOMMENDED, for security reasons."
+                );
+            } else {
+                LOG.info("bypassWhitelist=false, whitelisted BSNs({})={}", whitelistedBsn.size(), whitelistedBsn);
+            }
+        }
+    }
 }

Copied: sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/internal/LoginAdminWhitelistConfiguration.java (from r1769656, sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/internal/LoginAdminWhitelistConfiguration.java)
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/internal/LoginAdminWhitelistConfiguration.java?p2=sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/internal/LoginAdminWhitelistConfiguration.java&p1=sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/internal/LoginAdminWhitelistConfiguration.java&r1=1769656&r2=1769962&rev=1769962&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/internal/LoginAdminWhitelistConfiguration.java (original)
+++ sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/internal/LoginAdminWhitelistConfiguration.java Wed Nov 16 11:56:46 2016
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sling.jcr.oak.server.internal;
+package org.apache.sling.jcr.base.internal;
 
 import org.osgi.service.metatype.annotations.AttributeDefinition;
 import org.osgi.service.metatype.annotations.ObjectClassDefinition;

Modified: sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/package-info.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/package-info.java?rev=1769962&r1=1769961&r2=1769962&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/package-info.java (original)
+++ sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/package-info.java Wed Nov 16 11:56:46 2016
@@ -25,7 +25,7 @@
  * {@link org.apache.sling.jcr.base.AbstractSlingRepository2} being the
  * basis for the repository service instance handed to using bundles.
  */
-@org.osgi.annotation.versioning.Version("3.1.0")
+@org.osgi.annotation.versioning.Version("3.2.0")
 package org.apache.sling.jcr.base;
 
 

Copied: sling/trunk/bundles/jcr/base/src/test/java/org/apache/sling/jcr/base/internal/LoginAdminWhitelistTest.java (from r1769656, sling/trunk/bundles/jcr/oak-server/src/test/java/org/apache/sling/jcr/oak/server/internal/LoginAdminWhitelistTest.java)
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/base/src/test/java/org/apache/sling/jcr/base/internal/LoginAdminWhitelistTest.java?p2=sling/trunk/bundles/jcr/base/src/test/java/org/apache/sling/jcr/base/internal/LoginAdminWhitelistTest.java&p1=sling/trunk/bundles/jcr/oak-server/src/test/java/org/apache/sling/jcr/oak/server/internal/LoginAdminWhitelistTest.java&r1=1769656&r2=1769962&rev=1769962&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/oak-server/src/test/java/org/apache/sling/jcr/oak/server/internal/LoginAdminWhitelistTest.java (original)
+++ sling/trunk/bundles/jcr/base/src/test/java/org/apache/sling/jcr/base/internal/LoginAdminWhitelistTest.java Wed Nov 16 11:56:46 2016
@@ -16,20 +16,22 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sling.jcr.oak.server.internal;
+package org.apache.sling.jcr.base.internal;
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.when;
 
-import java.lang.annotation.Annotation;
 import java.util.ArrayList;
+import java.util.Hashtable;
 import java.util.List;
 import java.util.UUID;
 
+import org.apache.sling.jcr.base.util.ConfigAnnotationUtil;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mockito;
 import org.osgi.framework.Bundle;
+import org.osgi.service.cm.ConfigurationException;
 
 public class LoginAdminWhitelistTest {
 
@@ -58,9 +60,9 @@ public class LoginAdminWhitelistTest {
     }
  
     @Test
-    public void testDefaultConfig() {
+    public void testDefaultConfig() throws ConfigurationException {
         final LoginAdminWhitelistConfiguration config = config(null, null, null, null);
-        whitelist.activate(config);
+        whitelist.configure(config);
 
         for(String bsn : config.whitelist_bundles_default()) {
             assertAdminLogin(bsn, true);
@@ -74,8 +76,8 @@ public class LoginAdminWhitelistTest {
     }
 
     @Test
-    public void testBypassWhitelist() {
-        whitelist.activate(config(true, null, null, null));
+    public void testBypassWhitelist() throws ConfigurationException {
+        whitelist.configure(config(true, null, null, null));
         
         for(String bsn : randomBsn()) {
             assertAdminLogin(bsn, true);
@@ -83,11 +85,11 @@ public class LoginAdminWhitelistTest {
     }
     
     @Test
-    public void testDefaultConfigOnly() {
+    public void testDefaultConfigOnly() throws ConfigurationException {
         final String [] allowed = {
                 "bundle1", "bundle2"
         };
-        whitelist.activate(config(null, null, allowed, null));
+        whitelist.configure(config(null, null, allowed, null));
         
         assertAdminLogin("bundle1", true);
         assertAdminLogin("bundle2", true);
@@ -100,18 +102,18 @@ public class LoginAdminWhitelistTest {
     }
     
     @Test
-    public void testAdditionalConfigOnly() {
+    public void testAdditionalConfigOnly() throws ConfigurationException {
         final String [] allowed = {
                 "bundle5", "bundle6"
         };
         final LoginAdminWhitelistConfiguration config = config(null, null, null, allowed);
-        whitelist.activate(config);
+        whitelist.configure(config);
         
         assertAdminLogin("bundle5", true);
         assertAdminLogin("bundle6", true);
         assertAdminLogin("foo.1.bar", false);
         assertAdminLogin(TYPICAL_DEFAULT_ALLOWED_BSN, true);
-        
+
         for(String bsn : config.whitelist_bundles_default()) {
             assertAdminLogin(bsn, true);
         }
@@ -122,8 +124,8 @@ public class LoginAdminWhitelistTest {
     }
     
     @Test
-    public void testDefaultAndAdditionalConfig() {
-        whitelist.activate(config(null, null, new String [] { "defB"}, new String [] { "addB"}));
+    public void testDefaultAndAdditionalConfig() throws ConfigurationException {
+        whitelist.configure(config(null, null, new String [] { "defB"}, new String [] { "addB"}));
         
         assertAdminLogin("defB", true);
         assertAdminLogin("addB", true);
@@ -136,11 +138,11 @@ public class LoginAdminWhitelistTest {
     }
     
     @Test
-    public void testRegexpWhitelist() {
+    public void testRegexpWhitelist() throws ConfigurationException {
         final String [] allowed = {
                 "bundle3", "bundle4"
         };
-        whitelist.activate(config(null, "foo.*bar", allowed, null));
+        whitelist.configure(config(null, "foo.*bar", allowed, null));
         
         assertAdminLogin("bundle3", true);
         assertAdminLogin("bundle4", true);
@@ -153,44 +155,20 @@ public class LoginAdminWhitelistTest {
         }
     }
 
-
-    private LoginAdminWhitelistConfiguration config(final Boolean bypass, final String regexp, final String[] defaultBSNs, final String[] additionalBSNs) {
-        return new LoginAdminWhitelistConfiguration() {
-            @Override
-            public boolean whitelist_bypass() {
-                return defaultIfNull(bypass, "whitelist_bypass");
-            }
-
-            @Override
-            public String whitelist_bundles_regexp() {
-                return defaultIfNull(regexp, "whitelist_bundles_regexp");
-            }
-
-            @Override
-            public String[] whitelist_bundles_default() {
-                return defaultIfNull(defaultBSNs, "whitelist_bundles_default");
-            }
-
-            @Override
-            public String[] whitelist_bundles_additional() {
-                return defaultIfNull(additionalBSNs, "whitelist_bundles_additional");
-            }
-
-            @Override
-            public Class<? extends Annotation> annotationType() {
-                return LoginAdminWhitelistConfiguration.class;
-            }
-
-            private <T> T defaultIfNull(final T value, final String methodName) {
-                if (value != null) {
-                    return value;
-                }
-                try {
-                    return (T)this.annotationType().getMethod(methodName).getDefaultValue();
-                } catch (NoSuchMethodException e) {
-                    return null;
-                }
-            }
-        };
+    private LoginAdminWhitelistConfiguration config(final Boolean bypass, final String regexp, final String[] defaultBSNs, final String[] additionalBSNs) throws ConfigurationException {
+        final Hashtable<String, Object> props = new Hashtable<>();
+        if (bypass != null) {
+            props.put("whitelist.bypass", bypass);
+        }
+        if (regexp != null) {
+            props.put("whitelist.bundles.regexp", regexp);
+        }
+        if (defaultBSNs != null) {
+            props.put("whitelist.bundles.default", defaultBSNs);
+        }
+        if (additionalBSNs != null) {
+            props.put("whitelist.bundles.additional", additionalBSNs);
+        }
+        return ConfigAnnotationUtil.fromDictionary(LoginAdminWhitelistConfiguration.class, props);
     }
 }
\ No newline at end of file

Added: sling/trunk/bundles/jcr/base/src/test/java/org/apache/sling/jcr/base/util/ConfigAnnotationUtil.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/base/src/test/java/org/apache/sling/jcr/base/util/ConfigAnnotationUtil.java?rev=1769962&view=auto
==============================================================================
--- sling/trunk/bundles/jcr/base/src/test/java/org/apache/sling/jcr/base/util/ConfigAnnotationUtil.java (added)
+++ sling/trunk/bundles/jcr/base/src/test/java/org/apache/sling/jcr/base/util/ConfigAnnotationUtil.java Wed Nov 16 11:56:46 2016
@@ -0,0 +1,146 @@
+/*
+ * 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.sling.jcr.base.util;
+
+import org.osgi.service.cm.ConfigurationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+public class ConfigAnnotationUtil {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ConfigAnnotationUtil.class);
+
+    @SuppressWarnings("unchecked")
+    public static <T> T fromDictionary(final Class<T> clazz, final Dictionary<String, ?> properties)
+            throws ConfigurationException {
+        return (T)Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{ clazz },
+                new Handler(copyAndVerify(properties, clazz)));
+    }
+
+    private static class Handler implements InvocationHandler {
+
+        private Dictionary<String, ?> properties;
+
+        private Handler(final Dictionary<String, ?> properties) {
+            this.properties = properties;
+        }
+
+        @Override
+        public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
+            final String methodName = method.getName();
+            if ("toString".equals(methodName)) {
+                return proxy.getClass().getName() + "[" + properties.toString() + "]";
+            }
+
+            final String propertyName = toPropertyName(methodName);
+            Object value;
+            if (properties != null && (value = properties.get(propertyName)) != null) {
+                return value;
+            } else {
+                return method.getDefaultValue();
+            }
+        }
+    }
+
+    private static String toPropertyName(final String methodName) {
+        return methodName.replace('_', '.');
+    }
+
+    private static String toMethodName(final String propertyName) {
+        return propertyName.replace('.', '_');
+    }
+
+    private static <T> Dictionary<String, ?> copyAndVerify(final Dictionary<String, ?> properties, final Class<T> clazz)
+            throws ConfigurationException {
+        if (properties == null) {
+            return null;
+        }
+
+        final Hashtable<String, Object> copy = new Hashtable<>();
+        final Enumeration<String> keys = properties.keys();
+        while (keys.hasMoreElements()) {
+            final String propertyName = keys.nextElement();
+            final Object value = properties.get(propertyName);
+            verifyValueType(clazz, propertyName, value);
+            copy.put(propertyName, value);
+        }
+        return copy;
+    }
+
+    private static <T> void verifyValueType(final Class<T> clazz, final String propertyName, final Object value)
+            throws ConfigurationException {
+        final Method method = getDeclaredMethodByName(clazz, toMethodName(propertyName));
+        if (method != null) {
+            final Class<?> returnType = method.getReturnType();
+            final Class<?> valueClass = value.getClass();
+            if (!isAssignable(returnType, valueClass)) {
+                LOG.error("Invalid value type for {} ({} instead of {})", propertyName, valueClass, returnType);
+                throw new ConfigurationException(propertyName,
+                        "Value of incorrect type " + valueClass.getName() + " instead of " + returnType.getName());
+            }
+        }
+    }
+
+    private static boolean isAssignable(final Class<?> type, final Class<?> superType) {
+        final Class<?> wrappedType = primitiveToWrapper(type);
+        final Class<?> wrappedSuperType = primitiveToWrapper(superType);
+        return wrappedType.isAssignableFrom(wrappedSuperType);
+    }
+
+    private static Method getDeclaredMethodByName(final Class<?> clazz, final String methodName) {
+        final Method[] declaredMethods = clazz.getDeclaredMethods();
+        Method method = null;
+        for (final Method declaredMethod : declaredMethods) {
+            if (declaredMethod.getName().equals(methodName)) {
+                method = declaredMethod;
+                break;
+            }
+        }
+        return method;
+    }
+
+    private static Class<?> primitiveToWrapper(Class<?> clazz) {
+        if (primitiveToWrapper.containsKey(clazz)) {
+            return primitiveToWrapper.get(clazz);
+        } else {
+            return clazz;
+        }
+    }
+
+    private static final Map<Class<?>, Class<?>> primitiveToWrapper = new HashMap<Class<?>, Class<?>>();
+    static {
+        primitiveToWrapper.put(Boolean.TYPE, Boolean.class);
+        primitiveToWrapper.put(Byte.TYPE, Byte.class);
+        primitiveToWrapper.put(Character.TYPE, Character.class);
+        primitiveToWrapper.put(Short.TYPE, Short.class);
+        primitiveToWrapper.put(Integer.TYPE, Integer.class);
+        primitiveToWrapper.put(Long.TYPE, Long.class);
+        primitiveToWrapper.put(Double.TYPE, Double.class);
+        primitiveToWrapper.put(Float.TYPE, Float.class);
+    }
+}

Propchange: sling/trunk/bundles/jcr/base/src/test/java/org/apache/sling/jcr/base/util/ConfigAnnotationUtil.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: sling/trunk/bundles/jcr/oak-server/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/oak-server/pom.xml?rev=1769962&r1=1769961&r2=1769962&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/oak-server/pom.xml (original)
+++ sling/trunk/bundles/jcr/oak-server/pom.xml Wed Nov 16 11:56:46 2016
@@ -177,7 +177,7 @@
     <dependency>
       <groupId>org.apache.sling</groupId>
       <artifactId>org.apache.sling.jcr.base</artifactId>
-      <version>2.4.2</version>
+      <version>2.4.3-SNAPSHOT</version>
       <scope>provided</scope>
     </dependency>
     <dependency>

Modified: sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/internal/OakSlingRepositoryManager.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/internal/OakSlingRepositoryManager.java?rev=1769962&r1=1769961&r2=1769962&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/internal/OakSlingRepositoryManager.java (original)
+++ sling/trunk/bundles/jcr/oak-server/src/main/java/org/apache/sling/jcr/oak/server/internal/OakSlingRepositoryManager.java Wed Nov 16 11:56:46 2016
@@ -99,9 +99,6 @@ public class OakSlingRepositoryManager e
     @Reference
     private ThreadPoolManager threadPoolManager = null;
 
-    @Reference
-    private LoginAdminWhitelist loginAdminWhitelist;
-
     private ThreadPool threadPool;
 
     private ServiceRegistration oakExecutorServiceReference;
@@ -122,9 +119,6 @@ public class OakSlingRepositoryManager e
 
     private ServiceRegistration nodeAggregatorRegistration;
 
-    public OakSlingRepositoryManager() {
-    }
-
     @Override
     protected ServiceUserMapper getServiceUserMapper() {
         return this.serviceUserMapper;
@@ -203,11 +197,6 @@ public class OakSlingRepositoryManager e
         ((JackrabbitRepository) repository).shutdown();
     }
 
-    @Override
-    protected boolean allowLoginAdministrativeForBundle(final Bundle bundle) {
-        return loginAdminWhitelist.allowLoginAdministrative(bundle);
-    }
-
     @Activate
     private void activate(final OakSlingRepositoryManagerConfiguration configuration, final ComponentContext componentContext) {
         this.configuration = configuration;

Modified: sling/trunk/bundles/jcr/oak-server/src/test/java/org/apache/sling/jcr/oak/server/it/OakServerTestSupport.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/oak-server/src/test/java/org/apache/sling/jcr/oak/server/it/OakServerTestSupport.java?rev=1769962&r1=1769961&r2=1769962&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/oak-server/src/test/java/org/apache/sling/jcr/oak/server/it/OakServerTestSupport.java (original)
+++ sling/trunk/bundles/jcr/oak-server/src/test/java/org/apache/sling/jcr/oak/server/it/OakServerTestSupport.java Wed Nov 16 11:56:46 2016
@@ -202,7 +202,7 @@ public abstract class OakServerTestSuppo
     }
 
     protected Option getWhitelistRegexpOption() {
-        return newConfiguration("org.apache.sling.jcr.oak.server.internal.LoginAdminWhitelist")
+        return newConfiguration("org.apache.sling.jcr.base.internal.LoginAdminWhitelist")
             .put("whitelist.bundles.regexp", "PAXEXAM-PROBE-.*")
             .asOption();
     }