- Start factorizing LDIF and LDAP
authorMathieu Baudier <mbaudier@argeo.org>
Wed, 2 Sep 2015 17:48:21 +0000 (17:48 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Wed, 2 Sep 2015 17:48:21 +0000 (17:48 +0000)
- Add filter for role search

git-svn-id: https://svn.argeo.org/commons/trunk@8361 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

demo/argeo_node_rap.properties
demo/log4j.properties
org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/demo.ldif
org.argeo.security.core/ext/test/org/argeo/osgi/useradmin/LdifUserAdminTest.java
org.argeo.security.core/ext/test/org/argeo/osgi/useradmin/basic.ldif
org.argeo.security.core/src/org/argeo/osgi/useradmin/AbstractLdapUserAdmin.java [new file with mode: 0644]
org.argeo.security.core/src/org/argeo/osgi/useradmin/LdapUserAdmin.java
org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifUserAdmin.java

index 520c5baf46212a546806663a5a3f8ccca845efe9..b6ced43854d25f98a3ed9a2705a2f3add72566bd 100644 (file)
@@ -12,6 +12,8 @@ org.eclipse.gemini.blueprint.extender
 argeo.osgi.start.4.workbench=\
 org.eclipse.equinox.http.registry,\
 
+#argeo.node.useradmin.uri=ldap://localhost:10389/
+
 # HTTP
 org.osgi.service.http.port=7070
 org.eclipse.equinox.http.jetty.log.stderr.threshold=info
index 1238aeebe3232f9a4b5c293d931a2ded59949f73..da63069e9e37723a7426f83168aafa4d07e4fb88 100644 (file)
@@ -1,7 +1,7 @@
 log4j.rootLogger=WARN, development
 
 log4j.logger.org.argeo=DEBUG
-log4j.logger.org.apache.jackrabbit.core.RepositoryImpl=DEBUG
+#log4j.logger.org.apache.jackrabbit.core.RepositoryImpl=DEBUG
 #log4j.logger.argeo.stats=DEBUG
 
 ## Appenders
index 3b5d78d897ff24f6a9ff5b2765af13eb79c1d35c..5e9877935495ec113540de8f918ed06d0f4ddc0d 100644 (file)
@@ -1,15 +1,14 @@
 package org.argeo.cms.internal.kernel;
 
-import java.net.URL;
-
 import javax.jcr.RepositoryException;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.argeo.cms.CmsException;
-import org.argeo.cms.internal.useradmin.JcrUserAdmin;
 import org.argeo.cms.internal.useradmin.SimpleJcrSecurityModel;
 import org.argeo.cms.internal.useradmin.jackrabbit.JackrabbitUserAdminService;
+import org.argeo.osgi.useradmin.AbstractLdapUserAdmin;
+import org.argeo.osgi.useradmin.LdapUserAdmin;
 import org.argeo.osgi.useradmin.LdifUserAdmin;
 import org.argeo.security.OsAuthenticationToken;
 import org.argeo.security.UserAdminService;
@@ -37,7 +36,7 @@ class NodeSecurity implements AuthenticationManager {
        private final InternalAuthenticationProvider internalAuth;
        private final AnonymousAuthenticationProvider anonymousAuth;
        private final JackrabbitUserAdminService userAdminService;
-       private final LdifUserAdmin userAdmin;
+       private final AbstractLdapUserAdmin userAdmin;
 
        private ServiceRegistration<AuthenticationManager> authenticationManagerReg;
        private ServiceRegistration<UserAdminService> userAdminServiceReg;
@@ -65,7 +64,11 @@ class NodeSecurity implements AuthenticationManager {
                                .getFrameworkProp(KernelConstants.USERADMIN_URI);
                if (userAdminUri == null)
                        userAdminUri = getClass().getResource("demo.ldif").toString();
-               userAdmin = new LdifUserAdmin(userAdminUri);
+
+               if (userAdminUri.startsWith("ldap"))
+                       userAdmin = new LdapUserAdmin(userAdminUri);
+               else
+                       userAdmin = new LdifUserAdmin(userAdminUri);
        }
 
        public void publish() {
index 015ab2dd2ecb9b3435230706cbc2dd03c4a57c6b..1f172b29c4a84515580c8daf22d8ed525cbb103d 100644 (file)
@@ -15,9 +15,9 @@ objectClass: top
 ou: users
 
 dn: uid=demo,ou=users,dc=example,dc=com
+objectClass: inetOrgPerson
 objectClass: organizationalPerson
 objectClass: person
-objectClass: inetOrgPerson
 objectClass: top
 cn: Demo User
 description: Demo user
@@ -28,8 +28,8 @@ uid: demo
 userpassword:: e1NIQX1pZVNWNTVRYytlUU9hWURSU2hhL0Fqek5USkU9
 
 dn: uid=root,ou=users,dc=example,dc=com
-objectClass: person
 objectClass: inetOrgPerson
+objectClass: person
 objectClass: organizationalPerson
 objectClass: top
 cn: Super User
index d2a6c94c144d7663b735a5b9ed44df81652fa735..52682bf03ba85ce71b63d1f027178c49ab6e5309 100644 (file)
@@ -14,7 +14,7 @@ import org.osgi.service.useradmin.User;
 
 public class LdifUserAdminTest extends TestCase implements BasicTestConstants {
 
-       public void testBasicUserAdmin() {
+       public void testBasicUserAdmin() throws Exception {
                LdifUserAdmin userAdmin = new LdifUserAdmin(getClass()
                                .getResourceAsStream("basic.ldif"));
 
@@ -54,5 +54,15 @@ public class LdifUserAdminTest extends TestCase implements BasicTestConstants {
                                .getBytes();
                assertTrue(rootUser.hasCredential("userpassword", hashedPassword));
                assertTrue(demoUser.hasCredential("userpassword", hashedPassword));
+               
+               // search
+               Role[] search = userAdmin.getRoles(null);
+               assertEquals(4, search.length);
+               search = userAdmin.getRoles("(objectClass=groupOfNames)");
+               assertEquals(2, search.length);
+               search = userAdmin.getRoles("(objectclass=inetOrgPerson)");
+               assertEquals(2, search.length);
+               search = userAdmin.getRoles("(&(objectclass=inetOrgPerson)(uid=demo))");
+               assertEquals(1, search.length);
        }
 }
index 56c7499b29c7dfd9a2397c95912149fb969bd44e..5c6565e8ae9e85c314724977fcafa3abae352954 100644 (file)
@@ -15,9 +15,9 @@ objectClass: top
 ou: People
 
 dn: uid=demo,ou=People,dc=demo,dc=example,dc=org
+objectClass: inetOrgPerson
 objectClass: organizationalPerson
 objectClass: person
-objectClass: inetOrgPerson
 objectClass: top
 cn: demo User
 description: Demo user
@@ -28,11 +28,11 @@ uid: demo
 userpassword:: e1NIQX1pZVNWNTVRYytlUU9hWURSU2hhL0Fqek5USkU9
 
 dn: uid=root+cn=Super Admin,ou=People,dc=demo,dc=example,dc=org
-objectClass: person
 objectClass: inetOrgPerson
+objectClass: person
 objectClass: organizationalPerson
 objectClass: top
-cn: demo User
+cn: Super Admin
 description: Superuser
 givenname: Root
 mail: root@localhost
diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/AbstractLdapUserAdmin.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/AbstractLdapUserAdmin.java
new file mode 100644 (file)
index 0000000..df2ad4e
--- /dev/null
@@ -0,0 +1,52 @@
+package org.argeo.osgi.useradmin;
+
+import java.net.URI;
+import java.util.Arrays;
+import java.util.List;
+
+import org.osgi.service.useradmin.UserAdmin;
+
+public abstract class AbstractLdapUserAdmin implements UserAdmin {
+       private boolean isReadOnly;
+       private URI uri;
+
+       public AbstractLdapUserAdmin() {
+       }
+
+       public AbstractLdapUserAdmin(URI uri, boolean isReadOnly) {
+               this.uri = uri;
+               this.isReadOnly = isReadOnly;
+       }
+
+       private List<String> indexedUserProperties = Arrays.asList(new String[] {
+                       "uid", "mail", "cn" });
+
+       protected URI getUri() {
+               return uri;
+       }
+
+       protected void setUri(URI uri) {
+               this.uri = uri;
+       }
+
+       protected List<String> getIndexedUserProperties() {
+               return indexedUserProperties;
+       }
+
+       protected void setIndexedUserProperties(List<String> indexedUserProperties) {
+               this.indexedUserProperties = indexedUserProperties;
+       }
+
+       protected void setReadOnly(boolean isReadOnly) {
+               this.isReadOnly = isReadOnly;
+       }
+
+       public boolean isReadOnly() {
+               return isReadOnly;
+       }
+
+       public void destroy() {
+
+       }
+
+}
index 0173addbba8cc3f0b24d7a38630979552ec7070d..dcb639d9643f51718a56ceb0c5172c304cfec2f2 100644 (file)
@@ -1,7 +1,7 @@
 package org.argeo.osgi.useradmin;
 
+import java.net.URI;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Hashtable;
 import java.util.List;
 
@@ -24,23 +24,20 @@ import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.service.useradmin.Authorization;
 import org.osgi.service.useradmin.Role;
 import org.osgi.service.useradmin.User;
-import org.osgi.service.useradmin.UserAdmin;
 
-public class LdapUserAdmin implements UserAdmin {
+public class LdapUserAdmin extends AbstractLdapUserAdmin {
        private final static Log log = LogFactory.getLog(LdapUserAdmin.class);
 
-       private List<String> indexedUserProperties = Arrays.asList(new String[] {
-                       "uid", "mail", "cn" });
-
        private String baseDn = "dc=example,dc=com";
        private InitialLdapContext initialLdapContext = null;
 
        public LdapUserAdmin(String uri) {
                try {
+                       setUri(new URI(uri));
                        Hashtable<String, Object> connEnv = new Hashtable<String, Object>();
                        connEnv.put(Context.INITIAL_CONTEXT_FACTORY,
                                        "com.sun.jndi.ldap.LdapCtxFactory");
-                       connEnv.put(Context.PROVIDER_URL, "ldap://localhost:10389/");
+                       connEnv.put(Context.PROVIDER_URL, getUri().toString());
                        connEnv.put("java.naming.ldap.attributes.binary", "userPassword");
                        // connEnv.put(Context.SECURITY_AUTHENTICATION, "simple");
                        // connEnv.put(Context.SECURITY_PRINCIPAL, "uid=admin,ou=system");
@@ -106,15 +103,42 @@ public class LdapUserAdmin implements UserAdmin {
 
        @Override
        public Role[] getRoles(String filter) throws InvalidSyntaxException {
-               // TODO Auto-generated method stub
-               return null;
+               try {
+                       String searchFilter = filter;
+                       SearchControls searchControls = new SearchControls();
+                       searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
+
+                       String searchBase = baseDn;
+                       NamingEnumeration<SearchResult> results = initialLdapContext
+                                       .search(searchBase, searchFilter, searchControls);
+
+                       ArrayList<Role> res = new ArrayList<Role>();
+                       while (results.hasMoreElements()) {
+                               SearchResult searchResult = results.next();
+                               Attributes attrs = searchResult.getAttributes();
+                               String name = searchResult.getName();
+                               LdifUser role;
+                               if (attrs.get("objectClass").contains("groupOfNames"))
+                                       role = new LdifGroup(new LdapName(name), attrs);
+                               else if (attrs.get("objectClass").contains("inetOrgPerson"))
+                                       role = new LdifUser(new LdapName(name), attrs);
+                               else
+                                       throw new ArgeoUserAdminException(
+                                                       "Unsupported LDAP type for " + name);
+                               res.add(role);
+                       }
+                       return res.toArray(new Role[res.size()]);
+               } catch (Exception e) {
+                       throw new ArgeoUserAdminException("Cannot get roles for filter "
+                                       + filter, e);
+               }
        }
 
        @Override
        public User getUser(String key, String value) {
                if (key == null) {
                        List<User> users = new ArrayList<User>();
-                       for (String prop : indexedUserProperties) {
+                       for (String prop : getIndexedUserProperties()) {
                                User user = getUser(prop, value);
                                if (user != null)
                                        users.add(user);
index acbf1112f1e24d92b35926420aabc538406ecf5c..b1e9ceb49808a26f88ede1b0c56c004575fb731b 100644 (file)
@@ -4,7 +4,6 @@ import java.io.InputStream;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Dictionary;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -17,22 +16,18 @@ import javax.naming.NamingEnumeration;
 import javax.naming.directory.Attributes;
 import javax.naming.ldap.LdapName;
 
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.service.useradmin.Authorization;
 import org.osgi.service.useradmin.Role;
 import org.osgi.service.useradmin.User;
-import org.osgi.service.useradmin.UserAdmin;
 
 /** User admin implementation using LDIF file(s) as backend. */
-public class LdifUserAdmin implements UserAdmin {
+public class LdifUserAdmin extends AbstractLdapUserAdmin {
        SortedMap<LdapName, LdifUser> users = new TreeMap<LdapName, LdifUser>();
        SortedMap<LdapName, LdifGroup> groups = new TreeMap<LdapName, LdifGroup>();
 
-       private final boolean isReadOnly;
-       private final URI uri;
-
-       private List<String> indexedUserProperties = Arrays.asList(new String[] {
-                       "uid", "mail", "cn" });
        private Map<String, Map<String, LdifUser>> userIndexes = new LinkedHashMap<String, Map<String, LdifUser>>();
 
        public LdifUserAdmin(String uri) {
@@ -40,28 +35,28 @@ public class LdifUserAdmin implements UserAdmin {
        }
 
        public LdifUserAdmin(String uri, boolean isReadOnly) {
-               this.isReadOnly = isReadOnly;
+               setReadOnly(isReadOnly);
                try {
-                       this.uri = new URI(uri);
+                       setUri(new URI(uri));
                } catch (URISyntaxException e) {
                        throw new ArgeoUserAdminException("Invalid URI " + uri, e);
                }
 
-               if (!isReadOnly && !this.uri.getScheme().equals("file:"))
-                       throw new UnsupportedOperationException(this.uri.getScheme()
+               if (!isReadOnly && !getUri().getScheme().equals("file:"))
+                       throw new UnsupportedOperationException(getUri().getScheme()
                                        + "not supported read-write.");
 
                try {
-                       load(this.uri.toURL().openStream());
+                       load(getUri().toURL().openStream());
                } catch (Exception e) {
-                       throw new ArgeoUserAdminException("Cannot open URL " + this.uri, e);
+                       throw new ArgeoUserAdminException("Cannot open URL " + getUri(), e);
                }
        }
 
        public LdifUserAdmin(InputStream in) {
                load(in);
-               isReadOnly = true;
-               this.uri = null;
+               setReadOnly(true);
+               setUri(null);
        }
 
        protected void load(InputStream in) {
@@ -89,12 +84,12 @@ public class LdifUserAdmin implements UserAdmin {
                                group.loadMembers(this);
 
                        // indexes
-                       for (String attr : indexedUserProperties)
+                       for (String attr : getIndexedUserProperties())
                                userIndexes.put(attr, new TreeMap<String, LdifUser>());
 
                        for (LdifUser user : users.values()) {
                                Dictionary<String, Object> properties = user.getProperties();
-                               for (String attr : indexedUserProperties) {
+                               for (String attr : getIndexedUserProperties()) {
                                        Object value = properties.get(attr);
                                        if (value != null) {
                                                LdifUser otherUser = userIndexes.get(attr).put(
@@ -102,7 +97,7 @@ public class LdifUserAdmin implements UserAdmin {
                                                if (otherUser != null)
                                                        throw new ArgeoUserAdminException("User " + user
                                                                        + " and user " + otherUser
-                                                                       + " both habe property " + attr
+                                                                       + " both have property " + attr
                                                                        + " set to " + value);
                                        }
                                }
@@ -155,13 +150,20 @@ public class LdifUserAdmin implements UserAdmin {
 
        @Override
        public Role[] getRoles(String filter) throws InvalidSyntaxException {
+               ArrayList<Role> res = new ArrayList<Role>();
                if (filter == null) {
-                       ArrayList<Role> res = new ArrayList<Role>();
                        res.addAll(users.values());
                        res.addAll(groups.values());
-                       return res.toArray(new Role[res.size()]);
+               } else {
+                       Filter f = FrameworkUtil.createFilter(filter);
+                       for (LdifUser user : users.values())
+                               if (f.match(user.getProperties()))
+                                       res.add(user);
+                       for (LdifUser group : groups.values())
+                               if (f.match(group.getProperties()))
+                                       res.add(group);
                }
-               throw new UnsupportedOperationException();
+               return res.toArray(new Role[res.size()]);
        }
 
        @Override
@@ -175,7 +177,7 @@ public class LdifUserAdmin implements UserAdmin {
 
                // Try all indexes
                List<LdifUser> collectedUsers = new ArrayList<LdifUser>(
-                               indexedUserProperties.size());
+                               getIndexedUserProperties().size());
                // try dn
                LdifUser user = null;
                try {
@@ -197,8 +199,4 @@ public class LdifUserAdmin implements UserAdmin {
                // throw new UnsupportedOperationException();
        }
 
-       public boolean getIsReadOnly() {
-               return isReadOnly;
-       }
-
 }