From: Mathieu Baudier Date: Wed, 22 Jun 2022 04:17:26 +0000 (+0200) Subject: LDAP support for hierarchy unit. Code clean up. X-Git-Tag: v2.3.10~177 X-Git-Url: https://git.argeo.org/?a=commitdiff_plain;h=cceead8a279e8630f63cc9e8213bdcdca39955a5;p=lgpl%2Fargeo-commons.git LDAP support for hierarchy unit. Code clean up. --- diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java b/org.argeo.util/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java index e13f56289..dde39e0ab 100644 --- a/org.argeo.util/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java +++ b/org.argeo.util/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java @@ -129,6 +129,10 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory { disabled = false; } + /* + * ABSTRACT METHODS + */ + /** Returns the groups this user is a direct member of. */ protected abstract List getDirectGroups(LdapName dn); @@ -140,6 +144,14 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory { protected abstract AbstractUserDirectory scope(User user); + protected abstract HierarchyUnit doGetHierarchyUnit(LdapName dn); + + protected abstract Iterable doGetDirectHierarchyUnits(LdapName searchBase, boolean functionalOnly); + + /* + * INITIALIZATION + */ + public void init() { } @@ -500,55 +512,25 @@ 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.getLastRdnValue(baseDn); -// // TODO check ou, o, etc. -// return name; -// } - @Override public HierarchyUnit getHierarchyUnit(String path) { - throw new UnsupportedOperationException(); + LdapName dn = pathToName(path); + return doGetHierarchyUnit(dn); } @Override public HierarchyUnit getHierarchyUnit(Role role) { - throw new UnsupportedOperationException(); + LdapName dn = LdapNameUtils.toLdapName(role.getName()); + LdapName huDn = LdapNameUtils.getParent(dn); + HierarchyUnit hierarchyUnit = doGetHierarchyUnit(huDn); + if (hierarchyUnit == null) + throw new IllegalStateException("No hierarchy unit found for " + role); + return hierarchyUnit; } -// @Override -// public List getHierarchyUnitRoles(String filter, boolean deep) { -// try { -// return getRoles(getBaseDn(), filter, deep); -// } catch (InvalidSyntaxException e) { -// throw new IllegalArgumentException("Cannot filter " + filter + " " + getBaseDn(), e); -// } -// } - @Override public Iterable getDirectHierarchyUnits(boolean functionalOnly) { - throw new UnsupportedOperationException(); + return doGetDirectHierarchyUnits(baseDn, functionalOnly); } /* @@ -562,7 +544,7 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory { protected DirectoryGroup newGroup(LdapName name, Attributes attrs) { if (LdapNameUtils.getParentRdn(name).equals(getSystemRoleBaseRdn())) return new LdifGroup.LdifSystemPermissions(this, name, attrs); - + if (hasObjectClass(attrs, LdapObjs.organization)) return new LdifGroup.LdifOrganization(this, name, attrs); else diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/AggregatingUserAdmin.java b/org.argeo.util/src/org/argeo/osgi/useradmin/AggregatingUserAdmin.java index ca1fa338b..ac641de97 100644 --- a/org.argeo.util/src/org/argeo/osgi/useradmin/AggregatingUserAdmin.java +++ b/org.argeo.util/src/org/argeo/osgi/useradmin/AggregatingUserAdmin.java @@ -43,7 +43,7 @@ public class AggregatingUserAdmin implements UserAdmin { else this.tokensBaseDn = null; } catch (InvalidNameException e) { - throw new UserDirectoryException("Cannot initialize " + AggregatingUserAdmin.class, e); + throw new IllegalStateException("Cannot initialize " + AggregatingUserAdmin.class, e); } } @@ -170,7 +170,7 @@ public class AggregatingUserAdmin implements UserAdmin { } else { LdapName baseDn = toLdapName(basePath); if (businessRoles.containsKey(baseDn)) - throw new UserDirectoryException("There is already a user admin for " + baseDn); + throw new IllegalStateException("There is already a user admin for " + baseDn); businessRoles.put(baseDn, userDirectory); } userDirectory.init(); @@ -185,7 +185,7 @@ public class AggregatingUserAdmin implements UserAdmin { try { return findUserAdmin(new LdapName(name)); } catch (InvalidNameException e) { - throw new UserDirectoryException("Badly formatted name " + name, e); + throw new IllegalArgumentException("Badly formatted name " + name, e); } } @@ -213,9 +213,9 @@ public class AggregatingUserAdmin implements UserAdmin { } } if (res.size() == 0) - throw new UserDirectoryException("Cannot find user admin for " + name); + throw new IllegalStateException("Cannot find user admin for " + name); if (res.size() > 1) - throw new UserDirectoryException("Multiple user admin found for " + name); + throw new IllegalStateException("Multiple user admin found for " + name); return res.get(0); } @@ -256,10 +256,10 @@ public class AggregatingUserAdmin implements UserAdmin { protected void removeUserDirectory(String basePath) { if (isSystemRolesBaseDn(basePath)) - throw new UserDirectoryException("System roles cannot be removed "); + throw new IllegalArgumentException("System roles cannot be removed "); LdapName baseDn = toLdapName(basePath); if (!businessRoles.containsKey(baseDn)) - throw new UserDirectoryException("No user directory registered for " + baseDn); + throw new IllegalStateException("No user directory registered for " + baseDn); AbstractUserDirectory userDirectory = businessRoles.remove(baseDn); destroy(userDirectory); } diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/DigestUtils.java b/org.argeo.util/src/org/argeo/osgi/useradmin/DigestUtils.java index 511c2fede..55d24d994 100644 --- a/org.argeo.util/src/org/argeo/osgi/useradmin/DigestUtils.java +++ b/org.argeo.util/src/org/argeo/osgi/useradmin/DigestUtils.java @@ -5,6 +5,8 @@ import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; import java.security.spec.KeySpec; import java.util.Arrays; @@ -22,8 +24,8 @@ class DigestUtils { digest.update(bytes); byte[] checksum = digest.digest(); return checksum; - } catch (Exception e) { - throw new UserDirectoryException("Cannot SHA1 digest", e); + } catch (NoSuchAlgorithmException e) { + throw new IllegalStateException("Cannot SHA1 digest", e); } } @@ -56,8 +58,8 @@ class DigestUtils { } else { throw new UnsupportedOperationException("Unkown password scheme " + passwordScheme); } - } catch (Exception e) { - throw new UserDirectoryException("Cannot digest", e); + } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { + throw new IllegalStateException("Cannot digest", e); } } diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/IpaUtils.java b/org.argeo.util/src/org/argeo/osgi/useradmin/IpaUtils.java index 076f26949..780215a9c 100644 --- a/org.argeo.util/src/org/argeo/osgi/useradmin/IpaUtils.java +++ b/org.argeo.util/src/org/argeo/osgi/useradmin/IpaUtils.java @@ -82,8 +82,8 @@ public class IpaUtils { String dnsZone = hostname.substring(hostname.indexOf('.') + 1); kerberosDomain = dnsBrowser.getRecord("_kerberos." + dnsZone, "TXT"); return kerberosDomain; - } catch (Exception e) { - throw new UserDirectoryException("Cannot determine Kerberos domain from DNS", e); + } catch (NamingException | IOException e) { + throw new IllegalStateException("Cannot determine Kerberos domain from DNS", e); } } @@ -98,7 +98,7 @@ public class IpaUtils { } if (kerberosRealm == null) - throw new UserDirectoryException("No Kerberos domain available for " + uri); + throw new IllegalStateException("No Kerberos domain available for " + uri); // TODO intergrate CA certificate in truststore // String schemeToUse = SCHEME_LDAPS; String schemeToUse = UserAdminConf.SCHEME_LDAP; @@ -109,12 +109,12 @@ public class IpaUtils { ldapHosts = dnsBrowser.getSrvRecordsAsHosts("_ldap._tcp." + kerberosRealm.toLowerCase(), schemeToUse.equals(UserAdminConf.SCHEME_LDAP) ? true : false); if (ldapHosts == null || ldapHosts.size() == 0) { - throw new UserDirectoryException("Cannot configure LDAP for IPA " + uri); + throw new IllegalStateException("Cannot configure LDAP for IPA " + uri); } else { ldapHostsStr = ldapHosts.get(0); } } catch (NamingException | IOException e) { - throw new UserDirectoryException("cannot convert IPA uri " + uri, e); + throw new IllegalStateException("Cannot convert IPA uri " + uri, e); } } else { ldapHosts = new ArrayList<>(); @@ -128,7 +128,7 @@ public class IpaUtils { uriStr.append(convertedUri).append(' '); } } catch (URISyntaxException e) { - throw new UserDirectoryException("cannot convert IPA uri " + uri, e); + throw new IllegalStateException("Cannot convert IPA uri " + uri, e); } Hashtable res = new Hashtable<>(); diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/LdapConnection.java b/org.argeo.util/src/org/argeo/osgi/useradmin/LdapConnection.java index ed69eb16b..1eaf1e7d6 100644 --- a/org.argeo.util/src/org/argeo/osgi/useradmin/LdapConnection.java +++ b/org.argeo.util/src/org/argeo/osgi/useradmin/LdapConnection.java @@ -49,8 +49,8 @@ class LdapConnection { initialLdapContext.addToEnvironment(Context.SECURITY_CREDENTIALS, creds.toString()); } } - } catch (Exception e) { - throw new UserDirectoryException("Cannot connect to LDAP", e); + } catch (NamingException e) { + throw new IllegalStateException("Cannot connect to LDAP", e); } } @@ -105,17 +105,17 @@ class LdapConnection { // delete for (LdapName dn : wc.getDeletedUsers().keySet()) { if (!entryExists(dn)) - throw new UserDirectoryException("User to delete no found " + dn); + throw new IllegalStateException("User to delete no found " + dn); } // add for (LdapName dn : wc.getNewUsers().keySet()) { if (entryExists(dn)) - throw new UserDirectoryException("User to create found " + dn); + throw new IllegalStateException("User to create found " + dn); } // modify for (LdapName dn : wc.getModifiedUsers().keySet()) { if (!wc.getNewUsers().containsKey(dn) && !entryExists(dn)) - throw new UserDirectoryException("User to modify not found " + dn); + throw new IllegalStateException("User to modify not found " + dn); } } diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/LdapUserAdmin.java b/org.argeo.util/src/org/argeo/osgi/useradmin/LdapUserAdmin.java index 138eb39e9..52fa38b11 100644 --- a/org.argeo.util/src/org/argeo/osgi/useradmin/LdapUserAdmin.java +++ b/org.argeo.util/src/org/argeo/osgi/useradmin/LdapUserAdmin.java @@ -19,6 +19,7 @@ import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import javax.naming.ldap.LdapName; +import org.argeo.util.naming.LdapObjs; import org.osgi.framework.Filter; import org.osgi.service.useradmin.Role; import org.osgi.service.useradmin.User; @@ -81,11 +82,11 @@ public class LdapUserAdmin extends AbstractUserDirectory { int roleType = roleType(name); DirectoryUser res; if (roleType == Role.GROUP) - res = newGroup( name, attrs); + res = newGroup(name, attrs); else if (roleType == Role.USER) - res = newUser( name, attrs); + res = newUser(name, attrs); else - throw new UserDirectoryException("Unsupported LDAP type for " + name); + throw new IllegalArgumentException("Unsupported LDAP type for " + name); return res; } catch (NameNotFoundException e) { throw e; @@ -116,10 +117,10 @@ public class LdapUserAdmin extends AbstractUserDirectory { DirectoryUser role; if (objectClassAttr.contains(getGroupObjectClass()) || objectClassAttr.contains(getGroupObjectClass().toLowerCase())) - role = newGroup( dn, attrs); + role = newGroup(dn, attrs); else if (objectClassAttr.contains(getUserObjectClass()) || objectClassAttr.contains(getUserObjectClass().toLowerCase())) - role = newUser( dn, attrs); + role = newUser(dn, attrs); else { // log.warn("Unsupported LDAP type for " + searchResult.getName()); continue results; @@ -131,9 +132,8 @@ public class LdapUserAdmin extends AbstractUserDirectory { // ignore (typically an unsupported anonymous bind) // TODO better logging return res; - } catch (Exception e) { - e.printStackTrace(); - throw new UserDirectoryException("Cannot get roles for filter " + f, e); + } catch (NamingException e) { + throw new IllegalStateException("Cannot get roles for filter " + f, e); } } @@ -159,8 +159,8 @@ public class LdapUserAdmin extends AbstractUserDirectory { directGroups.add(toDn(searchBase, searchResult)); } return directGroups; - } catch (Exception e) { - throw new UserDirectoryException("Cannot populate direct members of " + dn, e); + } catch (NamingException e) { + throw new IllegalStateException("Cannot populate direct members of " + dn, e); } } @@ -169,7 +169,7 @@ public class LdapUserAdmin extends AbstractUserDirectory { try { ldapConnection.prepareChanges(wc); } catch (NamingException e) { - throw new UserDirectoryException("Cannot prepare LDAP", e); + throw new IllegalStateException("Cannot prepare LDAP", e); } } @@ -178,7 +178,7 @@ public class LdapUserAdmin extends AbstractUserDirectory { try { ldapConnection.commitChanges(wc); } catch (NamingException e) { - throw new UserDirectoryException("Cannot commit LDAP", e); + throw new IllegalStateException("Cannot commit LDAP", e); } } @@ -187,11 +187,44 @@ public class LdapUserAdmin extends AbstractUserDirectory { // prepare not impacting } -// @Override -// public HierarchyUnit getHierarchyUnit(String path) { -// LdapName dn = LdapNameUtils.toLdapName(path); -// Attributes attrs = ldapConnection.getAttributes(dn); -// -// } + /* + * HIERARCHY + */ + + @Override + protected Iterable doGetDirectHierarchyUnits(LdapName searchBase, boolean functionalOnly) { + List res = new ArrayList<>(); + try { + String searchFilter = "(|(" + objectClass + "=" + LdapObjs.organizationalUnit.name() + ")(" + objectClass + + "=" + LdapObjs.organization.name() + "))"; + + SearchControls searchControls = new SearchControls(); + searchControls.setSearchScope(SearchControls.ONELEVEL_SCOPE); + + NamingEnumeration results = ldapConnection.search(searchBase, searchFilter, searchControls); + + while (results.hasMoreElements()) { + SearchResult searchResult = (SearchResult) results.nextElement(); + LdapName dn = toDn(searchBase, searchResult); + Attributes attrs = searchResult.getAttributes(); + LdifHierarchyUnit hierarchyUnit = new LdifHierarchyUnit(this, dn, attrs); + if (hierarchyUnit.isFunctional()) + res.add(hierarchyUnit); + } + return res; + } catch (NamingException e) { + throw new IllegalStateException("Cannot get direct hierarchy units ", e); + } + } + + @Override + protected HierarchyUnit doGetHierarchyUnit(LdapName dn) { + try { + Attributes attrs = ldapConnection.getAttributes(dn); + return new LdifHierarchyUnit(this, dn, attrs); + } catch (NamingException e) { + throw new IllegalStateException("Cannot get hierarchy unit " + dn, e); + } + } } diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/LdifAuthorization.java b/org.argeo.util/src/org/argeo/osgi/useradmin/LdifAuthorization.java index 15afe08b1..80a9eea30 100644 --- a/org.argeo.util/src/org/argeo/osgi/useradmin/LdifAuthorization.java +++ b/org.argeo.util/src/org/argeo/osgi/useradmin/LdifAuthorization.java @@ -79,7 +79,7 @@ class LdifAuthorization implements Authorization { if (displayName == null) displayName = user.getName(); if (displayName == null) - throw new UserDirectoryException("Cannot set display name for " + user); + throw new IllegalStateException("Cannot set display name for " + user); return displayName.toString(); } } diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/LdifGroup.java b/org.argeo.util/src/org/argeo/osgi/useradmin/LdifGroup.java index b7167ea13..80bff5947 100644 --- a/org.argeo.util/src/org/argeo/osgi/useradmin/LdifGroup.java +++ b/org.argeo.util/src/org/argeo/osgi/useradmin/LdifGroup.java @@ -5,6 +5,7 @@ import java.util.List; import javax.naming.InvalidNameException; import javax.naming.NamingEnumeration; +import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.ldap.LdapName; @@ -73,7 +74,7 @@ abstract class LdifGroup extends LdifUser implements DirectoryGroup { for (LdapName ldapName : getMemberNames()) { Role role = findRole(ldapName); if (role == null) { - throw new UserDirectoryException("Role " + ldapName + " cannot be added."); + throw new IllegalStateException("Role " + ldapName + " not found."); } directMembers.add(role); } @@ -107,8 +108,8 @@ abstract class LdifGroup extends LdifUser implements DirectoryGroup { roles.add(dn); } return roles; - } catch (Exception e) { - throw new UserDirectoryException("Cannot get members", e); + } catch (NamingException e) { + throw new IllegalStateException("Cannot get members", e); } } diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/LdifHierarchyUnit.java b/org.argeo.util/src/org/argeo/osgi/useradmin/LdifHierarchyUnit.java index d4259c87d..a847e49ae 100644 --- a/org.argeo.util/src/org/argeo/osgi/useradmin/LdifHierarchyUnit.java +++ b/org.argeo.util/src/org/argeo/osgi/useradmin/LdifHierarchyUnit.java @@ -1,7 +1,5 @@ package org.argeo.osgi.useradmin; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Objects; @@ -20,8 +18,8 @@ class LdifHierarchyUnit implements HierarchyUnit { private final boolean functional; private final Attributes attributes; - HierarchyUnit parent; - List children = new ArrayList<>(); +// HierarchyUnit parent; +// List children = new ArrayList<>(); LdifHierarchyUnit(AbstractUserDirectory directory, LdapName dn, Attributes attributes) { Objects.requireNonNull(directory); @@ -38,20 +36,21 @@ class LdifHierarchyUnit implements HierarchyUnit { @Override public HierarchyUnit getParent() { - return parent; + return directory.doGetHierarchyUnit(LdapNameUtils.getParent(dn)); } @Override public Iterable getDirectHierachyUnits(boolean functionalOnly) { - List res = new ArrayList<>(); - if (functionalOnly) - for (HierarchyUnit hu : children) { - if (hu.isFunctional()) - res.add(hu); - } - else - res.addAll(children); - return Collections.unmodifiableList(res); +// List res = new ArrayList<>(); +// if (functionalOnly) +// for (HierarchyUnit hu : children) { +// if (hu.isFunctional()) +// res.add(hu); +// } +// else +// res.addAll(children); +// return Collections.unmodifiableList(res); + return directory.doGetDirectHierarchyUnits(dn, functionalOnly); } @Override diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/LdifUser.java b/org.argeo.util/src/org/argeo/osgi/useradmin/LdifUser.java index c4c02a748..db83b81e4 100644 --- a/org.argeo.util/src/org/argeo/osgi/useradmin/LdifUser.java +++ b/org.argeo.util/src/org/argeo/osgi/useradmin/LdifUser.java @@ -195,9 +195,9 @@ abstract class LdifUser implements DirectoryUser { protected synchronized void startEditing() { if (frozen) - throw new UserDirectoryException("Cannot edit frozen view"); + throw new IllegalStateException("Cannot edit frozen view"); if (getUserAdmin().isReadOnly()) - throw new UserDirectoryException("User directory is read-only"); + throw new IllegalStateException("User directory is read-only"); assert getModifiedAttributes() == null; getWc().startEditing(this); // modifiedAttributes = (Attributes) publishedAttributes.clone(); @@ -254,7 +254,7 @@ abstract class LdifUser implements DirectoryUser { effectiveKeys.add(id); } } catch (NamingException e) { - throw new UserDirectoryException("Cannot initialise attribute dictionary", e); + throw new IllegalStateException("Cannot initialise attribute dictionary", e); } if (!credentials) effectiveKeys.add(LdapAttrs.objectClasses.name()); @@ -383,7 +383,7 @@ abstract class LdifUser implements DirectoryUser { else return null; } catch (NamingException e) { - throw new UserDirectoryException("Cannot get value for attribute " + key, e); + throw new IllegalStateException("Cannot get value for attribute " + key, e); } } @@ -405,7 +405,7 @@ abstract class LdifUser implements DirectoryUser { else return null; } catch (NamingException e) { - throw new UserDirectoryException("Cannot remove attribute " + key, e); + throw new IllegalStateException("Cannot remove attribute " + key, e); } } } diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/LdifUserAdmin.java b/org.argeo.util/src/org/argeo/osgi/useradmin/LdifUserAdmin.java index 0a925e4eb..ef487594c 100644 --- a/org.argeo.util/src/org/argeo/osgi/useradmin/LdifUserAdmin.java +++ b/org.argeo.util/src/org/argeo/osgi/useradmin/LdifUserAdmin.java @@ -16,6 +16,7 @@ import java.util.Dictionary; import java.util.HashSet; import java.util.Hashtable; import java.util.List; +import java.util.NavigableMap; import java.util.Objects; import java.util.Set; import java.util.SortedMap; @@ -23,6 +24,7 @@ import java.util.TreeMap; import javax.naming.NameNotFoundException; import javax.naming.NamingEnumeration; +import javax.naming.NamingException; import javax.naming.directory.Attributes; import javax.naming.ldap.LdapName; @@ -35,11 +37,11 @@ import org.osgi.service.useradmin.User; /** A user admin based on a LDIF files. */ public class LdifUserAdmin extends AbstractUserDirectory { - private SortedMap users = new TreeMap<>(); - private SortedMap groups = new TreeMap<>(); + private NavigableMap users = new TreeMap<>(); + private NavigableMap groups = new TreeMap<>(); - private SortedMap hierarchy = new TreeMap<>(); - private List rootHierarchyUnits = new ArrayList<>(); + private NavigableMap hierarchy = new TreeMap<>(); +// private List rootHierarchyUnits = new ArrayList<>(); public LdifUserAdmin(String uri, String baseDn) { this(fromUri(uri, baseDn), false); @@ -69,15 +71,15 @@ public class LdifUserAdmin extends AbstractUserDirectory { char[] password = DigestUtils.bytesToChars(pwd); User directoryUser = (User) getRole(username); if (!directoryUser.hasCredential(null, password)) - throw new UserDirectoryException("Invalid credentials"); + throw new IllegalStateException("Invalid credentials"); } else { - throw new UserDirectoryException("Password is required"); + throw new IllegalStateException("Password is required"); } Dictionary properties = cloneProperties(); properties.put(UserAdminConf.readOnly.name(), "true"); LdifUserAdmin scopedUserAdmin = new LdifUserAdmin(properties, true); - scopedUserAdmin.groups = Collections.unmodifiableSortedMap(groups); - scopedUserAdmin.users = Collections.unmodifiableSortedMap(users); + scopedUserAdmin.groups = Collections.unmodifiableNavigableMap(groups); + scopedUserAdmin.users = Collections.unmodifiableNavigableMap(users); return scopedUserAdmin; } @@ -98,20 +100,20 @@ public class LdifUserAdmin extends AbstractUserDirectory { return; } load(u.toURL().openStream()); - } catch (Exception e) { - throw new UserDirectoryException("Cannot open URL " + getUri(), e); + } catch (IOException | URISyntaxException e) { + throw new IllegalStateException("Cannot open URL " + getUri(), e); } } public void save() { if (getUri() == null) - throw new UserDirectoryException("Cannot save LDIF user admin: no URI is set"); + throw new IllegalStateException("Cannot save LDIF user admin: no URI is set"); if (isReadOnly()) - throw new UserDirectoryException("Cannot save LDIF user admin: " + getUri() + " is read-only"); + throw new IllegalStateException("Cannot save LDIF user admin: " + getUri() + " is read-only"); try (FileOutputStream out = new FileOutputStream(new File(new URI(getUri())))) { save(out); } catch (IOException | URISyntaxException e) { - throw new UserDirectoryException("Cannot save user admin to " + getUri(), e); + throw new IllegalStateException("Cannot save user admin to " + getUri(), e); } } @@ -145,7 +147,7 @@ public class LdifUserAdmin extends AbstractUserDirectory { while (ids.hasMoreElements()) { String id = ids.nextElement().toLowerCase(); if (lowerCase.contains(id)) - throw new UserDirectoryException(key + " has duplicate id " + id); + throw new IllegalStateException(key + " has duplicate id " + id); lowerCase.add(id); } @@ -177,26 +179,26 @@ public class LdifUserAdmin extends AbstractUserDirectory { } // link hierarchy - hierachyUnits: for (LdapName dn : hierarchy.keySet()) { - LdifHierarchyUnit unit = hierarchy.get(dn); - LdapName parentDn = (LdapName) dn.getPrefix(dn.size() - 1); - LdifHierarchyUnit parent = hierarchy.get(parentDn); - if (parent == null) { - rootHierarchyUnits.add(unit); - unit.parent = null; - continue hierachyUnits; - } - parent.children.add(unit); - unit.parent = parent; - } - } catch (Exception e) { - throw new UserDirectoryException("Cannot load user admin service from LDIF", e); +// hierachyUnits: for (LdapName dn : hierarchy.keySet()) { +// LdifHierarchyUnit unit = hierarchy.get(dn); +// LdapName parentDn = (LdapName) dn.getPrefix(dn.size() - 1); +// LdifHierarchyUnit parent = hierarchy.get(parentDn); +// if (parent == null) { +// rootHierarchyUnits.add(unit); +// unit.parent = null; +// continue hierachyUnits; +// } +// parent.children.add(unit); +// unit.parent = parent; +// } + } catch (NamingException | IOException e) { + throw new IllegalStateException("Cannot load user admin service from LDIF", e); } } public void destroy() { if (users == null || groups == null) - throw new UserDirectoryException("User directory " + getBaseDn() + " is already destroyed"); + throw new IllegalStateException("User directory " + getBaseDn() + " is already destroyed"); users = null; groups = null; } @@ -270,19 +272,19 @@ public class LdifUserAdmin extends AbstractUserDirectory { else if (groups.containsKey(dn)) groups.remove(dn); else - throw new UserDirectoryException("User to delete not found " + dn); + throw new IllegalStateException("User to delete not found " + dn); } // add for (LdapName dn : wc.getNewUsers().keySet()) { DirectoryUser user = wc.getNewUsers().get(dn); if (users.containsKey(dn) || groups.containsKey(dn)) - throw new UserDirectoryException("User to create found " + dn); + throw new IllegalStateException("User to create found " + dn); else if (Role.USER == user.getType()) users.put(dn, user); else if (Role.GROUP == user.getType()) groups.put(dn, (DirectoryGroup) user); else - throw new UserDirectoryException("Unsupported role type " + user.getType() + " for new user " + dn); + throw new IllegalStateException("Unsupported role type " + user.getType() + " for new user " + dn); } // modify for (LdapName dn : wc.getModifiedUsers().keySet()) { @@ -293,7 +295,7 @@ public class LdifUserAdmin extends AbstractUserDirectory { else if (groups.containsKey(dn)) user = groups.get(dn); else - throw new UserDirectoryException("User to modify no found " + dn); + throw new IllegalStateException("User to modify no found " + dn); user.publishAttributes(modifiedAttrs); } } @@ -321,36 +323,43 @@ public class LdifUserAdmin extends AbstractUserDirectory { // public HierarchyUnit getHierarchyChild(int i) { // return rootHierarchyUnits.get(i); // } - @Override - public HierarchyUnit getHierarchyUnit(String path) { - LdapName dn = pathToName(path); + protected HierarchyUnit doGetHierarchyUnit(LdapName dn) { return hierarchy.get(dn); } @Override - public Iterable getDirectHierarchyUnits(boolean functionalOnly) { - if (functionalOnly) { - List res = new ArrayList<>(); - for (HierarchyUnit hu : rootHierarchyUnits) { - if (hu.isFunctional()) - res.add(hu); + protected Iterable doGetDirectHierarchyUnits(LdapName searchBase, boolean functionalOnly) { + List res = new ArrayList<>(); + for (LdapName n : hierarchy.keySet()) { + if (n.size() == searchBase.size() + 1) { + if (n.startsWith(searchBase)) { + HierarchyUnit hu = hierarchy.get(n); + if (functionalOnly) { + if (hu.isFunctional()) + res.add(hu); + } else { + res.add(hu); + } + } } - return res; - - } else { - return rootHierarchyUnits; } + return res; } - @Override - public HierarchyUnit getHierarchyUnit(Role role) { - LdapName dn = LdapNameUtils.toLdapName(role.getName()); - LdapName huDn = LdapNameUtils.getParent(dn); - HierarchyUnit hierarchyUnit = hierarchy.get(huDn); - if (hierarchyUnit == null) - throw new IllegalStateException("No hierarchy unit found for " + role); - return hierarchyUnit; - } +// @Override +// public Iterable getDirectHierarchyUnits(boolean functionalOnly) { +// if (functionalOnly) { +// List res = new ArrayList<>(); +// for (HierarchyUnit hu : rootHierarchyUnits) { +// if (hu.isFunctional()) +// res.add(hu); +// } +// return res; +// +// } else { +// return rootHierarchyUnits; +// } +// } } diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/OsUserDirectory.java b/org.argeo.util/src/org/argeo/osgi/useradmin/OsUserDirectory.java index b0a52626a..3ded7a7a6 100644 --- a/org.argeo.util/src/org/argeo/osgi/useradmin/OsUserDirectory.java +++ b/org.argeo.util/src/org/argeo/osgi/useradmin/OsUserDirectory.java @@ -15,6 +15,7 @@ import org.argeo.util.naming.LdapAttrs; import org.osgi.framework.Filter; import org.osgi.service.useradmin.User; +/** Pseudo user directory to be used when logging in as OS user. */ public class OsUserDirectory extends AbstractUserDirectory { private final String osUsername = System.getProperty("user.name"); private final LdapName osUserDn; @@ -23,12 +24,13 @@ public class OsUserDirectory extends AbstractUserDirectory { public OsUserDirectory(URI uriArg, Dictionary props) { super(uriArg, props, false); try { - osUserDn = new LdapName(LdapAttrs.uid.name() + "=" + osUsername + "," + getUserBaseRdn() + "," + getBaseDn()); + osUserDn = new LdapName( + LdapAttrs.uid.name() + "=" + osUsername + "," + getUserBaseRdn() + "," + getBaseDn()); Attributes attributes = new BasicAttributes(); attributes.put(LdapAttrs.uid.name(), osUsername); osUser = newUser(osUserDn, attributes); } catch (NamingException e) { - throw new UserDirectoryException("Cannot create system user", e); + throw new IllegalStateException("Cannot create system user", e); } } @@ -63,4 +65,14 @@ public class OsUserDirectory extends AbstractUserDirectory { throw new UnsupportedOperationException(); } + @Override + protected HierarchyUnit doGetHierarchyUnit(LdapName dn) { + return null; + } + + @Override + protected Iterable doGetDirectHierarchyUnits(LdapName searchBase, boolean functionalOnly) { + return new ArrayList<>(); + } + } diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/TokenUtils.java b/org.argeo.util/src/org/argeo/osgi/useradmin/TokenUtils.java index 4b00e6c6a..178b4ae82 100644 --- a/org.argeo.util/src/org/argeo/osgi/useradmin/TokenUtils.java +++ b/org.argeo.util/src/org/argeo/osgi/useradmin/TokenUtils.java @@ -29,7 +29,7 @@ public class TokenUtils { String token = ldapName.getRdn(ldapName.size()).getValue().toString(); res.add(token); } catch (InvalidNameException e) { - throw new UserDirectoryException("Invalid principal " + principal, e); + throw new IllegalArgumentException("Invalid principal " + principal, e); } } } diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/UserAdminConf.java b/org.argeo.util/src/org/argeo/osgi/useradmin/UserAdminConf.java index 93ca94ca6..7fd9e1895 100644 --- a/org.argeo.util/src/org/argeo/osgi/useradmin/UserAdminConf.java +++ b/org.argeo.util/src/org/argeo/osgi/useradmin/UserAdminConf.java @@ -10,6 +10,7 @@ import java.util.List; import java.util.Map; import javax.naming.Context; +import javax.naming.InvalidNameException; import javax.naming.ldap.LdapName; import org.argeo.util.naming.NamingUtils; @@ -141,7 +142,7 @@ public enum UserAdminConf { 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); + throw new IllegalArgumentException("Cannot create URI from properties", e); } } @@ -181,7 +182,7 @@ public enum UserAdminConf { } else if (scheme.equals(SCHEME_IPA)) { } else if (scheme.equals(SCHEME_OS)) { } else - throw new UserDirectoryException("Unsupported scheme " + scheme); + throw new IllegalArgumentException("Unsupported scheme " + scheme); Map> query = NamingUtils.queryToMap(u); for (String key : query.keySet()) { UserAdminConf ldapProp = UserAdminConf.valueOf(key); @@ -189,7 +190,7 @@ public enum UserAdminConf { if (values.size() == 1) { res.put(ldapProp.name(), values.get(0)); } else { - throw new UserDirectoryException("Only single values are supported"); + throw new IllegalArgumentException("Only single values are supported"); } } res.put(baseDn.name(), bDn); @@ -209,8 +210,8 @@ public enum UserAdminConf { } } return res; - } catch (Exception e) { - throw new UserDirectoryException("Cannot convert " + uri + " to properties", e); + } catch (URISyntaxException | InvalidNameException e) { + throw new IllegalArgumentException("Cannot convert " + uri + " to properties", e); } } @@ -239,7 +240,7 @@ public enum UserAdminConf { public static String baseDnHash(Dictionary properties) { String bDn = (String) properties.get(baseDn.name()); if (bDn == null) - throw new UserDirectoryException("No baseDn in " + properties); + throw new IllegalStateException("No baseDn in " + properties); return DigestUtils.sha1str(bDn); } } diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/UserDirectoryException.java b/org.argeo.util/src/org/argeo/osgi/useradmin/UserDirectoryException.java deleted file mode 100644 index 0140a196d..000000000 --- a/org.argeo.util/src/org/argeo/osgi/useradmin/UserDirectoryException.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.argeo.osgi.useradmin; - -import org.osgi.service.useradmin.UserAdmin; - -/** - * Exceptions related to Argeo's implementation of OSGi {@link UserAdmin} - * service. - */ -@Deprecated -public class UserDirectoryException extends RuntimeException { - private static final long serialVersionUID = 1419352360062048603L; - - public UserDirectoryException(String message) { - super(message); - } - - public UserDirectoryException(String message, Throwable e) { - super(message, e); - } -} diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/UserDirectoryWorkingCopy.java b/org.argeo.util/src/org/argeo/osgi/useradmin/UserDirectoryWorkingCopy.java index 0e25bdfa1..35a34bdbe 100644 --- a/org.argeo.util/src/org/argeo/osgi/useradmin/UserDirectoryWorkingCopy.java +++ b/org.argeo.util/src/org/argeo/osgi/useradmin/UserDirectoryWorkingCopy.java @@ -27,8 +27,7 @@ class UserDirectoryWorkingCopy { } public boolean noModifications() { - return newUsers.size() == 0 && modifiedUsers.size() == 0 - && deletedUsers.size() == 0; + return newUsers.size() == 0 && modifiedUsers.size() == 0 && deletedUsers.size() == 0; } public Attributes getAttributes(LdapName dn) { @@ -40,7 +39,7 @@ class UserDirectoryWorkingCopy { public void startEditing(DirectoryUser user) { LdapName dn = user.getDn(); if (modifiedUsers.containsKey(dn)) - throw new UserDirectoryException("Already editing " + dn); + throw new IllegalStateException("Already editing " + dn); modifiedUsers.put(dn, (Attributes) user.getAttributes().clone()); } diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/WcXaResource.java b/org.argeo.util/src/org/argeo/osgi/useradmin/WcXaResource.java index 1630b6bd3..af0f351c7 100644 --- a/org.argeo.util/src/org/argeo/osgi/useradmin/WcXaResource.java +++ b/org.argeo.util/src/org/argeo/osgi/useradmin/WcXaResource.java @@ -22,10 +22,10 @@ class WcXaResource implements XAResource { @Override public synchronized void start(Xid xid, int flags) throws XAException { if (editingXid != null) - throw new UserDirectoryException("Already editing " + editingXid); + throw new IllegalStateException("Already editing " + editingXid); UserDirectoryWorkingCopy wc = workingCopies.put(xid, new UserDirectoryWorkingCopy()); if (wc != null) - throw new UserDirectoryException("There is already a working copy for " + xid); + throw new IllegalStateException("There is already a working copy for " + xid); this.editingXid = xid; } @@ -43,7 +43,7 @@ class WcXaResource implements XAResource { return null; UserDirectoryWorkingCopy wc = workingCopies.get(editingXid); if (wc == null) - throw new UserDirectoryException("No working copy found for " + editingXid); + throw new IllegalStateException("No working copy found for " + editingXid); return wc; } diff --git a/org.argeo.util/src/org/argeo/util/naming/AuthPassword.java b/org.argeo.util/src/org/argeo/util/naming/AuthPassword.java index 973b90f0f..d8792729f 100644 --- a/org.argeo.util/src/org/argeo/util/naming/AuthPassword.java +++ b/org.argeo.util/src/org/argeo/util/naming/AuthPassword.java @@ -14,8 +14,6 @@ import javax.security.auth.callback.NameCallback; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.UnsupportedCallbackException; -import org.argeo.osgi.useradmin.UserDirectoryException; - /** LDAP authPassword field according to RFC 3112 */ public class AuthPassword implements CallbackHandler { private final String authScheme; @@ -118,7 +116,7 @@ public class AuthPassword implements CallbackHandler { } return null; } catch (NamingException e) { - throw new UserDirectoryException("Cannot check attribute", e); + throw new IllegalStateException("Cannot check attribute", e); } } diff --git a/org.argeo.util/src/org/argeo/util/naming/LdifParser.java b/org.argeo.util/src/org/argeo/util/naming/LdifParser.java index d68173a2a..69ceb129c 100644 --- a/org.argeo.util/src/org/argeo/util/naming/LdifParser.java +++ b/org.argeo.util/src/org/argeo/util/naming/LdifParser.java @@ -22,8 +22,6 @@ import javax.naming.directory.BasicAttributes; import javax.naming.ldap.LdapName; import javax.naming.ldap.Rdn; -import org.argeo.osgi.useradmin.UserDirectoryException; - /** Basic LDIF parser. */ public class LdifParser { private final static Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; @@ -36,13 +34,13 @@ public class LdifParser { if (nameAttr == null) currentAttributes.put(nameRdn.getType(), nameRdn.getValue()); else if (!nameAttr.get().equals(nameRdn.getValue())) - throw new UserDirectoryException( + throw new IllegalStateException( "Attribute " + nameAttr.getID() + "=" + nameAttr.get() + " not consistent with DN " + currentDn + " (shortly before line " + lineNumber + " in LDIF file)"); Attributes previous = res.put(currentDn, currentAttributes); return previous; } catch (NamingException e) { - throw new UserDirectoryException("Cannot add " + currentDn, e); + throw new IllegalStateException("Cannot add " + currentDn, e); } } diff --git a/org.argeo.util/src/org/argeo/util/naming/LdifWriter.java b/org.argeo.util/src/org/argeo/util/naming/LdifWriter.java index 457380b9b..496e53b1b 100644 --- a/org.argeo.util/src/org/argeo/util/naming/LdifWriter.java +++ b/org.argeo.util/src/org/argeo/util/naming/LdifWriter.java @@ -23,8 +23,6 @@ import javax.naming.directory.Attributes; import javax.naming.ldap.LdapName; import javax.naming.ldap.Rdn; -import org.argeo.osgi.useradmin.UserDirectoryException; - /** Basic LDIF writer */ public class LdifWriter { private final static Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; @@ -46,7 +44,7 @@ public class LdifWriter { Rdn nameRdn = name.getRdn(name.size() - 1); Attribute nameAttr = attributes.get(nameRdn.getType()); if (!nameAttr.get().equals(nameRdn.getValue())) - throw new UserDirectoryException( + throw new IllegalArgumentException( "Attribute " + nameAttr.getID() + "=" + nameAttr.get() + " not consistent with DN " + name); writer.append(DN + ": ").append(name.toString()).append('\n'); @@ -70,7 +68,7 @@ public class LdifWriter { writer.append('\n'); writer.flush(); } catch (NamingException e) { - throw new UserDirectoryException("Cannot write LDIF", e); + throw new IllegalStateException("Cannot write LDIF", e); } }