Improve properties
authorMathieu Baudier <mbaudier@argeo.org>
Wed, 16 Sep 2015 08:38:39 +0000 (08:38 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Wed, 16 Sep 2015 08:38:39 +0000 (08:38 +0000)
git-svn-id: https://svn.argeo.org/commons/trunk@8408 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

demo/argeo_node_rap.properties
org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeUserAdmin.java
org.argeo.security.core/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java
org.argeo.security.core/src/org/argeo/osgi/useradmin/LdapProperties.java [deleted file]
org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifUserAdmin.java
org.argeo.security.core/src/org/argeo/osgi/useradmin/UserAdminProps.java [new file with mode: 0644]
org.argeo.security.core/src/org/argeo/osgi/useradmin/UserDirectory.java [new file with mode: 0644]

index 2c9d5d8423490e25a8f4e22ba7d0d29be773633a..52eea6a30ec1d5c72feaf204924932b29b49cdb3 100644 (file)
@@ -12,7 +12,12 @@ org.eclipse.gemini.blueprint.extender
 argeo.osgi.start.4.workbench=\
 org.eclipse.equinox.http.registry,\
 
-#argeo.node.useradmin.uri="\
+org.osgi.framework.security=osgi
+java.security.policy=file:../../all.policy
+
+argeo.node.useradmin.uris=ldap://uid=admin,ou=system:secret@localhost:10389\
+/dc=example,dc=com?userBase=ou=users&groupBase=ou=groups
+#argeo.node.useradmin.uris="\
 #ldap://uid=admin,ou=system:secret\
 #@localhost:10389\
 #/dc=example,dc=com\
@@ -20,9 +25,6 @@ org.eclipse.equinox.http.registry,\
 #&userObjectClass=inetOrgPerson \
 #dc=example,dc=org.ldif"
 
-org.osgi.framework.security=osgi
-java.security.policy=file:../../all.policy
-
 # HTTP
 org.osgi.service.http.port=7070
 org.eclipse.equinox.http.jetty.log.stderr.threshold=info
index e0d237da194591ca89322843a8feabebe82024b1..663c2b9375e4f1353e80c4ef6bf5f4358aff5a76 100644 (file)
@@ -19,7 +19,7 @@ public interface KernelConstants {
        // Node Security
        final static String ROLES_URI = "argeo.node.roles.uri";
        /** URI to an LDIF file or LDAP server used as initialization or backend */
-       final static String USERADMIN_URI = "argeo.node.useradmin.uri";
+       final static String USERADMIN_URIS = "argeo.node.useradmin.uris";
        final static String[] DEFAULT_CNDS = { "/org/argeo/jcr/argeo.cnd",
                        "/org/argeo/cms/cms.cnd" };
 
index aed824fbdff830b3b21f0cbd7ba22c39e48e6821..0b6ce9a85fce0badb73613fbb298c53e15842100 100644 (file)
@@ -101,13 +101,11 @@ class NodeSecurity implements AuthenticationManager {
        }
 
        public void publish() {
+               userAdminReg = bundleContext.registerService(UserAdmin.class,
+                               userAdmin, userAdmin.currentState());
+               // dummy auth manager, in order to smooth transition from Argeo 1
                authenticationManagerReg = bundleContext.registerService(
                                AuthenticationManager.class, this, null);
-               Hashtable<String, Object> properties = new Hashtable<String, Object>();
-               // properties.put(KernelConstants.USERADMIN_URI,
-               // userAdmin.asConfigUris());
-               userAdminReg = bundleContext.registerService(UserAdmin.class,
-                               userAdmin, properties);
        }
 
        void destroy() {
index 9227eaeb9af02d389cca96b09b909f1b45383863..7ead081510e7ba3088f7b03786edc998154b5e24 100644 (file)
@@ -9,6 +9,7 @@ import java.util.Arrays;
 import java.util.Dictionary;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -22,8 +23,8 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.argeo.cms.CmsException;
 import org.argeo.cms.KernelHeader;
-import org.argeo.osgi.useradmin.AbstractUserDirectory;
-import org.argeo.osgi.useradmin.LdapProperties;
+import org.argeo.osgi.useradmin.UserDirectory;
+import org.argeo.osgi.useradmin.UserAdminProps;
 import org.argeo.osgi.useradmin.LdapUserAdmin;
 import org.argeo.osgi.useradmin.LdifUserAdmin;
 import org.argeo.osgi.useradmin.UserDirectoryException;
@@ -54,7 +55,7 @@ public class NodeUserAdmin implements UserAdmin {
                nodeBaseDir.mkdirs();
 
                String userAdminUri = KernelUtils
-                               .getFrameworkProp(KernelConstants.USERADMIN_URI);
+                               .getFrameworkProp(KernelConstants.USERADMIN_URIS);
                if (userAdminUri == null) {
                        String demoBaseDn = "dc=example,dc=com";
                        File businessRolesFile = new File(nodeBaseDir, demoBaseDn + ".ldif");
@@ -88,16 +89,16 @@ public class NodeUserAdmin implements UserAdmin {
                                throw new CmsException(
                                                "Cannot interpret " + uri + " as an uri", e);
                        }
-                       Dictionary<String, ?> properties = LdapProperties.uriAsProperties(u
+                       Dictionary<String, ?> properties = UserAdminProps.uriAsProperties(u
                                        .toString());
-                       AbstractUserDirectory businessRoles;
+                       UserDirectory businessRoles;
                        if (u.getScheme().startsWith("ldap")) {
                                businessRoles = new LdapUserAdmin(properties);
                        } else {
                                businessRoles = new LdifUserAdmin(properties);
                        }
                        businessRoles.init();
-                       addUserAdmin(businessRoles.getBaseDn(), businessRoles);
+                       addUserAdmin(businessRoles.getBaseDn(), (UserAdmin) businessRoles);
                        if (log.isDebugEnabled())
                                log.debug("User directory " + businessRoles.getBaseDn() + " ["
                                                + u.getScheme() + "] enabled.");
@@ -119,14 +120,14 @@ public class NodeUserAdmin implements UserAdmin {
                        nodeRolesUri = nodeRolesFile.toURI().toString();
                }
 
-               Dictionary<String, ?> nodeRolesProperties = LdapProperties
+               Dictionary<String, ?> nodeRolesProperties = UserAdminProps
                                .uriAsProperties(nodeRolesUri);
-               if (!nodeRolesProperties.get(LdapProperties.baseDn.getFullName())
+               if (!nodeRolesProperties.get(UserAdminProps.baseDn.getFullName())
                                .equals(baseNodeRoleDn)) {
                        throw new CmsException("Invalid base dn for node roles");
                        // TODO deal with "mounted" roles with a different baseDN
                }
-               AbstractUserDirectory nodeRoles;
+               UserDirectory nodeRoles;
                if (nodeRolesUri.startsWith("ldap")) {
                        nodeRoles = new LdapUserAdmin(nodeRolesProperties);
                } else {
@@ -134,31 +135,33 @@ public class NodeUserAdmin implements UserAdmin {
                }
                nodeRoles.setExternalRoles(this);
                nodeRoles.init();
-               addUserAdmin(baseNodeRoleDn, nodeRoles);
+               addUserAdmin(baseNodeRoleDn, (UserAdmin)nodeRoles);
                if (log.isTraceEnabled())
                        log.trace("Node roles enabled.");
        }
 
-       String asConfigUris() {
-               StringBuilder buf = new StringBuilder();
+       Dictionary<String, ?> currentState() {
+               Dictionary<String, Object> res = new Hashtable<String, Object>();
                for (LdapName name : userAdmins.keySet()) {
-                       buf.append('/').append(name.toString());
-                       if (userAdmins.get(name) instanceof AbstractUserDirectory) {
-                               AbstractUserDirectory userDirectory = (AbstractUserDirectory) userAdmins
+                       StringBuilder buf = new StringBuilder();
+                       if (userAdmins.get(name) instanceof UserDirectory) {
+                               UserDirectory userDirectory = (UserDirectory) userAdmins
                                                .get(name);
-                               if (userDirectory.isReadOnly())
-                                       buf.append('?').append(LdapProperties.readOnly.name())
-                                                       .append("=true");
+                               String uri = UserAdminProps.propertiesAsUri(
+                                               userDirectory.getProperties()).toString();
+                               res.put(uri, "");
+                       } else {
+                               buf.append('/').append(name.toString())
+                                               .append("?readOnly=true");
                        }
-                       buf.append(' ');
                }
-               return buf.toString();
+               return res;
        }
 
        public void destroy() {
                for (LdapName name : userAdmins.keySet()) {
-                       if (userAdmins.get(name) instanceof AbstractUserDirectory) {
-                               AbstractUserDirectory userDirectory = (AbstractUserDirectory) userAdmins
+                       if (userAdmins.get(name) instanceof UserDirectory) {
+                               UserDirectory userDirectory = (UserDirectory) userAdmins
                                                .get(name);
                                userDirectory.destroy();
                        }
@@ -283,12 +286,12 @@ public class NodeUserAdmin implements UserAdmin {
        }
 
        public void setTransactionManager(TransactionManager transactionManager) {
-               if (nodeRoles instanceof AbstractUserDirectory)
-                       ((AbstractUserDirectory) nodeRoles)
+               if (nodeRoles instanceof UserDirectory)
+                       ((UserDirectory) nodeRoles)
                                        .setTransactionManager(transactionManager);
                for (UserAdmin userAdmin : userAdmins.values()) {
-                       if (userAdmin instanceof AbstractUserDirectory)
-                               ((AbstractUserDirectory) userAdmin)
+                       if (userAdmin instanceof UserDirectory)
+                               ((UserDirectory) userAdmin)
                                                .setTransactionManager(transactionManager);
                }
        }
index f689400025b26721b41a5c19b34536d17f7bd169..18cb5ece251b1e81fc4b990dc0b5bbbee67d81a8 100644 (file)
@@ -41,7 +41,7 @@ import org.osgi.service.useradmin.Role;
 import org.osgi.service.useradmin.User;
 import org.osgi.service.useradmin.UserAdmin;
 
-public abstract class AbstractUserDirectory implements UserAdmin {
+abstract class AbstractUserDirectory implements UserAdmin, UserDirectory {
        private final static Log log = LogFactory
                        .getLog(AbstractUserDirectory.class);
 
@@ -72,7 +72,7 @@ public abstract class AbstractUserDirectory implements UserAdmin {
                // TODO make a copy?
                this.properties = properties;
 
-               String uriStr = LdapProperties.uri.getValue(properties);
+               String uriStr = UserAdminProps.uri.getValue(properties);
                if (uriStr == null)
                        uri = null;
                else
@@ -82,16 +82,16 @@ public abstract class AbstractUserDirectory implements UserAdmin {
                                throw new UserDirectoryException("Badly formatted URI", e);
                        }
 
-               baseDn = LdapProperties.baseDn.getValue(properties).toString();
-               String isReadOnly = LdapProperties.readOnly.getValue(properties);
+               baseDn = UserAdminProps.baseDn.getValue(properties).toString();
+               String isReadOnly = UserAdminProps.readOnly.getValue(properties);
                if (isReadOnly == null)
                        this.isReadOnly = readOnlyDefault(uri);
                else
                        this.isReadOnly = new Boolean(isReadOnly);
 
-               this.userObjectClass = LdapProperties.userObjectClass
+               this.userObjectClass = UserAdminProps.userObjectClass
                                .getValue(properties);
-               this.groupObjectClass = LdapProperties.groupObjectClass
+               this.groupObjectClass = UserAdminProps.groupObjectClass
                                .getValue(properties);
        }
 
@@ -411,7 +411,7 @@ public abstract class AbstractUserDirectory implements UserAdmin {
                return groupObjectClass;
        }
 
-       protected Dictionary<String, ?> getProperties() {
+       public Dictionary<String, ?> getProperties() {
                return properties;
        }
 
diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdapProperties.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdapProperties.java
deleted file mode 100644 (file)
index 749c8fe..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-package org.argeo.osgi.useradmin;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URI;
-import java.net.URLDecoder;
-import java.util.Dictionary;
-import java.util.Hashtable;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import javax.naming.Context;
-
-public enum LdapProperties {
-       /** Base DN */
-       baseDn("dc=example,dc=com"),
-
-       /** URI of the underlying resource */
-       uri("ldap://localhost:10389"),
-
-       /** User objectClass */
-       userObjectClass("inetOrgPerson"),
-
-       /** Groups objectClass */
-       groupObjectClass("groupOfNames"),
-
-       /** Read-only source */
-       readOnly(null);
-
-       private static String PREFIX = "argeo.ldap.";
-
-       /** The default value. */
-       private Object def;
-
-       LdapProperties(Object def) {
-               this.def = def;
-       }
-
-       public Object getDefault() {
-               return def;
-       }
-
-       public String getFullName() {
-               return getPrefix() + name();
-       }
-
-       public String getPrefix() {
-               return PREFIX;
-       }
-
-       public String getValue(Dictionary<String, ?> properties) {
-               Object res = getRawValue(properties);
-               if (res == null)
-                       return null;
-               return res.toString();
-       }
-
-       @SuppressWarnings("unchecked")
-       public <T> T getRawValue(Dictionary<String, ?> properties) {
-               Object res = properties.get(getFullName());
-               if (res == null)
-                       res = getDefault();
-               return (T) res;
-       }
-
-       public static Dictionary<String, ?> uriAsProperties(String uriStr) {
-               try {
-                       Hashtable<String, Object> res = new Hashtable<String, Object>();
-                       URI u = new URI(uriStr);
-                       String scheme = u.getScheme();
-                       String path = u.getPath();
-                       String bDn = path.substring(path.lastIndexOf('/') + 1,
-                                       path.length());
-                       String principal = null;
-                       String credentials = null;
-                       if (scheme != null)
-                               if (scheme.equals("ldap") || scheme.equals("ldaps")) {
-                                       // TODO additional checks
-                                       String[] userInfo = u.getUserInfo().split(":");
-                                       principal = userInfo.length > 0 ? userInfo[0] : null;
-                                       credentials = userInfo.length > 1 ? userInfo[1] : null;
-                               } else if (scheme.equals("file")) {
-                                       if (bDn.endsWith(".ldif")) {
-                                               bDn = bDn.substring(0, bDn.length() - ".ldif".length());
-                                       }
-                               } else
-                                       throw new UserDirectoryException("Unsupported scheme "
-                                                       + scheme);
-                       Map<String, List<String>> query = splitQuery(u.getQuery());
-                       for (String key : query.keySet()) {
-                               LdapProperties ldapProp = LdapProperties.valueOf(key);
-                               List<String> values = query.get(key);
-                               if (values.size() == 1) {
-                                       res.put(ldapProp.getFullName(), values.get(0));
-                               } else {
-                                       throw new UserDirectoryException(
-                                                       "Only single values are supported");
-                               }
-                       }
-                       res.put(baseDn.getFullName(), bDn);
-                       if (principal != null)
-                               res.put(Context.SECURITY_PRINCIPAL, principal);
-                       if (credentials != null)
-                               res.put(Context.SECURITY_CREDENTIALS, credentials);
-                       if (scheme != null) {
-                               URI bareUri = new URI(scheme, null, u.getHost(), u.getPort(),
-                                               scheme.equals("file") ? u.getPath() : null, null, null);
-                               res.put(uri.getFullName(), bareUri.toString());
-                       }
-                       return res;
-               } catch (Exception e) {
-                       throw new UserDirectoryException("Cannot convert " + uri
-                                       + " to properties", e);
-               }
-       }
-
-       public static Map<String, List<String>> splitQuery(String query)
-                       throws UnsupportedEncodingException {
-               final Map<String, List<String>> query_pairs = new LinkedHashMap<String, List<String>>();
-               if (query == null)
-                       return query_pairs;
-               final String[] pairs = query.split("&");
-               for (String pair : pairs) {
-                       final int idx = pair.indexOf("=");
-                       final String key = idx > 0 ? URLDecoder.decode(
-                                       pair.substring(0, idx), "UTF-8") : pair;
-                       if (!query_pairs.containsKey(key)) {
-                               query_pairs.put(key, new LinkedList<String>());
-                       }
-                       final String value = idx > 0 && pair.length() > idx + 1 ? URLDecoder
-                                       .decode(pair.substring(idx + 1), "UTF-8") : null;
-                       query_pairs.get(key).add(value);
-               }
-               return query_pairs;
-       }
-
-       public static void main(String[] args) {
-               System.out.println(uriAsProperties("ldap://"
-                               + "uid=admin,ou=system:secret@localhost:10389"
-                               + "/dc=example,dc=com"
-                               + "?readOnly=false&userObjectClass=person"));
-               System.out
-                               .println(uriAsProperties("file://some/dir/dc=example,dc=com.ldif"));
-               System.out
-                               .println(uriAsProperties("/dc=example,dc=com.ldif?readOnly=true"));
-       }
-}
index 750d6a82a0537903e7d210c76a18e128aa5a184b..830488589c2331311d1f7148e0dc31b6b4993046 100644 (file)
@@ -48,8 +48,8 @@ public class LdifUserAdmin extends AbstractUserDirectory {
 
        private static Dictionary<String, Object> fromUri(String uri, String baseDn) {
                Hashtable<String, Object> res = new Hashtable<String, Object>();
-               res.put(LdapProperties.uri.getFullName(), uri);
-               res.put(LdapProperties.baseDn.getFullName(), baseDn);
+               res.put(UserAdminProps.uri.getFullName(), uri);
+               res.put(UserAdminProps.baseDn.getFullName(), baseDn);
                return res;
        }
 
diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/UserAdminProps.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/UserAdminProps.java
new file mode 100644 (file)
index 0000000..580110d
--- /dev/null
@@ -0,0 +1,191 @@
+package org.argeo.osgi.useradmin;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URLDecoder;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javax.naming.Context;
+
+public enum UserAdminProps {
+       /** Base DN */
+       baseDn("dc=example,dc=com"),
+
+       /** URI of the underlying resource */
+       uri("ldap://localhost:10389"),
+
+       /** User objectClass */
+       userObjectClass("inetOrgPerson"),
+
+       /** Relative base DN for users */
+       userBase("ou=users"),
+
+       /** Groups objectClass */
+       groupObjectClass("groupOfNames"),
+
+       /** Relative base DN for users */
+       groupBase("ou=groups"),
+
+       /** Read-only source */
+       readOnly(null);
+
+       private static String PREFIX = "argeo.useradmin";
+
+       /** The default value. */
+       private Object def;
+
+       UserAdminProps(Object def) {
+               this.def = def;
+       }
+
+       public Object getDefault() {
+               return def;
+       }
+
+       public String getFullName() {
+               return getPrefix() + name();
+       }
+
+       public String getPrefix() {
+               return PREFIX;
+       }
+
+       public String getValue(Dictionary<String, ?> properties) {
+               Object res = getRawValue(properties);
+               if (res == null)
+                       return null;
+               return res.toString();
+       }
+
+       @SuppressWarnings("unchecked")
+       public <T> T getRawValue(Dictionary<String, ?> properties) {
+               Object res = properties.get(getFullName());
+               if (res == null)
+                       res = getDefault();
+               return (T) res;
+       }
+
+       /** Hides host and credentials. */
+       public static URI propertiesAsUri(Dictionary<String, ?> properties) {
+               StringBuilder query = new StringBuilder();
+
+               boolean first = true;
+               for (Enumeration<String> keys = properties.keys(); keys
+                               .hasMoreElements();) {
+                       String key = keys.nextElement();
+                       if (key.startsWith(PREFIX) && !key.equals(baseDn.getFullName())
+                                       && !key.equals(uri.getFullName())) {
+                               if (first)
+                                       first = false;
+                               else
+                                       query.append('&');
+                               query.append(key.substring(PREFIX.length()));
+                               query.append('=').append(properties.get(key).toString());
+                       }
+               }
+
+               String bDn = (String) properties.get(baseDn.getFullName());
+               try {
+                       return new URI(null, null, bDn != null ? '/' + bDn : null,
+                                       query.length() != 0 ? query.toString() : null, null);
+               } catch (URISyntaxException e) {
+                       throw new UserDirectoryException(
+                                       "Cannot create URI from properties", e);
+               }
+       }
+
+       public static Dictionary<String, ?> uriAsProperties(String uriStr) {
+               try {
+                       Hashtable<String, Object> res = new Hashtable<String, Object>();
+                       URI u = new URI(uriStr);
+                       String scheme = u.getScheme();
+                       String path = u.getPath();
+                       String bDn = path.substring(path.lastIndexOf('/') + 1,
+                                       path.length());
+                       if (bDn.endsWith(".ldif"))
+                               bDn = bDn.substring(0, bDn.length() - ".ldif".length());
+
+                       String principal = null;
+                       String credentials = null;
+                       if (scheme != null)
+                               if (scheme.equals("ldap") || scheme.equals("ldaps")) {
+                                       // TODO additional checks
+                                       String[] userInfo = u.getUserInfo().split(":");
+                                       principal = userInfo.length > 0 ? userInfo[0] : null;
+                                       credentials = userInfo.length > 1 ? userInfo[1] : null;
+                               } else if (scheme.equals("file")) {
+                               } else
+                                       throw new UserDirectoryException("Unsupported scheme "
+                                                       + scheme);
+                       Map<String, List<String>> query = splitQuery(u.getQuery());
+                       for (String key : query.keySet()) {
+                               UserAdminProps ldapProp = UserAdminProps.valueOf(key);
+                               List<String> values = query.get(key);
+                               if (values.size() == 1) {
+                                       res.put(ldapProp.getFullName(), values.get(0));
+                               } else {
+                                       throw new UserDirectoryException(
+                                                       "Only single values are supported");
+                               }
+                       }
+                       res.put(baseDn.getFullName(), bDn);
+                       if (principal != null)
+                               res.put(Context.SECURITY_PRINCIPAL, principal);
+                       if (credentials != null)
+                               res.put(Context.SECURITY_CREDENTIALS, credentials);
+                       if (scheme != null) {
+                               URI bareUri = new URI(scheme, null, u.getHost(), u.getPort(),
+                                               scheme.equals("file") ? u.getPath() : null, null, null);
+                               res.put(uri.getFullName(), bareUri.toString());
+                       }
+                       return res;
+               } catch (Exception e) {
+                       throw new UserDirectoryException("Cannot convert " + uri
+                                       + " to properties", e);
+               }
+       }
+
+       private static Map<String, List<String>> splitQuery(String query)
+                       throws UnsupportedEncodingException {
+               final Map<String, List<String>> query_pairs = new LinkedHashMap<String, List<String>>();
+               if (query == null)
+                       return query_pairs;
+               final String[] pairs = query.split("&");
+               for (String pair : pairs) {
+                       final int idx = pair.indexOf("=");
+                       final String key = idx > 0 ? URLDecoder.decode(
+                                       pair.substring(0, idx), "UTF-8") : pair;
+                       if (!query_pairs.containsKey(key)) {
+                               query_pairs.put(key, new LinkedList<String>());
+                       }
+                       final String value = idx > 0 && pair.length() > idx + 1 ? URLDecoder
+                                       .decode(pair.substring(idx + 1), "UTF-8") : null;
+                       query_pairs.get(key).add(value);
+               }
+               return query_pairs;
+       }
+
+       public static void main(String[] args) {
+               Dictionary<String, ?> props = uriAsProperties("ldap://"
+                               + "uid=admin,ou=system:secret@localhost:10389"
+                               + "/dc=example,dc=com"
+                               + "?readOnly=false&userObjectClass=person");
+               System.out.println(props);
+               System.out.println(propertiesAsUri(props));
+
+               System.out
+                               .println(uriAsProperties("file://some/dir/dc=example,dc=com.ldif"));
+
+               props = uriAsProperties("/dc=example,dc=com.ldif?readOnly=true"
+                               + "&userBase=ou=CoWorkers,ou=People&groupBase=ou=Roles");
+               System.out.println(props);
+               System.out.println(propertiesAsUri(props));
+       }
+}
diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/UserDirectory.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/UserDirectory.java
new file mode 100644 (file)
index 0000000..b02acd6
--- /dev/null
@@ -0,0 +1,23 @@
+package org.argeo.osgi.useradmin;
+
+import java.util.Dictionary;
+
+import javax.transaction.TransactionManager;
+
+import org.osgi.service.useradmin.UserAdmin;
+
+/** Information about a user directory. */
+public interface UserDirectory {
+       public String getBaseDn();
+
+       public void setExternalRoles(UserAdmin externalRoles);
+
+       public Dictionary<String, ?> getProperties();
+
+       // Transitional. In the future, more will be managed in OSGi.
+       public void setTransactionManager(TransactionManager transactionManager);
+
+       public void init();
+
+       public void destroy();
+}