Introduce directory kinds.
authorMathieu Baudier <mbaudier@argeo.org>
Tue, 21 Jun 2022 05:18:11 +0000 (07:18 +0200)
committerMathieu Baudier <mbaudier@argeo.org>
Tue, 21 Jun 2022 05:18:11 +0000 (07:18 +0200)
17 files changed:
org.argeo.cms/src/org/argeo/cms/CmsUserManager.java
org.argeo.cms/src/org/argeo/cms/acr/directory/DirectoryContent.java
org.argeo.cms/src/org/argeo/cms/internal/auth/CmsUserManagerImpl.java
org.argeo.util/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java
org.argeo.util/src/org/argeo/osgi/useradmin/FunctionalGroup.java [new file with mode: 0644]
org.argeo.util/src/org/argeo/osgi/useradmin/HierarchyUnit.java
org.argeo.util/src/org/argeo/osgi/useradmin/LdapNameUtils.java
org.argeo.util/src/org/argeo/osgi/useradmin/LdapUserAdmin.java
org.argeo.util/src/org/argeo/osgi/useradmin/LdifGroup.java
org.argeo.util/src/org/argeo/osgi/useradmin/LdifHierarchyUnit.java
org.argeo.util/src/org/argeo/osgi/useradmin/LdifUser.java
org.argeo.util/src/org/argeo/osgi/useradmin/LdifUserAdmin.java
org.argeo.util/src/org/argeo/osgi/useradmin/Organization.java [new file with mode: 0644]
org.argeo.util/src/org/argeo/osgi/useradmin/OsUserDirectory.java
org.argeo.util/src/org/argeo/osgi/useradmin/Person.java [new file with mode: 0644]
org.argeo.util/src/org/argeo/osgi/useradmin/SystemPermissions.java [new file with mode: 0644]
org.argeo.util/src/org/argeo/osgi/useradmin/UserDirectory.java

index 5256dbfed5901eb507e9ddaf8583edd1ab628b3f..9af578c962ab8370b0d7ceb9dc72f4024f88eb1b 100644 (file)
@@ -81,7 +81,7 @@ public interface CmsUserManager {
 
        void expireAuthTokens(Subject subject);
        
-       UserDirectory getUserDirectory(User user);
+       UserDirectory getDirectory(Role role);
 
 //     User createUserFromPerson(Node person);
 
index b0c1b6bd18ba66bca3d8887a5dc390411897c51b..dc9aefa800b7385f4e4848ba8ebaa628d821a944 100644 (file)
@@ -32,7 +32,7 @@ class DirectoryContent extends AbstractContent {
        @Override
        public Iterator<Content> iterator() {
                List<Content> res = new ArrayList<>();
-               for (Iterator<HierarchyUnit> it = directory.getRootHierarchyUnits().iterator(); it.hasNext();) {
+               for (Iterator<HierarchyUnit> it = directory.getRootHierarchyUnits(false).iterator(); it.hasNext();) {
                        res.add(new HierarchyUnitContent(getSession(), provider, it.next()));
                }
                return res.iterator();
index e6a305685e4920115e63478b6e3c4b623a4663ea..5d5477e9b953d567cea8d831af3dcf86dbc48494 100644 (file)
@@ -441,7 +441,7 @@ public class CmsUserManagerImpl implements CmsUserManager {
        }
 
        @Override
-       public UserDirectory getUserDirectory(User user) {
+       public UserDirectory getDirectory(Role user) {
                String name = user.getName();
                NavigableMap<String, UserDirectory> possible = new TreeMap<>();
                for (UserDirectory userDirectory : userDirectories.keySet()) {
index 27662938faf84682c56bfec8f50f0f6c416694e0..f2e1d26066603ff30560f2bef6198f6e88cac865 100644 (file)
@@ -33,6 +33,7 @@ import javax.naming.ldap.Rdn;
 
 import org.argeo.osgi.transaction.WorkControl;
 import org.argeo.util.naming.LdapAttrs;
+import org.argeo.util.naming.LdapObjs;
 import org.osgi.framework.Filter;
 import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.InvalidSyntaxException;
@@ -47,7 +48,9 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory {
        static final String SHARED_STATE_PASSWORD = "javax.security.auth.login.password";
 
        private final Hashtable<String, Object> properties;
-       private final LdapName baseDn, userBaseDn, groupBaseDn;
+       private final LdapName baseDn;
+       // private final LdapName userBaseDn, groupBaseDn;
+       private final Rdn userBaseRdn, groupBaseRdn;
        private final String userObjectClass, userBase, groupObjectClass, groupBase;
 
        private final boolean readOnly;
@@ -99,8 +102,10 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory {
                groupBase = UserAdminConf.groupBase.getValue(properties);
                try {
                        baseDn = new LdapName(UserAdminConf.baseDn.getValue(properties));
-                       userBaseDn = new LdapName(userBase + "," + baseDn);
-                       groupBaseDn = new LdapName(groupBase + "," + baseDn);
+                       userBaseRdn = new Rdn(userBase);
+//                     userBaseDn = new LdapName(userBase + "," + baseDn);
+                       groupBaseRdn = new Rdn(groupBase);
+//                     groupBaseDn = new LdapName(groupBase + "," + baseDn);
                } catch (InvalidNameException e) {
                        throw new IllegalArgumentException("Badly formated base DN " + UserAdminConf.baseDn.getValue(properties),
                                        e);
@@ -429,7 +434,7 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory {
        }
 
        protected DirectoryUser newRole(LdapName dn, int type, Attributes attrs) {
-               LdifUser newRole;
+               DirectoryUser newRole;
                BasicAttribute objClass = new BasicAttribute(objectClass.name());
                if (type == Role.USER) {
                        String userObjClass = newUserObjectClass(dn);
@@ -443,14 +448,14 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory {
                        objClass.add(top.name());
                        objClass.add(extensibleObject.name());
                        attrs.put(objClass);
-                       newRole = new LdifUser(this, dn, attrs);
+                       newRole = newUser(dn, attrs);
                } else if (type == Role.GROUP) {
                        String groupObjClass = getGroupObjectClass();
                        objClass.add(groupObjClass);
                        // objClass.add(LdifName.extensibleObject.name());
                        objClass.add(top.name());
                        attrs.put(objClass);
-                       newRole = new LdifGroup(this, dn, attrs);
+                       newRole = newGroup(dn, attrs);
                } else
                        throw new IllegalArgumentException("Unsupported type " + type);
                return newRole;
@@ -529,6 +534,10 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory {
                throw new UnsupportedOperationException();
        }
 
+       void isFunctionalHierarchyUnit(HierarchyUnit hu) {
+
+       }
+
 //     @Override
 //     public List<? extends Role> getHierarchyUnitRoles(String filter, boolean deep) {
 //             try {
@@ -539,10 +548,42 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory {
 //     }
 
        @Override
-       public Iterable<HierarchyUnit> getRootHierarchyUnits() {
+       public Iterable<HierarchyUnit> getRootHierarchyUnits(boolean functionalOnly) {
                throw new UnsupportedOperationException();
        }
 
+       /*
+        * ROLES CREATION
+        */
+       protected DirectoryUser newUser(LdapName name, Attributes attrs) {
+               // TODO support devices, applications, etc.
+               return new LdifUser.LdifPerson(this, name, attrs);
+       }
+
+       protected DirectoryGroup newGroup(LdapName name, Attributes attrs) {
+               if (hasObjectClass(attrs, LdapObjs.organization))
+                       return new LdifGroup.LdifOrganization(this, name, attrs);
+               else
+                       return new LdifGroup.LdifFunctionalGroup(this, name, attrs);
+
+       }
+
+       private boolean hasObjectClass(Attributes attrs, LdapObjs objectClass) {
+               try {
+                       Attribute attr = attrs.get(LdapAttrs.objectClass.name());
+                       NamingEnumeration<?> en = attr.getAll();
+                       while (en.hasMore()) {
+                               String v = en.next().toString();
+                               if (v.equalsIgnoreCase(objectClass.name()))
+                                       return true;
+
+                       }
+                       return false;
+               } catch (NamingException e) {
+                       throw new IllegalStateException("Cannot search for objectClass " + objectClass.name(), e);
+               }
+       }
+
        // GETTERS
        protected String getMemberAttributeId() {
                return memberAttributeId;
@@ -596,12 +637,14 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory {
        }
 
        protected int roleType(LdapName dn) {
-               if (dn.startsWith(groupBaseDn))
+               Rdn technicalRdn = LdapNameUtils.getParentRdn(dn);
+               if (groupBaseRdn.equals(technicalRdn))
                        return Role.GROUP;
-               else if (dn.startsWith(userBaseDn))
+               else if (userBaseRdn.equals(technicalRdn))
                        return Role.USER;
                else
-                       return Role.GROUP;
+                       throw new IllegalArgumentException(
+                                       "Cannot dind role type, " + technicalRdn + " is not a technical RDN for " + dn);
        }
 
        /** dn can be null, in that case a default should be returned. */
@@ -609,10 +652,15 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory {
                return userObjectClass;
        }
 
-       public String getUserBase() {
+       @Deprecated
+       String getUserBase() {
                return userBase;
        }
 
+       Rdn getUserBaseRdn() {
+               return userBaseRdn;
+       }
+
        protected String newUserObjectClass(LdapName dn) {
                return getUserObjectClass();
        }
@@ -621,10 +669,15 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory {
                return groupObjectClass;
        }
 
-       public String getGroupBase() {
+       @Deprecated
+       String getGroupBase() {
                return groupBase;
        }
 
+       Rdn getGroupBaseRdn() {
+               return groupBaseRdn;
+       }
+
        LdapName getBaseDn() {
                return (LdapName) baseDn.clone();
        }
diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/FunctionalGroup.java b/org.argeo.util/src/org/argeo/osgi/useradmin/FunctionalGroup.java
new file mode 100644 (file)
index 0000000..5f17d8b
--- /dev/null
@@ -0,0 +1,5 @@
+package org.argeo.osgi.useradmin;
+
+public interface FunctionalGroup {
+
+}
index 9783a2786b238819330d8a2da050c81f36297c3a..ba76617d768bfef3b469732ba8b93a7d6de2ec41 100644 (file)
@@ -6,17 +6,15 @@ import org.osgi.service.useradmin.Role;
 
 /** A unit within the high-level organisational structure of a directory. */
 public interface HierarchyUnit {
-       final static int UNKOWN = 0;
-       final static int ORGANIZATION = 1;
-       final static int OU = 2;
-
        String getHierarchyUnitName();
 
        HierarchyUnit getParent();
 
        Iterable<HierarchyUnit> getDirectHierachyUnits();
 
-       int getHierarchyUnitType();
+       Iterable<HierarchyUnit> getFunctionalHierachyUnits();
+
+       boolean isFunctional();
 
        String getBasePath();
 
index f76d9441b9a5613799f4bd659faa87cf2553593b..7e763456a54cb846097ec12ff40b6cc55636c3cf 100644 (file)
@@ -31,6 +31,13 @@ class LdapNameUtils {
                }
        }
 
+       static Rdn getParentRdn(LdapName dn) {
+               if (dn.size() < 2)
+                       throw new IllegalArgumentException(dn + " has no parent");
+               Rdn parentRdn = dn.getRdn(dn.size() - 2);
+               return parentRdn;
+       }
+
        static LdapName toLdapName(String distinguishedName) {
                try {
                        return new LdapName(distinguishedName);
index af75bf03e524c7ed4b4f6d143fe74a4c6036ed1c..138eb39e9a49dc03ec7c02b7fbda001703c6e7a7 100644 (file)
@@ -79,11 +79,11 @@ public class LdapUserAdmin extends AbstractUserDirectory {
                        if (attrs.size() == 0)
                                return null;
                        int roleType = roleType(name);
-                       LdifUser res;
+                       DirectoryUser res;
                        if (roleType == Role.GROUP)
-                               res = new LdifGroup(this, name, attrs);
+                               res = newGroup( name, attrs);
                        else if (roleType == Role.USER)
-                               res = new LdifUser(this, name, attrs);
+                               res = newUser( name, attrs);
                        else
                                throw new UserDirectoryException("Unsupported LDAP type for " + name);
                        return res;
@@ -113,13 +113,13 @@ public class LdapUserAdmin extends AbstractUserDirectory {
                                Attributes attrs = searchResult.getAttributes();
                                Attribute objectClassAttr = attrs.get(objectClass.name());
                                LdapName dn = toDn(searchBase, searchResult);
-                               LdifUser role;
+                               DirectoryUser role;
                                if (objectClassAttr.contains(getGroupObjectClass())
                                                || objectClassAttr.contains(getGroupObjectClass().toLowerCase()))
-                                       role = new LdifGroup(this, dn, attrs);
+                                       role = newGroup( dn, attrs);
                                else if (objectClassAttr.contains(getUserObjectClass())
                                                || objectClassAttr.contains(getUserObjectClass().toLowerCase()))
-                                       role = new LdifUser(this, dn, attrs);
+                                       role = newUser( dn, attrs);
                                else {
 //                                     log.warn("Unsupported LDAP type for " + searchResult.getName());
                                        continue results;
index f4e558348194c0ae336bf11c11370bc2deca3cbf..b7167ea134684bacf63b25618446e8b198db27a5 100644 (file)
@@ -12,7 +12,7 @@ import javax.naming.ldap.LdapName;
 import org.osgi.service.useradmin.Role;
 
 /** Directory group implementation */
-class LdifGroup extends LdifUser implements DirectoryGroup {
+abstract class LdifGroup extends LdifUser implements DirectoryGroup {
        private final String memberAttributeId;
 
        LdifGroup(AbstractUserDirectory userAdmin, LdapName dn, Attributes attributes) {
@@ -121,4 +121,31 @@ class LdifGroup extends LdifUser implements DirectoryGroup {
        public int getType() {
                return GROUP;
        }
+
+       /*
+        * KIND
+        */
+       static class LdifFunctionalGroup extends LdifGroup implements FunctionalGroup {
+
+               public LdifFunctionalGroup(AbstractUserDirectory userAdmin, LdapName dn, Attributes attributes) {
+                       super(userAdmin, dn, attributes);
+               }
+
+       }
+
+       static class LdifOrganization extends LdifGroup implements Organization {
+
+               public LdifOrganization(AbstractUserDirectory userAdmin, LdapName dn, Attributes attributes) {
+                       super(userAdmin, dn, attributes);
+               }
+
+       }
+
+       static class LdifSystemPermissions extends LdifGroup implements SystemPermissions {
+
+               public LdifSystemPermissions(AbstractUserDirectory userAdmin, LdapName dn, Attributes attributes) {
+                       super(userAdmin, dn, attributes);
+               }
+
+       }
 }
index 271f236115d330911e34974252e6ebbd9dc2028e..b4813e685b5b457ab65bdf6ffc488187f999479a 100644 (file)
@@ -2,11 +2,11 @@ package org.argeo.osgi.useradmin;
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 import java.util.Objects;
 
 import javax.naming.directory.Attributes;
 import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
 
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.service.useradmin.Role;
@@ -16,20 +16,22 @@ class LdifHierarchyUnit implements HierarchyUnit {
        private final AbstractUserDirectory directory;
 
        private final LdapName dn;
-       private final int type;
+       private final boolean functional;
        private final Attributes attributes;
 
        HierarchyUnit parent;
        List<HierarchyUnit> children = new ArrayList<>();
 
-       LdifHierarchyUnit(AbstractUserDirectory directory, LdapName dn, int type, Attributes attributes) {
+       LdifHierarchyUnit(AbstractUserDirectory directory, LdapName dn, Attributes attributes) {
                Objects.requireNonNull(directory);
                Objects.requireNonNull(dn);
 
                this.directory = directory;
                this.dn = dn;
-               this.type = type;
                this.attributes = attributes;
+
+               Rdn rdn = LdapNameUtils.getLastRdn(dn);
+               functional = !(directory.getUserBaseRdn().equals(rdn) || directory.getGroupBaseRdn().equals(rdn));
        }
 
        @Override
@@ -43,8 +45,18 @@ class LdifHierarchyUnit implements HierarchyUnit {
        }
 
        @Override
-       public int getHierarchyUnitType() {
-               return type;
+       public Iterable<HierarchyUnit> getFunctionalHierachyUnits() {
+               List<HierarchyUnit> res = new ArrayList<>();
+               for (HierarchyUnit hu : children) {
+                       if (hu.isFunctional())
+                               res.add(hu);
+               }
+               return res;
+       }
+
+       @Override
+       public boolean isFunctional() {
+               return functional;
        }
 
        @Override
index 1eb4067d7a036e4bc1bd2cd372c74a87e70d565c..c4c02a748f8e0eb4130eb9da2cc9bbce4ab70496 100644 (file)
@@ -10,10 +10,8 @@ import java.util.Base64;
 import java.util.Collections;
 import java.util.Dictionary;
 import java.util.Enumeration;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Set;
 import java.util.StringJoiner;
 
 import javax.naming.NamingEnumeration;
@@ -29,7 +27,7 @@ import org.argeo.util.naming.LdapObjs;
 import org.argeo.util.naming.SharedSecret;
 
 /** Directory user implementation */
-class LdifUser implements DirectoryUser {
+abstract class LdifUser implements DirectoryUser {
        private final AbstractUserDirectory userAdmin;
 
        private final LdapName dn;
@@ -209,9 +207,9 @@ class LdifUser implements DirectoryUser {
                publishedAttributes = modifiedAttributes;
        }
 
-       public DirectoryUser getPublished() {
-               return new LdifUser(userAdmin, dn, publishedAttributes, true);
-       }
+//     public DirectoryUser getPublished() {
+//             return new LdifUser(userAdmin, dn, publishedAttributes, true);
+//     }
 
        @Override
        public int hashCode() {
@@ -429,4 +427,11 @@ class LdifUser implements DirectoryUser {
                return ch >= 32 && ch < 127;
        }
 
+       static class LdifPerson extends LdifUser implements Person {
+
+               public LdifPerson(AbstractUserDirectory userAdmin, LdapName dn, Attributes attributes) {
+                       super(userAdmin, dn, attributes);
+               }
+
+       }
 }
index 90b64b257a337ce9fa7cfc6f89ea8bae78542199..224be18703b583c018422de11b6ea2276af5c816 100644 (file)
@@ -15,7 +15,6 @@ import java.util.Collections;
 import java.util.Dictionary;
 import java.util.HashSet;
 import java.util.Hashtable;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
@@ -157,10 +156,10 @@ public class LdifUserAdmin extends AbstractUserDirectory {
                                        String objectClass = objectClasses.next().toString();
                                        // System.out.println(" " + objectClass);
                                        if (objectClass.toLowerCase().equals(inetOrgPerson.name().toLowerCase())) {
-                                               users.put(key, new LdifUser(this, key, attributes));
+                                               users.put(key, newUser(key, attributes));
                                                break objectClasses;
                                        } else if (objectClass.toLowerCase().equals(getGroupObjectClass().toLowerCase())) {
-                                               groups.put(key, new LdifGroup(this, key, attributes));
+                                               groups.put(key, newGroup(key, attributes));
                                                break objectClasses;
 //                                     } else if (objectClass.equalsIgnoreCase(LdapObjs.organization.name())) {
 //                                             // we only consider organizations which are not groups
@@ -171,7 +170,7 @@ public class LdifUserAdmin extends AbstractUserDirectory {
 //                                             if (getUserBase().equalsIgnoreCase(name) || getGroupBase().equalsIgnoreCase(name))
 //                                                     break objectClasses; // skip
                                                // TODO skip if it does not contain groups or users
-                                               hierarchy.put(key, new LdifHierarchyUnit(this, key, HierarchyUnit.OU, attributes));
+                                               hierarchy.put(key, new LdifHierarchyUnit(this, key, attributes));
                                                break objectClasses;
                                        }
                                }
@@ -330,8 +329,18 @@ public class LdifUserAdmin extends AbstractUserDirectory {
        }
 
        @Override
-       public Iterable<HierarchyUnit> getRootHierarchyUnits() {
-               return rootHierarchyUnits;
+       public Iterable<HierarchyUnit> getRootHierarchyUnits(boolean functionalOnly) {
+               if (functionalOnly) {
+                       List<HierarchyUnit> res = new ArrayList<>();
+                       for (HierarchyUnit hu : rootHierarchyUnits) {
+                               if (hu.isFunctional())
+                                       res.add(hu);
+                       }
+                       return res;
+
+               } else {
+                       return rootHierarchyUnits;
+               }
        }
 
        @Override
diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/Organization.java b/org.argeo.util/src/org/argeo/osgi/useradmin/Organization.java
new file mode 100644 (file)
index 0000000..85b1280
--- /dev/null
@@ -0,0 +1,5 @@
+package org.argeo.osgi.useradmin;
+
+public interface Organization {
+
+}
index 68f2eabcd142cbfd181e80c05a084171a922465d..329da91499165170ebb043dcf53cf938b6f20192 100644 (file)
@@ -18,7 +18,7 @@ import org.osgi.service.useradmin.User;
 public class OsUserDirectory extends AbstractUserDirectory {
        private final String osUsername = System.getProperty("user.name");
        private final LdapName osUserDn;
-       private final LdifUser osUser;
+       private final DirectoryUser osUser;
 
        public OsUserDirectory(URI uriArg, Dictionary<String, ?> props) {
                super(uriArg, props, false);
@@ -26,7 +26,7 @@ public class OsUserDirectory extends AbstractUserDirectory {
                        osUserDn = new LdapName(LdapAttrs.uid.name() + "=" + osUsername + "," + getUserBase() + "," + getBaseDn());
                        Attributes attributes = new BasicAttributes();
                        attributes.put(LdapAttrs.uid.name(), osUsername);
-                       osUser = new LdifUser(this, osUserDn, attributes);
+                       osUser = newUser(osUserDn, attributes);
                } catch (NamingException e) {
                        throw new UserDirectoryException("Cannot create system user", e);
                }
diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/Person.java b/org.argeo.util/src/org/argeo/osgi/useradmin/Person.java
new file mode 100644 (file)
index 0000000..8f6980b
--- /dev/null
@@ -0,0 +1,5 @@
+package org.argeo.osgi.useradmin;
+
+public interface Person {
+
+}
diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/SystemPermissions.java b/org.argeo.util/src/org/argeo/osgi/useradmin/SystemPermissions.java
new file mode 100644 (file)
index 0000000..c386a41
--- /dev/null
@@ -0,0 +1,5 @@
+package org.argeo.osgi.useradmin;
+
+public interface SystemPermissions {
+
+}
index 3800b75489f92418120e26a2074a757f31f10342..727d9295da9e61fbb5d54e6b46e58327d31d4b25 100644 (file)
@@ -27,15 +27,15 @@ public interface UserDirectory {
 
        String getUserObjectClass();
 
-       String getUserBase();
+//     String getUserBase();
 
        String getGroupObjectClass();
 
-       String getGroupBase();
+//     String getGroupBase();
 
        Optional<String> getRealm();
 
-       Iterable<HierarchyUnit> getRootHierarchyUnits();
+       Iterable<HierarchyUnit> getRootHierarchyUnits(boolean functionalOnly);
 
        HierarchyUnit getHierarchyUnit(String path);