Simplify hierarchy units
authorMathieu Baudier <mbaudier@argeo.org>
Mon, 20 Jun 2022 08:32:09 +0000 (10:32 +0200)
committerMathieu Baudier <mbaudier@argeo.org>
Mon, 20 Jun 2022 08:32:09 +0000 (10:32 +0200)
17 files changed:
eclipse/org.argeo.cms.e4/src/org/argeo/cms/e4/users/UserAdminWrapper.java
org.argeo.cms/src/org/argeo/cms/acr/ContentUtils.java
org.argeo.cms/src/org/argeo/cms/acr/directory/DirectoryContent.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/acr/directory/DirectoryContentProvider.java
org.argeo.cms/src/org/argeo/cms/acr/directory/HierarchyUnitContent.java
org.argeo.cms/src/org/argeo/cms/acr/directory/RoleContent.java
org.argeo.cms/src/org/argeo/cms/internal/auth/CmsUserManagerImpl.java
org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsUserAdmin.java
org.argeo.util/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java
org.argeo.util/src/org/argeo/osgi/useradmin/AggregatingUserAdmin.java
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/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/UserDirectory.java
org.argeo.util/src/org/argeo/util/LangUtils.java

index 465c15a17be6199487d90b7e7e95a9c5c9582ad3..dbbd970a78d84ba98fd06ffc4644fd2a56d5dbdb 100644 (file)
@@ -91,7 +91,7 @@ public class UserAdminWrapper {
                Map<String, String> dns = new HashMap<String, String>();
                for (UserDirectory userDirectory : userDirectories.keySet()) {
                        Boolean readOnly = userDirectory.isReadOnly();
-                       String baseDn = userDirectory.getBasePath();
+                       String baseDn = userDirectory.getGlobalId();
 
                        if (onlyWritable && readOnly)
                                continue;
index 272a5c5a148d3f51b3315fad79918e4837aed3c9..eeec4fcfc9aa66ac537560581db37d6392194768 100644 (file)
@@ -3,6 +3,7 @@ package org.argeo.cms.acr;
 import java.io.PrintStream;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.StringJoiner;
 import java.util.function.BiConsumer;
 
 import javax.xml.namespace.QName;
@@ -78,6 +79,13 @@ public class ContentUtils {
                                path.substring(parentIndex + 1) };
        }
 
+       public static String toPath(List<String> segments) {
+               // TODO checks
+               StringJoiner sj = new StringJoiner("/");
+               segments.forEach((s) -> sj.add(s));
+               return sj.toString();
+       }
+
        public static List<String> toPathSegments(String path) {
                List<String> res = new ArrayList<>();
                if ("".equals(path) || ROOT_SLASH.equals(path))
diff --git a/org.argeo.cms/src/org/argeo/cms/acr/directory/DirectoryContent.java b/org.argeo.cms/src/org/argeo/cms/acr/directory/DirectoryContent.java
new file mode 100644 (file)
index 0000000..b0c1b6b
--- /dev/null
@@ -0,0 +1,51 @@
+package org.argeo.cms.acr.directory;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.namespace.QName;
+
+import org.argeo.api.acr.Content;
+import org.argeo.api.acr.ContentName;
+import org.argeo.api.acr.spi.ContentProvider;
+import org.argeo.api.acr.spi.ProvidedSession;
+import org.argeo.cms.acr.AbstractContent;
+import org.argeo.osgi.useradmin.HierarchyUnit;
+import org.argeo.osgi.useradmin.UserDirectory;
+
+class DirectoryContent extends AbstractContent {
+       private UserDirectory directory;
+       private DirectoryContentProvider provider;
+
+       public DirectoryContent(ProvidedSession session, DirectoryContentProvider provider, UserDirectory directory) {
+               super(session);
+               this.provider = provider;
+               this.directory = directory;
+       }
+
+       @Override
+       public ContentProvider getProvider() {
+               return provider;
+       }
+
+       @Override
+       public Iterator<Content> iterator() {
+               List<Content> res = new ArrayList<>();
+               for (Iterator<HierarchyUnit> it = directory.getRootHierarchyUnits().iterator(); it.hasNext();) {
+                       res.add(new HierarchyUnitContent(getSession(), provider, it.next()));
+               }
+               return res.iterator();
+       }
+
+       @Override
+       public QName getName() {
+               return new ContentName(directory.getName());
+       }
+
+       @Override
+       public Content getParent() {
+               return provider.getRootContent(getSession());
+       }
+
+}
index 60ef67551a17109528ff7a9d42cbe49f6e72f70a..c1ded945a61b9ac29b0f97f631b47e25c889e9ff 100644 (file)
@@ -5,8 +5,6 @@ import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 
-import javax.naming.InvalidNameException;
-import javax.naming.ldap.LdapName;
 import javax.xml.namespace.QName;
 
 import org.argeo.api.acr.Content;
@@ -20,7 +18,6 @@ import org.argeo.cms.CmsUserManager;
 import org.argeo.cms.acr.AbstractContent;
 import org.argeo.cms.acr.ContentUtils;
 import org.argeo.osgi.useradmin.HierarchyUnit;
-import org.argeo.osgi.useradmin.LdapNameUtils;
 import org.argeo.osgi.useradmin.UserDirectory;
 import org.osgi.service.useradmin.User;
 
@@ -45,7 +42,7 @@ public class DirectoryContentProvider implements ContentProvider {
                String userDirectoryDn = segments.get(0);
                UserDirectory userDirectory = null;
                userDirectories: for (UserDirectory ud : userManager.getUserDirectories()) {
-                       if (userDirectoryDn.equals(ud.getBasePath())) {
+                       if (userDirectoryDn.equals(ud.getGlobalId())) {
                                userDirectory = ud;
                                break userDirectories;
                        }
@@ -53,25 +50,29 @@ public class DirectoryContentProvider implements ContentProvider {
                if (userDirectory == null)
                        throw new ContentNotFoundException("Cannot find user directory " + userDirectoryDn);
                if (segments.size() == 1) {
-                       return new HierarchyUnitContent(session, this, userDirectory);
+                       return new DirectoryContent(session, this, userDirectory);
                } else {
-                       LdapName dn;
-                       try {
-                               dn = LdapNameUtils.toLdapName(userDirectoryDn);
-                               for (int i = 1; i < segments.size(); i++) {
-                                       dn.add(segments.get(i));
-                               }
-                       } catch (InvalidNameException e) {
-                               throw new IllegalStateException("Cannot interpret " + segments + " as DN", e);
-                       }
-                       User user = userManager.getUser(dn.toString());
+                       List<String> relSegments = new ArrayList<>(segments);
+                       relSegments.remove(0);
+                       String pathWithinUserDirectory = ContentUtils.toPath(relSegments);
+//                     LdapName dn;
+//                     try {
+//                             dn = LdapNameUtils.toLdapName(userDirectoryDn);
+//                             for (int i = 1; i < segments.size(); i++) {
+//                                     dn.add(segments.get(i));
+//                             }
+//                     } catch (InvalidNameException e) {
+//                             throw new IllegalStateException("Cannot interpret " + segments + " as DN", e);
+//                     }
+                       User user = (User) userDirectory.getRoleByPath(pathWithinUserDirectory);
                        if (user != null) {
                                HierarchyUnit parent = userDirectory.getHierarchyUnit(user);
                                return new RoleContent(session, this, new HierarchyUnitContent(session, this, parent), user);
                        }
-                       HierarchyUnit hierarchyUnit = userDirectory.getHierarchyUnit(dn.toString());
+                       HierarchyUnit hierarchyUnit = userDirectory.getHierarchyUnit(pathWithinUserDirectory);
                        if (hierarchyUnit == null)
-                               throw new ContentNotFoundException("Cannot find " + dn);
+                               throw new ContentNotFoundException(
+                                               "Cannot find " + pathWithinUserDirectory + " within " + userDirectoryDn);
                        return new HierarchyUnitContent(session, this, hierarchyUnit);
                }
        }
@@ -104,7 +105,7 @@ public class DirectoryContentProvider implements ContentProvider {
        public void setUserManager(CmsUserManager userManager) {
                this.userManager = userManager;
        }
-       
+
        UserManagerContent getRootContent(ProvidedSession session) {
                return new UserManagerContent(session);
        }
@@ -134,7 +135,7 @@ public class DirectoryContentProvider implements ContentProvider {
                public Iterator<Content> iterator() {
                        List<Content> res = new ArrayList<>();
                        for (UserDirectory userDirectory : userManager.getUserDirectories()) {
-                               HierarchyUnitContent content = new HierarchyUnitContent(getSession(), DirectoryContentProvider.this,
+                               DirectoryContent content = new DirectoryContent(getSession(), DirectoryContentProvider.this,
                                                userDirectory);
                                res.add(content);
                        }
index 9184c63afbb23fb53e9fdf7f0d6204720f5ffff6..5ec57c51f859297b8553c31b1852d79edc7d2838 100644 (file)
@@ -16,7 +16,7 @@ import org.argeo.cms.acr.AbstractContent;
 import org.argeo.osgi.useradmin.HierarchyUnit;
 import org.osgi.service.useradmin.Role;
 
-public class HierarchyUnitContent extends AbstractContent {
+class HierarchyUnitContent extends AbstractContent {
        private HierarchyUnit hierarchyUnit;
 
        private DirectoryContentProvider provider;
@@ -36,10 +36,10 @@ public class HierarchyUnitContent extends AbstractContent {
 
        @Override
        public QName getName() {
-               if (hierarchyUnit.getParent() == null) {// base DN
-                       String baseDn = hierarchyUnit.getBasePath();
-                       return new ContentName(baseDn);
-               }
+//             if (hierarchyUnit.getParent() == null) {// base DN
+//                     String baseDn = hierarchyUnit.getBasePath();
+//                     return new ContentName(baseDn);
+//             }
                String name = hierarchyUnit.getHierarchyUnitName();
                return new ContentName(name);
        }
@@ -48,7 +48,7 @@ public class HierarchyUnitContent extends AbstractContent {
        public Content getParent() {
                HierarchyUnit parentHu = hierarchyUnit.getParent();
                if (parentHu == null) {
-                       return provider.getRootContent(getSession());
+                       return new DirectoryContent(getSession(), provider, hierarchyUnit.getDirectory());
                }
                return new HierarchyUnitContent(getSession(), provider, parentHu);
        }
@@ -56,10 +56,10 @@ public class HierarchyUnitContent extends AbstractContent {
        @Override
        public Iterator<Content> iterator() {
                List<Content> lst = new ArrayList<>();
-               for (int i = 0; i < hierarchyUnit.getHierarchyChildCount(); i++)
-                       lst.add(new HierarchyUnitContent(getSession(), provider, hierarchyUnit.getHierarchyChild(i)));
+               for (HierarchyUnit hu : hierarchyUnit.getDirectHierachyUnits())
+                       lst.add(new HierarchyUnitContent(getSession(), provider, hu));
 
-               for (Role role : hierarchyUnit.getRoles(null, false))
+               for (Role role : hierarchyUnit.getHierarchyUnitRoles(null, false))
                        lst.add(new RoleContent(getSession(), provider, this, role));
                return lst.iterator();
        }
@@ -75,4 +75,12 @@ public class HierarchyUnitContent extends AbstractContent {
                return res;
        }
 
+       /*
+        * ACCESSOR
+        */
+       HierarchyUnit getHierarchyUnit() {
+               return hierarchyUnit;
+       }
+
+       
 }
index 8043205ec4371df0d2e6308434b1ee0a9db985c1..344dede76d52c7a1ddce15c02c2a601a4828ec8a 100644 (file)
@@ -7,7 +7,6 @@ import java.util.Optional;
 import java.util.Set;
 import java.util.TreeSet;
 
-import javax.naming.ldap.LdapName;
 import javax.swing.GroupLayout.Group;
 import javax.xml.namespace.QName;
 
@@ -18,13 +17,12 @@ import org.argeo.api.acr.NamespaceUtils;
 import org.argeo.api.acr.spi.ContentProvider;
 import org.argeo.api.acr.spi.ProvidedSession;
 import org.argeo.cms.acr.AbstractContent;
-import org.argeo.osgi.useradmin.LdapNameUtils;
 import org.argeo.util.naming.LdapAttrs;
 import org.argeo.util.naming.LdapObjs;
 import org.osgi.service.useradmin.Role;
 import org.osgi.service.useradmin.User;
 
-public class RoleContent extends AbstractContent {
+class RoleContent extends AbstractContent {
 
        private DirectoryContentProvider provider;
        private HierarchyUnitContent parent;
@@ -45,8 +43,7 @@ public class RoleContent extends AbstractContent {
 
        @Override
        public QName getName() {
-               LdapName dn = LdapNameUtils.toLdapName(role.getName());
-               String name = LdapNameUtils.getLastRdnAsString(dn);
+               String name = parent.getHierarchyUnit().getDirectory().getRoleSimpleName(role);
                return new ContentName(name);
        }
 
index 135bf50c8ebac917827a31c8405d719dccc4e71d..e6a305685e4920115e63478b6e3c4b623a4663ea 100644 (file)
@@ -232,7 +232,7 @@ public class CmsUserManagerImpl implements CmsUserManager {
                Map<String, String> dns = new HashMap<String, String>();
                for (UserDirectory userDirectory : userDirectories.keySet()) {
                        Boolean readOnly = userDirectory.isReadOnly();
-                       String baseDn = userDirectory.getBasePath();
+                       String baseDn = userDirectory.getGlobalId();
 
                        if (onlyWritable && readOnly)
                                continue;
@@ -247,7 +247,7 @@ public class CmsUserManagerImpl implements CmsUserManager {
        }
 
        public Set<UserDirectory> getUserDirectories() {
-               TreeSet<UserDirectory> res = new TreeSet<>((o1, o2) -> o1.getBasePath().compareTo(o2.getBasePath()));
+               TreeSet<UserDirectory> res = new TreeSet<>((o1, o2) -> o1.getGlobalId().compareTo(o2.getGlobalId()));
                res.addAll(userDirectories.keySet());
                return res;
        }
@@ -445,8 +445,8 @@ public class CmsUserManagerImpl implements CmsUserManager {
                String name = user.getName();
                NavigableMap<String, UserDirectory> possible = new TreeMap<>();
                for (UserDirectory userDirectory : userDirectories.keySet()) {
-                       if (name.endsWith(userDirectory.getBasePath())) {
-                               possible.put(userDirectory.getBasePath(), userDirectory);
+                       if (name.endsWith(userDirectory.getGlobalId())) {
+                               possible.put(userDirectory.getGlobalId(), userDirectory);
                        }
                }
                if (possible.size() == 0)
index 391c94a3da1c3011b06846b34727b4da4001891e..49e55f16c5f0b6ac2e44aa9bcc122a1ace2f451c 100644 (file)
@@ -107,14 +107,14 @@ public class CmsUserAdmin extends AggregatingUserAdmin {
                } else {
                        throw new IllegalArgumentException("Unsupported scheme " + u.getScheme());
                }
-               String basePath = userDirectory.getBasePath();
+               String basePath = userDirectory.getGlobalId();
 
                addUserDirectory(userDirectory);
                if (isSystemRolesBaseDn(basePath)) {
                        addStandardSystemRoles();
                }
                if (log.isDebugEnabled()) {
-                       log.debug("User directory " + userDirectory.getBasePath() + (u != null ? " [" + u.getScheme() + "]" : "")
+                       log.debug("User directory " + userDirectory.getGlobalId() + (u != null ? " [" + u.getScheme() + "]" : "")
                                        + " enabled." + (realm != null ? " " + realm + " realm." : ""));
                }
                return userDirectory;
index 889f9cfa79fd3829bf4ab6ed6aee79b09626fc7b..27662938faf84682c56bfec8f50f0f6c416694e0 100644 (file)
@@ -18,6 +18,7 @@ import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Optional;
+import java.util.StringJoiner;
 
 import javax.naming.InvalidNameException;
 import javax.naming.NameNotFoundException;
@@ -104,12 +105,16 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory {
                        throw new IllegalArgumentException("Badly formated base DN " + UserAdminConf.baseDn.getValue(properties),
                                        e);
                }
+
+               // read only
                String readOnlyStr = UserAdminConf.readOnly.getValue(properties);
                if (readOnlyStr == null) {
                        readOnly = readOnlyDefault(uri);
                        properties.put(UserAdminConf.readOnly.name(), Boolean.toString(readOnly));
                } else
                        readOnly = Boolean.parseBoolean(readOnlyStr);
+
+               // disabled
                String disabledStr = UserAdminConf.disabled.getValue(properties);
                if (disabledStr != null)
                        disabled = Boolean.parseBoolean(disabledStr);
@@ -136,11 +141,77 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory {
 
        }
 
+       /*
+        * PATHS
+        */
+
        @Override
-       public String getBasePath() {
+       public String getGlobalId() {
                return getBaseDn().toString();
        }
 
+       @Override
+       public String getName() {
+               return nameToSimple(getBaseDn(), ".");
+       }
+
+       @Override
+       public String getRolePath(Role role) {
+               return nameToRelativePath(((DirectoryUser) role).getDn());
+       }
+
+       @Override
+       public String getRoleSimpleName(Role role) {
+               LdapName dn = LdapNameUtils.toLdapName(role.getName());
+               String name = LdapNameUtils.getLastRdnValue(dn);
+               return name;
+       }
+
+       protected String nameToRelativePath(LdapName dn) {
+               LdapName name = LdapNameUtils.relativeName(getBaseDn(), dn);
+               return nameToSimple(name, "/");
+       }
+
+       protected String nameToSimple(LdapName name, String separator) {
+               StringJoiner path = new StringJoiner(separator);
+               for (int i = 0; i < name.size(); i++) {
+                       path.add(name.getRdn(i).getValue().toString());
+               }
+               return path.toString();
+
+       }
+
+       protected LdapName pathToName(String path) {
+               try {
+                       LdapName name = (LdapName) getBaseDn().clone();
+                       String[] segments = path.split("/");
+                       String parentSegment = null;
+                       for (String segment : segments) {
+                               String attr = "ou";
+                               if (parentSegment != null) {
+                                       if (getUserBase().equals(parentSegment))
+                                               attr = "uid";
+                                       else if (getGroupBase().equals(parentSegment))
+                                               attr = "cn";
+                               }
+                               Rdn rdn = new Rdn(attr, segment);
+                               name.add(rdn);
+
+                               // TODO make it more robust using RDNs
+                               parentSegment = rdn.toString();
+                       }
+                       return name;
+               } catch (InvalidNameException e) {
+                       throw new IllegalStateException("Cannot get role " + path, e);
+               }
+
+       }
+
+       @Override
+       public Role getRoleByPath(String path) {
+               return doGetRole(pathToName(path));
+       }
+
        @Override
        public Optional<String> getRealm() {
                Object realm = getProperties().get(UserAdminConf.realm.name());
@@ -149,6 +220,10 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory {
                return Optional.of(realm.toString());
        }
 
+       /*
+        * EDITION
+        */
+
        protected boolean isEditing() {
                return xaResource.wc() != null;
        }
@@ -240,23 +315,6 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory {
 
        @Override
        public Role[] getRoles(String filter) throws InvalidSyntaxException {
-//             UserDirectoryWorkingCopy wc = getWorkingCopy();
-//             Filter f = filter != null ? FrameworkUtil.createFilter(filter) : null;
-//             List<DirectoryUser> res = doGetRoles(getBaseDn(), f, true);
-//             if (wc != null) {
-//                     for (Iterator<DirectoryUser> it = res.iterator(); it.hasNext();) {
-//                             DirectoryUser user = it.next();
-//                             LdapName dn = user.getDn();
-//                             if (wc.getDeletedUsers().containsKey(dn))
-//                                     it.remove();
-//                     }
-//                     for (DirectoryUser user : wc.getNewUsers().values()) {
-//                             if (f == null || f.match(user.getProperties()))
-//                                     res.add(user);
-//                     }
-//                     // no need to check modified users,
-//                     // since doGetRoles was already based on the modified attributes
-//             }
                List<? extends Role> res = getRoles(getBaseDn(), filter, true);
                return res.toArray(new Role[res.size()]);
        }
@@ -281,19 +339,19 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory {
                }
 
                // if non deep we also search users and groups
-               if (!deep) {
-                       try {
-                               if (!(searchBase.endsWith(new LdapName(getUserBase()))
-                                               || searchBase.endsWith(new LdapName(getGroupBase())))) {
-                                       LdapName usersBase = (LdapName) ((LdapName) searchBase.clone()).add(getUserBase());
-                                       res.addAll(getRoles(usersBase, filter, false));
-                                       LdapName groupsBase = (LdapName) ((LdapName) searchBase.clone()).add(getGroupBase());
-                                       res.addAll(getRoles(groupsBase, filter, false));
-                               }
-                       } catch (InvalidNameException e) {
-                               throw new IllegalStateException("Cannot search users and groups", e);
-                       }
-               }
+//             if (!deep) {
+//                     try {
+//                             if (!(searchBase.endsWith(new LdapName(getUserBase()))
+//                                             || searchBase.endsWith(new LdapName(getGroupBase())))) {
+//                                     LdapName usersBase = (LdapName) ((LdapName) searchBase.clone()).add(getUserBase());
+//                                     res.addAll(getRoles(usersBase, filter, false));
+//                                     LdapName groupsBase = (LdapName) ((LdapName) searchBase.clone()).add(getGroupBase());
+//                                     res.addAll(getRoles(groupsBase, filter, false));
+//                             }
+//                     } catch (InvalidNameException e) {
+//                             throw new IllegalStateException("Cannot search users and groups", e);
+//                     }
+//             }
                return res;
        }
 
@@ -434,50 +492,55 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory {
        /*
         * HIERARCHY
         */
-       @Override
-       public int getHierarchyChildCount() {
-               return 0;
-       }
-
-       @Override
-       public HierarchyUnit getHierarchyChild(int i) {
-               throw new IllegalArgumentException("No child hierarchy unit available");
-       }
-
-       @Override
-       public HierarchyUnit getParent() {
-               return null;
-       }
-
-       @Override
-       public int getHierarchyUnitType() {
-               return 0;
-       }
-
-       @Override
-       public String getHierarchyUnitName() {
-               String name = LdapNameUtils.getLastRdnAsString(baseDn);
-               // TODO check ou, o, etc.
-               return name;
-       }
+//     @Override
+//     public int getHierarchyChildCount() {
+//             return 0;
+//     }
+//
+//     @Override
+//     public HierarchyUnit getHierarchyChild(int i) {
+//             throw new IllegalArgumentException("No child hierarchy unit available");
+//     }
+//
+//     @Override
+//     public HierarchyUnit getParent() {
+//             return null;
+//     }
+//
+//     @Override
+//     public int getHierarchyUnitType() {
+//             return 0;
+//     }
+//
+//     @Override
+//     public String getHierarchyUnitName() {
+//             String name = LdapNameUtils.getLastRdnValue(baseDn);
+//             // TODO check ou, o, etc.
+//             return name;
+//     }
 
        @Override
        public HierarchyUnit getHierarchyUnit(String path) {
-               return null;
+               throw new UnsupportedOperationException();
        }
 
        @Override
        public HierarchyUnit getHierarchyUnit(Role role) {
-               return null;
+               throw new UnsupportedOperationException();
        }
 
+//     @Override
+//     public List<? extends Role> getHierarchyUnitRoles(String filter, boolean deep) {
+//             try {
+//                     return getRoles(getBaseDn(), filter, deep);
+//             } catch (InvalidSyntaxException e) {
+//                     throw new IllegalArgumentException("Cannot filter " + filter + " " + getBaseDn(), e);
+//             }
+//     }
+
        @Override
-       public List<? extends Role> getRoles(String filter, boolean deep) {
-               try {
-                       return getRoles(getBaseDn(), filter, deep);
-               } catch (InvalidSyntaxException e) {
-                       throw new IllegalArgumentException("Cannot filter " + filter + " " + getBaseDn(), e);
-               }
+       public Iterable<HierarchyUnit> getRootHierarchyUnits() {
+               throw new UnsupportedOperationException();
        }
 
        // GETTERS
@@ -562,7 +625,7 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory {
                return groupBase;
        }
 
-       public LdapName getBaseDn() {
+       LdapName getBaseDn() {
                return (LdapName) baseDn.clone();
        }
 
index ad6a83fb5d437d5b519c662b15623dc3523abe3e..54a6d9e315c8b2a9a99ae017e4099c25f8b8ae2f 100644 (file)
@@ -160,7 +160,7 @@ public class AggregatingUserAdmin implements UserAdmin {
                if (!(ud instanceof AbstractUserDirectory))
                        throw new IllegalArgumentException("Only " + AbstractUserDirectory.class.getName() + " is supported");
                AbstractUserDirectory userDirectory = (AbstractUserDirectory) ud;
-               String basePath = userDirectory.getBasePath();
+               String basePath = userDirectory.getGlobalId();
                if (isSystemRolesBaseDn(basePath)) {
                        this.systemRoles = userDirectory;
                        systemRoles.setExternalRoles(this);
@@ -272,7 +272,7 @@ public class AggregatingUserAdmin implements UserAdmin {
        }
 
        public Set<UserDirectory> getUserDirectories() {
-               TreeSet<UserDirectory> res = new TreeSet<>((o1, o2) -> o1.getBasePath().compareTo(o2.getBasePath()));
+               TreeSet<UserDirectory> res = new TreeSet<>((o1, o2) -> o1.getGlobalId().compareTo(o2.getGlobalId()));
                res.addAll(businessRoles.values());
                return res;
        }
index 24943463139baa20772c928bdef48acccac0aa24..9783a2786b238819330d8a2da050c81f36297c3a 100644 (file)
@@ -1,7 +1,6 @@
 package org.argeo.osgi.useradmin;
 
 import java.util.List;
-import java.util.Map;
 
 import org.osgi.service.useradmin.Role;
 
@@ -13,17 +12,17 @@ public interface HierarchyUnit {
 
        String getHierarchyUnitName();
 
-       int getHierarchyChildCount();
-
        HierarchyUnit getParent();
 
-       HierarchyUnit getHierarchyChild(int i);
+       Iterable<HierarchyUnit> getDirectHierachyUnits();
 
        int getHierarchyUnitType();
 
        String getBasePath();
 
-       List<? extends Role> getRoles(String filter, boolean deep);
-       
+       List<? extends Role> getHierarchyUnitRoles(String filter, boolean deep);
+
+       UserDirectory getDirectory();
+
 //     Map<String,Object> getHierarchyProperties();
 }
index b98c8bff7225035485392bbc9088c90b25a0b752..f76d9441b9a5613799f4bd659faa87cf2553593b 100644 (file)
@@ -1,27 +1,27 @@
 package org.argeo.osgi.useradmin;
 
-import java.util.StringJoiner;
-
 import javax.naming.InvalidNameException;
 import javax.naming.ldap.LdapName;
 import javax.naming.ldap.Rdn;
 
 /** Utilities to simplify using {@link LdapName}. */
-public class LdapNameUtils {
-
-       public static String toRevertPath(String dn, String prefix) {
-               if (!dn.endsWith(prefix))
-                       throw new IllegalArgumentException("Prefix " + prefix + " not consistent with " + dn);
-               String relativeName = dn.substring(0, dn.length() - prefix.length() - 1);
-               LdapName name = toLdapName(relativeName);
-               StringJoiner path = new StringJoiner("/");
-               for (int i = 0; i < name.size(); i++) {
-                       path.add(name.get(i));
+class LdapNameUtils {
+
+       static LdapName relativeName(LdapName prefix, LdapName dn) {
+               try {
+                       if (!dn.startsWith(prefix))
+                               throw new IllegalArgumentException("Prefix " + prefix + " not consistent with " + dn);
+                       LdapName res = (LdapName) dn.clone();
+                       for (int i = 0; i < prefix.size(); i++) {
+                               res.remove(0);
+                       }
+                       return res;
+               } catch (InvalidNameException e) {
+                       throw new IllegalStateException("Cannot find realtive name", e);
                }
-               return path.toString();
        }
 
-       public static LdapName getParent(LdapName dn) {
+       static LdapName getParent(LdapName dn) {
                try {
                        LdapName parent = (LdapName) dn.clone();
                        parent.remove(parent.size() - 1);
@@ -31,7 +31,7 @@ public class LdapNameUtils {
                }
        }
 
-       public static LdapName toLdapName(String distinguishedName) {
+       static LdapName toLdapName(String distinguishedName) {
                try {
                        return new LdapName(distinguishedName);
                } catch (InvalidNameException e) {
@@ -39,15 +39,15 @@ public class LdapNameUtils {
                }
        }
 
-       public static Rdn getLastRdn(LdapName dn) {
+       static Rdn getLastRdn(LdapName dn) {
                return dn.getRdn(dn.size() - 1);
        }
 
-       public static String getLastRdnAsString(LdapName dn) {
+       static String getLastRdnAsString(LdapName dn) {
                return getLastRdn(dn).toString();
        }
 
-       public static String getLastRdnValue(LdapName dn) {
+       static String getLastRdnValue(LdapName dn) {
                return getLastRdn(dn).getValue().toString();
        }
 
index 593416259c0fba213001d9085710169da8cb7c86..271f236115d330911e34974252e6ebbd9dc2028e 100644 (file)
@@ -32,19 +32,14 @@ class LdifHierarchyUnit implements HierarchyUnit {
                this.attributes = attributes;
        }
 
-       @Override
-       public int getHierarchyChildCount() {
-               return children.size();
-       }
-
        @Override
        public HierarchyUnit getParent() {
                return parent;
        }
 
        @Override
-       public HierarchyUnit getHierarchyChild(int i) {
-               return children.get(i);
+       public Iterable<HierarchyUnit> getDirectHierachyUnits() {
+               return children;
        }
 
        @Override
@@ -54,7 +49,7 @@ class LdifHierarchyUnit implements HierarchyUnit {
 
        @Override
        public String getHierarchyUnitName() {
-               String name = LdapNameUtils.getLastRdnAsString(dn);
+               String name = LdapNameUtils.getLastRdnValue(dn);
                // TODO check ou, o, etc.
                return name;
        }
@@ -69,7 +64,7 @@ class LdifHierarchyUnit implements HierarchyUnit {
        }
 
        @Override
-       public List<? extends Role> getRoles(String filter, boolean deep) {
+       public List<? extends Role> getHierarchyUnitRoles(String filter, boolean deep) {
                try {
                        return directory.getRoles(dn, filter, deep);
                } catch (InvalidSyntaxException e) {
@@ -77,6 +72,11 @@ class LdifHierarchyUnit implements HierarchyUnit {
                }
        }
 
+       @Override
+       public UserDirectory getDirectory() {
+               return directory;
+       }
+
        @Override
        public int hashCode() {
                return dn.hashCode();
index c03465b7058b318afecd63c689677c846ade3b4a..552bfdc8da8bfbeaac3d20c608abbb64e2d2d63d 100644 (file)
@@ -25,6 +25,7 @@ import javax.naming.ldap.LdapName;
 
 import org.argeo.util.naming.AuthPassword;
 import org.argeo.util.naming.LdapAttrs;
+import org.argeo.util.naming.LdapObjs;
 import org.argeo.util.naming.SharedSecret;
 
 /** Directory user implementation */
@@ -308,21 +309,34 @@ class LdifUser implements DirectoryUser {
                                }
                                if (attr.size() == 1)
                                        return value;
-//                             if (!attr.getID().equals(LdapAttrs.objectClass.name()))
-//                                     return value;
                                // special case for object class
-                               NamingEnumeration<?> en = attr.getAll();
-                               StringJoiner values = new StringJoiner("\n");
-                               // Set<String> values = new HashSet<String>();
-                               while (en.hasMore()) {
-                                       String v = en.next().toString();
-                                       values.add(v);
+                               if (attr.getID().equals(LdapAttrs.objectClass.name())) {
+                                       // TODO support multiple object classes
+                                       NamingEnumeration<?> en = attr.getAll();
+                                       String first = null;
+                                       attrs: while (en.hasMore()) {
+                                               String v = en.next().toString();
+                                               if (v.equalsIgnoreCase(LdapObjs.top.name()))
+                                                       continue attrs;
+                                               if (first == null)
+                                                       first = v;
+                                               if (v.equalsIgnoreCase(userAdmin.getUserObjectClass()))
+                                                       return userAdmin.getUserObjectClass();
+                                               else if (v.equalsIgnoreCase(userAdmin.getGroupObjectClass()))
+                                                       return userAdmin.getGroupObjectClass();
+                                       }
+                                       if (first != null)
+                                               return first;
+                                       throw new IllegalStateException("Cannot find objectClass in " + value);
+                               } else {
+                                       NamingEnumeration<?> en = attr.getAll();
+                                       StringJoiner values = new StringJoiner("\n");
+                                       while (en.hasMore()) {
+                                               String v = en.next().toString();
+                                               values.add(v);
+                                       }
+                                       return values.toString();
                                }
-                               return values.toString();
-//                             if (objectClasses.contains(userAdmin.getUserObjectClass()))
-//                                     return userAdmin.getUserObjectClass();
-//                             else if (objectClasses.contains(userAdmin.getGroupObjectClass()))
-//                                     return userAdmin.getGroupObjectClass();
 //                             else
 //                                     return value;
                        } catch (NamingException e) {
index 6d9305a176e29e5e9edab2e40ba93f0e5713a7a0..90b64b257a337ce9fa7cfc6f89ea8bae78542199 100644 (file)
@@ -15,6 +15,7 @@ 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;
@@ -161,14 +162,14 @@ public class LdifUserAdmin extends AbstractUserDirectory {
                                        } else if (objectClass.toLowerCase().equals(getGroupObjectClass().toLowerCase())) {
                                                groups.put(key, new LdifGroup(this, key, attributes));
                                                break objectClasses;
-                                       } else if (objectClass.equalsIgnoreCase(LdapObjs.organization.name())) {
-                                               // we only consider organizations which are not groups
-                                               hierarchy.put(key, new LdifHierarchyUnit(this, key, HierarchyUnit.ORGANIZATION, attributes));
-                                               break objectClasses;
+//                                     } else if (objectClass.equalsIgnoreCase(LdapObjs.organization.name())) {
+//                                             // we only consider organizations which are not groups
+//                                             hierarchy.put(key, new LdifHierarchyUnit(this, key, HierarchyUnit.ORGANIZATION, attributes));
+//                                             break objectClasses;
                                        } else if (objectClass.equalsIgnoreCase(LdapObjs.organizationalUnit.name())) {
-                                               String name = key.getRdn(key.size() - 1).toString();
-                                               if (getUserBase().equalsIgnoreCase(name) || getGroupBase().equalsIgnoreCase(name))
-                                                       break objectClasses; // skip
+//                                             String name = key.getRdn(key.size() - 1).toString();
+//                                             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));
                                                break objectClasses;
@@ -183,7 +184,7 @@ public class LdifUserAdmin extends AbstractUserDirectory {
                                LdifHierarchyUnit parent = hierarchy.get(parentDn);
                                if (parent == null) {
                                        rootHierarchyUnits.add(unit);
-                                       unit.parent = this;
+                                       unit.parent = null;
                                        continue hierachyUnits;
                                }
                                parent.children.add(unit);
@@ -311,27 +312,32 @@ public class LdifUserAdmin extends AbstractUserDirectory {
        /*
         * HIERARCHY
         */
-       @Override
-       public int getHierarchyChildCount() {
-               return rootHierarchyUnits.size();
-       }
 
-       @Override
-       public HierarchyUnit getHierarchyChild(int i) {
-               return rootHierarchyUnits.get(i);
-       }
+//     @Override
+//     public int getHierarchyChildCount() {
+//             return rootHierarchyUnits.size();
+//     }
+//
+//     @Override
+//     public HierarchyUnit getHierarchyChild(int i) {
+//             return rootHierarchyUnits.get(i);
+//     }
 
        @Override
        public HierarchyUnit getHierarchyUnit(String path) {
-               LdapName dn = LdapNameUtils.toLdapName(path);
+               LdapName dn = pathToName(path);
                return hierarchy.get(dn);
        }
 
+       @Override
+       public Iterable<HierarchyUnit> getRootHierarchyUnits() {
+               return rootHierarchyUnits;
+       }
+
        @Override
        public HierarchyUnit getHierarchyUnit(Role role) {
                LdapName dn = LdapNameUtils.toLdapName(role.getName());
-               // 2 levels
-               LdapName huDn = LdapNameUtils.getParent(LdapNameUtils.getParent(dn));
+               LdapName huDn = LdapNameUtils.getParent(dn);
                HierarchyUnit hierarchyUnit = hierarchy.get(huDn);
                if (hierarchyUnit == null)
                        throw new IllegalStateException("No hierarchy unit found for " + role);
index 781b7855a34c08b973d49fd0be9273b7d07cddc4..3800b75489f92418120e26a2074a757f31f10342 100644 (file)
@@ -6,12 +6,14 @@ import org.argeo.osgi.transaction.WorkControl;
 import org.osgi.service.useradmin.Role;
 
 /** Information about a user directory. */
-public interface UserDirectory extends HierarchyUnit {
+public interface UserDirectory {
        /**
         * The base of the hierarchy defined by this directory. This could typically be
         * an LDAP base DN.
         */
-       String getBasePath();
+       String getGlobalId();
+       
+       String getName();
 
 //     /** The base DN of all entries in this user directory */
 //     LdapName getBaseDn();
@@ -33,10 +35,18 @@ public interface UserDirectory extends HierarchyUnit {
 
        Optional<String> getRealm();
 
+       Iterable<HierarchyUnit> getRootHierarchyUnits();
+
        HierarchyUnit getHierarchyUnit(String path);
 
        HierarchyUnit getHierarchyUnit(Role role);
 
+       String getRolePath(Role role);
+
+       String getRoleSimpleName(Role role);
+
+       Role getRoleByPath(String path);
+
        @Deprecated
        void setTransactionControl(WorkControl transactionControl);
 }
index 36bec240e83601aedd915a342f377b5aef89b1d4..1177d4f5354c53addedc51fddfa10f5d2d71ec25 100644 (file)
@@ -11,11 +11,12 @@ import java.time.ZonedDateTime;
 import java.time.temporal.ChronoUnit;
 import java.time.temporal.Temporal;
 import java.util.ArrayList;
-import java.util.Collections;
+import java.util.Collection;
 import java.util.Dictionary;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Hashtable;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
@@ -236,6 +237,34 @@ public class LangUtils {
                return values;
        }
 
+       /** Size of an {@link Iterable}, optimised if it is a {@link Collection}. */
+       public static int size(Iterable<?> iterable) {
+               if (iterable instanceof Collection)
+                       return ((Collection<?>) iterable).size();
+
+               int size = 0;
+               for (Iterator<?> it = iterable.iterator(); it.hasNext(); size++)
+                       it.next();
+               return size;
+       }
+
+       public static <T> T getAt(Iterable<T> iterable, int index) {
+               if (iterable instanceof List) {
+                       List<T> lst = ((List<T>) iterable);
+                       if (index >= lst.size())
+                               throw new IllegalArgumentException("Index " + index + " is not available (size is " + lst.size() + ")");
+                       return lst.get(index);
+               }
+               int i = 0;
+               for (Iterator<T> it = iterable.iterator(); it.hasNext(); i++) {
+                       if (i == index)
+                               return it.next();
+                       else
+                               it.next();
+               }
+               throw new IllegalArgumentException("Index " + index + " is not available (size is " + i + ")");
+       }
+
        /*
         * EXCEPTIONS
         */