You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by an...@apache.org on 2014/06/12 16:46:53 UTC

svn commit: r1602183 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/security/authentication/token/ main/java/org/apache/jackrabbit/oak/security/authorization/ main/java/org/apache/jackrabbit/oak/security/authorization/perm...

Author: angela
Date: Thu Jun 12 14:46:53 2014
New Revision: 1602183

URL: http://svn.apache.org/r1602183
Log:
OAK-1887 : Expose security related configuration options as component properties

Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenConfigurationImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AuthorizationConfigurationImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/ConfigurationParameters.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/ConfigurationParametersTest.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenConfigurationImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenConfigurationImpl.java?rev=1602183&r1=1602182&r2=1602183&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenConfigurationImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenConfigurationImpl.java Thu Jun 12 14:46:53 2014
@@ -17,11 +17,12 @@
 package org.apache.jackrabbit.oak.security.authentication.token;
 
 import java.util.Map;
-
 import javax.annotation.Nonnull;
 
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Service;
 import org.apache.jackrabbit.oak.api.Root;
 import org.apache.jackrabbit.oak.spi.security.ConfigurationBase;
@@ -31,12 +32,34 @@ import org.apache.jackrabbit.oak.spi.sec
 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.user.UserConfiguration;
+import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
+import org.apache.jackrabbit.oak.spi.security.user.util.PasswordUtil;
 
 /**
  * Default implementation for the {@code TokenConfiguration} interface.
  */
-@Component()
+@Component(metatype = true, label = "Apache Jackrabbit Oak TokenConfiguration")
 @Service({TokenConfiguration.class, SecurityConfiguration.class})
+@Properties({
+        @Property(name = TokenProvider.PARAM_TOKEN_EXPIRATION,
+                label = "Token Expiration",
+                description = "Expiration time of login tokens in ms."),
+        @Property(name = TokenProvider.PARAM_TOKEN_LENGTH,
+                label = "Token Length",
+                description = "Length of the generated token."),
+        @Property(name = UserConstants.PARAM_PASSWORD_HASH_ALGORITHM,
+                label = "Hash Algorithm",
+                description = "Name of the algorithm to hash the token.",
+                value = PasswordUtil.DEFAULT_ALGORITHM),
+        @Property(name = UserConstants.PARAM_PASSWORD_HASH_ITERATIONS,
+                label = "Hash Iterations",
+                description = "Number of iterations used to hash the token.",
+                intValue = PasswordUtil.DEFAULT_ITERATIONS),
+        @Property(name = UserConstants.PARAM_PASSWORD_SALT_SIZE,
+                label = "Hash Salt Size",
+                description = "Size of the salt used to generate the hash.",
+                intValue = PasswordUtil.DEFAULT_SALT_SIZE)
+})
 public class TokenConfigurationImpl extends ConfigurationBase implements TokenConfiguration {
 
     public TokenConfigurationImpl() {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AuthorizationConfigurationImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AuthorizationConfigurationImpl.java?rev=1602183&r1=1602182&r2=1602183&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AuthorizationConfigurationImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AuthorizationConfigurationImpl.java Thu Jun 12 14:46:53 2014
@@ -21,20 +21,24 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-
 import javax.annotation.Nonnull;
 import javax.jcr.security.AccessControlManager;
 
+import com.google.common.collect.ImmutableList;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.PropertyOption;
 import org.apache.felix.scr.annotations.Service;
 import org.apache.jackrabbit.oak.api.Root;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.plugins.name.NamespaceConstants;
+import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
 import org.apache.jackrabbit.oak.plugins.version.VersionablePathHook;
 import org.apache.jackrabbit.oak.security.authorization.accesscontrol.AccessControlImporter;
 import org.apache.jackrabbit.oak.security.authorization.accesscontrol.AccessControlManagerImpl;
 import org.apache.jackrabbit.oak.security.authorization.accesscontrol.AccessControlValidatorProvider;
-import org.apache.jackrabbit.oak.security.authorization.permission.PermissionEntryCache;
 import org.apache.jackrabbit.oak.security.authorization.permission.PermissionHook;
 import org.apache.jackrabbit.oak.security.authorization.permission.PermissionProviderImpl;
 import org.apache.jackrabbit.oak.security.authorization.permission.PermissionStoreValidatorProvider;
@@ -51,19 +55,49 @@ import org.apache.jackrabbit.oak.spi.sec
 import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
 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.permission.PermissionConstants;
 import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider;
 import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
+import org.apache.jackrabbit.oak.spi.xml.ImportBehavior;
 import org.apache.jackrabbit.oak.spi.xml.ProtectedItemImporter;
 
-import com.google.common.collect.ImmutableList;
-
 /**
  * Default implementation of the {@code AccessControlConfiguration}.
  */
-@Component()
+@Component(metatype = true, label = "Apache Jackrabbit Oak AuthorizationConfiguration")
 @Service({AuthorizationConfiguration.class, SecurityConfiguration.class})
+@Properties({
+        @Property(name = PermissionConstants.PARAM_PERMISSIONS_JR2,
+                label = "Jackrabbit 2.x Permissions",
+                description = "Enforce backwards compatible permission validation with respect to the configurable options.",
+                cardinality = 2,
+                options = {
+                        @PropertyOption(name = "USER_MANAGEMENT", value = "USER_MANAGEMENT"),
+                        @PropertyOption(name = "REMOVE_NODE", value = "REMOVE_NODE")
+                }),
+        @Property(name = ProtectedItemImporter.PARAM_IMPORT_BEHAVIOR,
+                label = "Import Behavior",
+                description = "Behavior for access control related items upon XML import.",
+                options = {
+                        @PropertyOption(name = ImportBehavior.NAME_ABORT, value = ImportBehavior.NAME_ABORT),
+                        @PropertyOption(name = ImportBehavior.NAME_BESTEFFORT, value = ImportBehavior.NAME_BESTEFFORT),
+                        @PropertyOption(name = ImportBehavior.NAME_IGNORE, value = ImportBehavior.NAME_IGNORE)
+                },
+                value = ImportBehavior.NAME_ABORT),
+        @Property(name = PermissionConstants.PARAM_READ_PATHS,
+                label = "Readable Paths",
+                description = "Enable full read access to regular nodes and properties at the specified paths irrespective of other policies that may take effective.",
+                value = {
+                NamespaceConstants.NAMESPACES_PATH,
+                NodeTypeConstants.NODE_TYPES_PATH,
+                PrivilegeConstants.PRIVILEGES_PATH }),
+        @Property(name = PermissionConstants.PARAM_ADMINISTRATIVE_PRINCIPALS,
+                label = "Administrative Principals",
+                description = "Allows to specify principals that should be granted full permissions on the complete repository content.",
+                cardinality = 10)
+})
 public class AuthorizationConfigurationImpl extends ConfigurationBase implements AuthorizationConfiguration {
-
     public AuthorizationConfigurationImpl() {
         super();
     }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java?rev=1602183&r1=1602182&r2=1602183&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java Thu Jun 12 14:46:53 2014
@@ -17,17 +17,18 @@
 package org.apache.jackrabbit.oak.security.authorization.permission;
 
 import java.security.Principal;
+import java.util.Collections;
 import java.util.Set;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import com.google.common.collect.ImmutableSet;
 import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Root;
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.core.ImmutableRoot;
 import org.apache.jackrabbit.oak.plugins.tree.ImmutableTree;
+import org.apache.jackrabbit.oak.plugins.tree.TreeLocation;
 import org.apache.jackrabbit.oak.plugins.version.VersionConstants;
 import org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration;
 import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
@@ -38,7 +39,6 @@ import org.apache.jackrabbit.oak.spi.sec
 import org.apache.jackrabbit.oak.spi.security.authorization.permission.TreePermission;
 import org.apache.jackrabbit.oak.spi.security.principal.AdminPrincipal;
 import org.apache.jackrabbit.oak.spi.security.principal.SystemPrincipal;
-import org.apache.jackrabbit.oak.plugins.tree.TreeLocation;
 
 public class PermissionProviderImpl implements PermissionProvider, AccessControlConstants, PermissionConstants {
 
@@ -119,7 +119,7 @@ public class PermissionProviderImpl impl
     //--------------------------------------------------------------------------
 
     private boolean isAdmin(Set<Principal> principals) {
-        Set<String> adminNames = ImmutableSet.copyOf(acConfig.getParameters().getConfigValue(PARAM_ADMINISTRATIVE_PRINCIPALS, new String[0]));
+        Set<String> adminNames = acConfig.getParameters().getConfigValue(PARAM_ADMINISTRATIVE_PRINCIPALS, Collections.EMPTY_SET);
         for (Principal principal : principals) {
             if (principal instanceof AdminPrincipal || adminNames.contains(principal.getName())) {
                 return true;

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImpl.java?rev=1602183&r1=1602182&r2=1602183&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImpl.java Thu Jun 12 14:46:53 2014
@@ -26,6 +26,9 @@ import javax.annotation.Nonnull;
 
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.PropertyOption;
 import org.apache.felix.scr.annotations.Service;
 import org.apache.jackrabbit.api.security.user.UserManager;
 import org.apache.jackrabbit.oak.api.Root;
@@ -41,13 +44,54 @@ import org.apache.jackrabbit.oak.spi.sec
 import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
 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.util.PasswordUtil;
+import org.apache.jackrabbit.oak.spi.xml.ImportBehavior;
 import org.apache.jackrabbit.oak.spi.xml.ProtectedItemImporter;
 
 /**
  * Default implementation of the {@link UserConfiguration}.
  */
-@Component()
+@Component(metatype = true, label = "Apache Jackrabbit Oak UserConfiguration")
 @Service({UserConfiguration.class, SecurityConfiguration.class})
+@Properties({
+        @Property(name = UserConstants.PARAM_USER_PATH,
+                label = "User Path",
+                description = "Path underneath which user nodes are being created.",
+                value = UserConstants.DEFAULT_USER_PATH),
+        @Property(name = UserConstants.PARAM_GROUP_PATH,
+                label = "Group Path",
+                description = "Path underneath which group nodes are being created.",
+                value = UserConstants.DEFAULT_GROUP_PATH),
+        @Property(name = UserConstants.PARAM_DEFAULT_DEPTH,
+                label = "Default Depth",
+                description = "Number of levels that are used by default to store authorizable nodes",
+                intValue = UserConstants.DEFAULT_DEPTH),
+        @Property(name = ProtectedItemImporter.PARAM_IMPORT_BEHAVIOR,
+                label = "Import Behavior",
+                description = "Behavior for user/group related items upon XML import.",
+                options = {
+                        @PropertyOption(name = ImportBehavior.NAME_ABORT, value = ImportBehavior.NAME_ABORT),
+                        @PropertyOption(name = ImportBehavior.NAME_BESTEFFORT, value = ImportBehavior.NAME_BESTEFFORT),
+                        @PropertyOption(name = ImportBehavior.NAME_IGNORE, value = ImportBehavior.NAME_IGNORE)
+                },
+                value = ImportBehavior.NAME_IGNORE),
+        @Property(name = UserConstants.PARAM_PASSWORD_HASH_ALGORITHM,
+                label = "Hash Algorithm",
+                description = "Name of the algorithm used to generate the password hash.",
+                value = PasswordUtil.DEFAULT_ALGORITHM),
+        @Property(name = UserConstants.PARAM_PASSWORD_HASH_ITERATIONS,
+                label = "Hash Iterations",
+                description = "Number of iterations to generate the password hash.",
+                intValue = PasswordUtil.DEFAULT_ITERATIONS),
+        @Property(name = UserConstants.PARAM_PASSWORD_SALT_SIZE,
+                label = "Hash Salt Size",
+                description = "Salt size to generate the password hash.",
+                intValue = PasswordUtil.DEFAULT_SALT_SIZE),
+        @Property(name = UserConstants.PARAM_SUPPORT_AUTOSAVE,
+                label = "Autosave Support",
+                description = "Configuration option to enable autosave behavior. Note: this config option is present for backwards compatibility with Jackrabbit 2.x and should only be used for broken code that doesn't properly verify the autosave behavior (see Jackrabbit API). If this option is turned on autosave will be enabled by default; otherwise autosave is not supported.",
+                boolValue = false)
+})
 public class UserConfigurationImpl extends ConfigurationBase implements UserConfiguration, SecurityConfiguration {
 
     public UserConfigurationImpl() {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/ConfigurationParameters.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/ConfigurationParameters.java?rev=1602183&r1=1602182&r2=1602183&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/ConfigurationParameters.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/ConfigurationParameters.java Thu Jun 12 14:46:53 2014
@@ -26,11 +26,11 @@ import java.util.Properties;
 import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-
 import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import com.google.common.collect.ImmutableSet;
 import org.apache.jackrabbit.oak.commons.PropertiesUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -249,6 +249,22 @@ public final class ConfigurationParamete
                 return (T) Boolean.valueOf(str);
             } else if (clazz == String[].class){
                 return (T) PropertiesUtil.toStringArray(configProperty, (String[]) defaultValue);
+            } else if (clazz == Set.class || Set.class.isAssignableFrom(clazz)) {
+                if (configProperty instanceof Set) {
+                    return (T) configProperty;
+                } else if (configProperty instanceof Collection) {
+                    return (T) ImmutableSet.copyOf((Collection) configProperty);
+                } else if (configProperty.getClass().isArray()) {
+                    return (T) ImmutableSet.copyOf((Object[]) configProperty);
+                } else {
+                    String[] arr = PropertiesUtil.toStringArray(configProperty);
+                    if (arr != null) {
+                        return (T) ImmutableSet.copyOf(arr);
+                    } else {
+                        log.warn("Unsupported target type {} for value {}", clazz.getName(), str);
+                        throw new IllegalArgumentException("Cannot convert config entry " + str + " to " + clazz.getName());
+                    }
+                }
             } else {
                 // unsupported target type
                 log.warn("Unsupported target type {} for value {}", clazz.getName(), str);

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/ConfigurationParametersTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/ConfigurationParametersTest.java?rev=1602183&r1=1602182&r2=1602183&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/ConfigurationParametersTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/ConfigurationParametersTest.java Thu Jun 12 14:46:53 2014
@@ -16,12 +16,16 @@
  */
 package org.apache.jackrabbit.oak.spi.security;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 
+import com.google.common.collect.ImmutableSet;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -266,6 +270,122 @@ public class ConfigurationParametersTest
     }
 
     @Test
+    public void testConversionToSet() {
+        String[] stringArray = new String[] {"a", "b"};
+        Set<String> stringSet = ImmutableSet.copyOf(stringArray);
+
+        TestObject[] testObjectArray = new TestObject[] {new TestObject("a"), new TestObject("b")};
+        Set<TestObject> testObjectSet = ImmutableSet.copyOf(testObjectArray);
+
+        // map of config value (key) and expected result set.
+        Map<Object, Set> configValues = new HashMap<Object, Set>();
+        configValues.put("a", ImmutableSet.of("a"));
+        configValues.put(stringArray, stringSet);
+        configValues.put(stringSet, stringSet);
+        configValues.put(testObjectArray, testObjectSet);
+        configValues.put(testObjectSet, testObjectSet);
+        configValues.put(new String[0], Collections.<String>emptySet());
+        configValues.put(new HashSet(), Collections.emptySet());
+        configValues.put(ImmutableSet.of(), Collections.emptySet());
+        configValues.put(new ArrayList(), Collections.emptySet());
+        configValues.put(ConfigurationParameters.EMPTY, Collections.<String>emptySet());
+
+        Set<String> defaultStrings = ImmutableSet.of("abc", "def", "ghi");
+        Set<TestObject> defaultObjects = ImmutableSet.of(new TestObject("abc"), new TestObject("def"));
+
+        for (Object value : configValues.keySet()) {
+            ConfigurationParameters config;
+            if (value instanceof ConfigurationParameters) {
+                config = ConfigurationParameters.of((ConfigurationParameters) value);
+            } else {
+                config = ConfigurationParameters.of(Collections.singletonMap("key", value));
+            }
+
+            Set expected = configValues.get(value);
+            assertEquals(expected, config.getConfigValue("key", Collections.emptySet()));
+            assertEquals(expected, config.getConfigValue("key", Collections.<String>emptySet()));
+            assertEquals(expected, config.getConfigValue("key", ImmutableSet.of()));
+
+            assertEquals(expected, config.getConfigValue("key", Collections.emptySet(), Set.class));
+            assertEquals(expected, config.getConfigValue("key", Collections.<String>emptySet(), Set.class));
+            assertEquals(expected, config.getConfigValue("key", ImmutableSet.of(), Set.class));
+
+            // test with default values
+            if (!config.containsKey("key")) {
+                assertEquals(defaultStrings, config.getConfigValue("key", defaultStrings, Set.class));
+                assertEquals(defaultObjects, config.getConfigValue("key", defaultObjects, Set.class));
+                assertEquals(null, config.getConfigValue("key", null, Set.class));
+                assertEquals(defaultStrings, config.getConfigValue("key", defaultStrings));
+                assertEquals(defaultObjects, config.getConfigValue("key", defaultObjects));
+            } else {
+                assertEquals(expected, config.getConfigValue("key", defaultStrings, Set.class));
+                assertEquals(expected, config.getConfigValue("key", defaultObjects, Set.class));
+                assertEquals(expected, config.getConfigValue("key", null, Set.class));
+                assertEquals(expected, config.getConfigValue("key", defaultStrings));
+                assertEquals(expected, config.getConfigValue("key", defaultObjects));
+            }
+
+            // non existing kez with default values
+            assertEquals(defaultStrings, config.getConfigValue("nonexisting", defaultStrings));
+            assertEquals(defaultStrings, config.getConfigValue("nonexisting", defaultStrings, Set.class));
+            assertEquals(defaultObjects, config.getConfigValue("nonexisting", defaultObjects));
+            assertEquals(defaultObjects, config.getConfigValue("nonexisting", defaultObjects, Set.class));
+        }
+    }
+
+    @Test
+    public void testConversionToStringArray() {
+        String[] stringArray = new String[] {"a", "b"};
+        Set<String> stringSet = ImmutableSet.copyOf(stringArray);
+
+        TestObject[] testObjectArray = new TestObject[] {new TestObject("a"), new TestObject("b")};
+        Set<TestObject> testObjectSet = ImmutableSet.copyOf(testObjectArray);
+
+        String[] defaultStrings = new String[]{"abc", "def", "ghi"};
+
+        // map of config value (key) and expected result set.
+        Map<Object, Object[]> configValues = new HashMap<Object, Object[]>();
+        configValues.put("a", new String[] {"a"});
+        configValues.put(stringArray, stringArray);
+        configValues.put(stringSet, stringArray);
+        configValues.put(testObjectArray, stringArray);
+        configValues.put(testObjectSet, stringArray);
+        configValues.put(new String[0], new String[0]);
+        configValues.put(new HashSet(), new String[0]);
+        configValues.put(ImmutableSet.of(), new String[0]);
+        configValues.put(new ArrayList(), new String[0]);
+        configValues.put(ConfigurationParameters.EMPTY, new String[0]);
+
+        for (Object value : configValues.keySet()) {
+            ConfigurationParameters config;
+            if (value instanceof ConfigurationParameters) {
+                config = ConfigurationParameters.of((ConfigurationParameters) value);
+            } else {
+                config = ConfigurationParameters.of(Collections.singletonMap("key", value));
+            }
+            Object[] expected = configValues.get(value);
+
+            assertArrayEquals(expected, config.getConfigValue("key", new String[0]));
+            assertArrayEquals(expected, config.getConfigValue("key", new String[0], String[].class));
+
+            // test with default values
+            if (!config.containsKey("key")) {
+                assertArrayEquals(defaultStrings, config.getConfigValue("key", defaultStrings, String[].class));
+                assertArrayEquals(null, config.getConfigValue("key", null, String[].class));
+                assertArrayEquals(defaultStrings, config.getConfigValue("key", defaultStrings));
+            } else {
+                assertArrayEquals(expected, config.getConfigValue("key", defaultStrings, String[].class));
+                assertArrayEquals(expected, config.getConfigValue("key", null, String[].class));
+                assertArrayEquals(expected, config.getConfigValue("key", defaultStrings));
+            }
+
+            // non existing kez with default values
+            assertArrayEquals(defaultStrings, config.getConfigValue("nonexisting", defaultStrings));
+            assertArrayEquals(defaultStrings, config.getConfigValue("nonexisting", defaultStrings, String[].class));
+        }
+    }
+
+    @Test
     public void testNullValue() {
         ConfigurationParameters options = ConfigurationParameters.of(Collections.singletonMap("test", null));
 
@@ -288,6 +408,24 @@ public class ConfigurationParametersTest
         assertNull(options.getConfigValue("test", false, null));
     }
 
+    @Test
+    public void testDurationParser() {
+        assertNull(ConfigurationParameters.Milliseconds.of(""));
+        assertNull(ConfigurationParameters.Milliseconds.of(null));
+        assertEquals(1, ConfigurationParameters.Milliseconds.of("1").value);
+        assertEquals(1, ConfigurationParameters.Milliseconds.of("1ms").value);
+        assertEquals(1, ConfigurationParameters.Milliseconds.of("  1ms").value);
+        assertEquals(1, ConfigurationParameters.Milliseconds.of("  1ms   ").value);
+        assertEquals(1, ConfigurationParameters.Milliseconds.of("  1ms  foobar").value);
+        assertEquals(1000, ConfigurationParameters.Milliseconds.of("1s").value);
+        assertEquals(1500, ConfigurationParameters.Milliseconds.of("1.5s").value);
+        assertEquals(1500, ConfigurationParameters.Milliseconds.of("1s 500ms").value);
+        assertEquals(60 * 1000, ConfigurationParameters.Milliseconds.of("1m").value);
+        assertEquals(90 * 1000, ConfigurationParameters.Milliseconds.of("1m30s").value);
+        assertEquals(60 * 60 * 1000 + 90 * 1000, ConfigurationParameters.Milliseconds.of("1h1m30s").value);
+        assertEquals(36 * 60 * 60 * 1000 + 60 * 60 * 1000 + 90 * 1000, ConfigurationParameters.Milliseconds.of("1.5d1h1m30s").value);
+    }
+
     private class TestObject {
 
         private final String name;
@@ -308,22 +446,4 @@ public class ConfigurationParametersTest
             return object == this || object instanceof TestObject && name.equals(((TestObject) object).name);
         }
     }
-
-    @Test
-    public void testDurationParser() {
-        assertNull(ConfigurationParameters.Milliseconds.of(""));
-        assertNull(ConfigurationParameters.Milliseconds.of(null));
-        assertEquals(1, ConfigurationParameters.Milliseconds.of("1").value);
-        assertEquals(1, ConfigurationParameters.Milliseconds.of("1ms").value);
-        assertEquals(1, ConfigurationParameters.Milliseconds.of("  1ms").value);
-        assertEquals(1, ConfigurationParameters.Milliseconds.of("  1ms   ").value);
-        assertEquals(1, ConfigurationParameters.Milliseconds.of("  1ms  foobar").value);
-        assertEquals(1000, ConfigurationParameters.Milliseconds.of("1s").value);
-        assertEquals(1500, ConfigurationParameters.Milliseconds.of("1.5s").value);
-        assertEquals(1500, ConfigurationParameters.Milliseconds.of("1s 500ms").value);
-        assertEquals(60*1000, ConfigurationParameters.Milliseconds.of("1m").value);
-        assertEquals(90*1000, ConfigurationParameters.Milliseconds.of("1m30s").value);
-        assertEquals(60*60*1000+90*1000, ConfigurationParameters.Milliseconds.of("1h1m30s").value);
-        assertEquals(36*60*60*1000 + 60*60*1000+90*1000, ConfigurationParameters.Milliseconds.of("1.5d1h1m30s").value);
-    }
 }
\ No newline at end of file