From: Mathieu Baudier Date: Mon, 13 Jun 2022 05:53:47 +0000 (+0200) Subject: Start clarifying user admin. X-Git-Tag: v2.3.10~187 X-Git-Url: https://git.argeo.org/?a=commitdiff_plain;h=a0a4cc2c5657faec904e2de279efa4a165d59ac8;p=lgpl%2Fargeo-commons.git Start clarifying user admin. --- diff --git a/eclipse/org.argeo.cms.e4/src/org/argeo/cms/e4/users/UserAdminWrapper.java b/eclipse/org.argeo.cms.e4/src/org/argeo/cms/e4/users/UserAdminWrapper.java index 16aa78316..465c15a17 100644 --- a/eclipse/org.argeo.cms.e4/src/org/argeo/cms/e4/users/UserAdminWrapper.java +++ b/eclipse/org.argeo.cms.e4/src/org/argeo/cms/e4/users/UserAdminWrapper.java @@ -91,7 +91,7 @@ public class UserAdminWrapper { Map dns = new HashMap(); for (UserDirectory userDirectory : userDirectories.keySet()) { Boolean readOnly = userDirectory.isReadOnly(); - String baseDn = userDirectory.getBaseDn().toString(); + String baseDn = userDirectory.getBasePath(); if (onlyWritable && readOnly) continue; diff --git a/org.argeo.cms/src/org/argeo/cms/internal/auth/CmsUserManagerImpl.java b/org.argeo.cms/src/org/argeo/cms/internal/auth/CmsUserManagerImpl.java index 19136606d..782487a9a 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/auth/CmsUserManagerImpl.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/auth/CmsUserManagerImpl.java @@ -229,7 +229,7 @@ public class CmsUserManagerImpl implements CmsUserManager { Map dns = new HashMap(); for (UserDirectory userDirectory : userDirectories.keySet()) { Boolean readOnly = userDirectory.isReadOnly(); - String baseDn = userDirectory.getBaseDn().toString(); + String baseDn = userDirectory.getBasePath(); if (onlyWritable && readOnly) continue; diff --git a/org.argeo.cms/src/org/argeo/cms/internal/osgi/NodeUserAdmin.java b/org.argeo.cms/src/org/argeo/cms/internal/osgi/NodeUserAdmin.java index 4eda98c35..0746d4301 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/osgi/NodeUserAdmin.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/osgi/NodeUserAdmin.java @@ -5,9 +5,6 @@ import java.util.HashMap; import java.util.Hashtable; import java.util.Map; -import javax.naming.InvalidNameException; -import javax.naming.ldap.LdapName; - import org.argeo.api.cms.CmsConstants; import org.argeo.api.cms.CmsLog; import org.argeo.cms.internal.runtime.CmsUserAdmin; @@ -27,22 +24,17 @@ public class NodeUserAdmin extends CmsUserAdmin implements ManagedServiceFactory private final static CmsLog log = CmsLog.getLog(NodeUserAdmin.class); // OSGi - private Map pidToBaseDn = new HashMap<>(); + private Map pidToBaseDn = new HashMap<>(); @Override public void updated(String pid, Dictionary properties) throws ConfigurationException { - LdapName baseDn; - try { - baseDn = new LdapName((String) properties.get(UserAdminConf.baseDn.name())); - } catch (InvalidNameException e) { - throw new IllegalArgumentException(e); - } + String basePath = (String) properties.get(UserAdminConf.baseDn.name()); // FIXME make updates more robust - if (pidToBaseDn.containsValue(baseDn)) { + if (pidToBaseDn.containsValue(basePath)) { if (log.isDebugEnabled()) - log.debug("Ignoring user directory update of " + baseDn); + log.debug("Ignoring user directory update of " + basePath); return; } @@ -50,14 +42,14 @@ public class NodeUserAdmin extends CmsUserAdmin implements ManagedServiceFactory // OSGi Hashtable regProps = new Hashtable<>(); regProps.put(Constants.SERVICE_PID, pid); - if (isSystemRolesBaseDn(baseDn)) + if (isSystemRolesBaseDn(basePath)) regProps.put(Constants.SERVICE_RANKING, Integer.MAX_VALUE); - regProps.put(UserAdminConf.baseDn.name(), baseDn); + regProps.put(UserAdminConf.baseDn.name(), basePath); CmsActivator.getBundleContext().registerService(UserDirectory.class, userDirectory, regProps); - pidToBaseDn.put(pid, baseDn); + pidToBaseDn.put(pid, basePath); - if (isSystemRolesBaseDn(baseDn)) { + if (isSystemRolesBaseDn(basePath)) { // publishes itself as user admin only when system roles are available Dictionary userAdminregProps = new Hashtable<>(); userAdminregProps.put(CmsConstants.CN, CmsConstants.DEFAULT); @@ -71,8 +63,8 @@ public class NodeUserAdmin extends CmsUserAdmin implements ManagedServiceFactory // assert pidToServiceRegs.get(pid) != null; assert pidToBaseDn.get(pid) != null; // pidToServiceRegs.remove(pid).unregister(); - LdapName baseDn = pidToBaseDn.remove(pid); - removeUserDirectory(baseDn); + String basePath = pidToBaseDn.remove(pid); + removeUserDirectory(basePath); } @Override diff --git a/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsUserAdmin.java b/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsUserAdmin.java index 9364ee4a3..391c94a3d 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsUserAdmin.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsUserAdmin.java @@ -11,9 +11,9 @@ import java.security.PrivilegedExceptionAction; import java.util.ArrayList; import java.util.Dictionary; import java.util.Iterator; +import java.util.Optional; import java.util.Set; -import javax.naming.ldap.LdapName; import javax.security.auth.Subject; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; @@ -35,7 +35,6 @@ import org.argeo.cms.internal.http.client.HttpCredentialProvider; import org.argeo.cms.internal.http.client.SpnegoAuthScheme; import org.argeo.osgi.transaction.WorkControl; import org.argeo.osgi.transaction.WorkTransaction; -import org.argeo.osgi.useradmin.AbstractUserDirectory; import org.argeo.osgi.useradmin.AggregatingUserAdmin; import org.argeo.osgi.useradmin.LdapUserAdmin; import org.argeo.osgi.useradmin.LdifUserAdmin; @@ -96,7 +95,7 @@ public class CmsUserAdmin extends AggregatingUserAdmin { } // Create - AbstractUserDirectory userDirectory; + UserDirectory userDirectory; if (realm != null || UserAdminConf.SCHEME_LDAP.equals(u.getScheme()) || UserAdminConf.SCHEME_LDAPS.equals(u.getScheme())) { userDirectory = new LdapUserAdmin(properties); @@ -108,14 +107,14 @@ public class CmsUserAdmin extends AggregatingUserAdmin { } else { throw new IllegalArgumentException("Unsupported scheme " + u.getScheme()); } - LdapName baseDn = userDirectory.getBaseDn(); + String basePath = userDirectory.getBasePath(); addUserDirectory(userDirectory); - if (isSystemRolesBaseDn(baseDn)) { + if (isSystemRolesBaseDn(basePath)) { addStandardSystemRoles(); } if (log.isDebugEnabled()) { - log.debug("User directory " + userDirectory.getBaseDn() + (u != null ? " [" + u.getScheme() + "]" : "") + log.debug("User directory " + userDirectory.getBasePath() + (u != null ? " [" + u.getScheme() + "]" : "") + " enabled." + (realm != null ? " " + realm + " realm." : "")); } return userDirectory; @@ -153,13 +152,14 @@ public class CmsUserAdmin extends AggregatingUserAdmin { } } - protected void postAdd(AbstractUserDirectory userDirectory) { + @Override + protected void postAdd(UserDirectory userDirectory) { userDirectory.setTransactionControl(transactionManager); - Object realm = userDirectory.getProperties().get(UserAdminConf.realm.name()); - if (realm != null) { + Optional realm = userDirectory.getRealm(); + if (realm.isPresent()) { if (Files.exists(nodeKeyTab)) { - String servicePrincipal = getKerberosServicePrincipal(realm.toString()); + String servicePrincipal = getKerberosServicePrincipal(realm.get()); if (servicePrincipal != null) { CallbackHandler callbackHandler = new CallbackHandler() { @Override @@ -193,9 +193,10 @@ public class CmsUserAdmin extends AggregatingUserAdmin { } } - protected void preDestroy(AbstractUserDirectory userDirectory) { - Object realm = userDirectory.getProperties().get(UserAdminConf.realm.name()); - if (realm != null) { + @Override + protected void preDestroy(UserDirectory userDirectory) { + Optional realm = userDirectory.getRealm(); + if (realm.isPresent()) { if (acceptorCredentials != null) { try { acceptorCredentials.dispose(); 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 e028e384e..19cd06886 100644 --- a/org.argeo.util/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java +++ b/org.argeo.util/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java @@ -17,10 +17,12 @@ import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import java.util.List; +import java.util.Optional; import javax.naming.InvalidNameException; import javax.naming.NameNotFoundException; import javax.naming.NamingEnumeration; +import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.BasicAttribute; @@ -39,7 +41,7 @@ import org.osgi.service.useradmin.User; import org.osgi.service.useradmin.UserAdmin; /** Base class for a {@link UserDirectory}. */ -public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory { +abstract class AbstractUserDirectory implements UserAdmin, UserDirectory { static final String SHARED_STATE_USERNAME = "javax.security.auth.login.name"; static final String SHARED_STATE_PASSWORD = "javax.security.auth.login.password"; @@ -99,7 +101,8 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory userBaseDn = new LdapName(userBase + "," + baseDn); groupBaseDn = new LdapName(groupBase + "," + baseDn); } catch (InvalidNameException e) { - throw new UserDirectoryException("Badly formated base DN " + UserAdminConf.baseDn.getValue(properties), e); + throw new IllegalArgumentException("Badly formated base DN " + UserAdminConf.baseDn.getValue(properties), + e); } String readOnlyStr = UserAdminConf.readOnly.getValue(properties); if (readOnlyStr == null) { @@ -133,6 +136,19 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory } + @Override + public String getBasePath() { + return getBaseDn().toString(); + } + + @Override + public Optional getRealm() { + Object realm = getProperties().get(UserAdminConf.realm.name()); + if (realm == null) + return Optional.empty(); + return Optional.of(realm.toString()); + } + protected boolean isEditing() { return xaResource.wc() != null; } @@ -145,20 +161,11 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory } protected void checkEdit() { -// Transaction transaction; -// try { -// transaction = transactionManager.getTransaction(); -// } catch (SystemException e) { -// throw new UserDirectoryException("Cannot get transaction", e); -// } -// if (transaction == null) -// throw new UserDirectoryException("A transaction needs to be active in order to edit"); if (xaResource.wc() == null) { try { -// transaction.enlistResource(xaResource); transactionControl.getWorkContext().registerXAResource(xaResource, null); } catch (Exception e) { - throw new UserDirectoryException("Cannot enlist " + xaResource, e); + throw new IllegalStateException("Cannot enlist " + xaResource, e); } } else { } @@ -189,8 +196,8 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory if (group != null) allRoles.add(group); } - } catch (Exception e) { - throw new UserDirectoryException("Cannot get memberOf groups for " + user, e); + } catch (NamingException e) { + throw new IllegalStateException("Cannot get memberOf groups for " + user, e); } } else { for (LdapName groupDn : getDirectGroups(user.getDn())) { @@ -211,7 +218,7 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory // USER ADMIN @Override public Role getRole(String name) { - return doGetRole(toDn(name)); + return doGetRole(toLdapName(name)); } protected DirectoryUser doGetRole(LdapName dn) { @@ -260,7 +267,7 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory if (key != null) { doGetUser(key, value, collectedUsers); } else { - throw new UserDirectoryException("Key cannot be null"); + throw new IllegalArgumentException("Key cannot be null"); } if (collectedUsers.size() == 1) { @@ -278,7 +285,7 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory List users = doGetRoles(f); collectedUsers.addAll(users); } catch (InvalidSyntaxException e) { - throw new UserDirectoryException("Cannot get user with " + key + "=" + value, e); + throw new IllegalArgumentException("Cannot get user with " + key + "=" + value, e); } } @@ -292,7 +299,7 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory try { DirectoryUser directoryUser = (DirectoryUser) scopedUserAdmin.getRole(user.getName()); if (directoryUser == null) - throw new UserDirectoryException("No scoped user found for " + user); + throw new IllegalStateException("No scoped user found for " + user); LdifAuthorization authorization = new LdifAuthorization(directoryUser, scopedUserAdmin.getAllRoles(directoryUser)); return authorization; @@ -306,9 +313,9 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory public Role createRole(String name, int type) { checkEdit(); UserDirectoryWorkingCopy wc = getWorkingCopy(); - LdapName dn = toDn(name); + LdapName dn = toLdapName(name); if ((daoHasRole(dn) && !wc.getDeletedUsers().containsKey(dn)) || wc.getNewUsers().containsKey(dn)) - throw new UserDirectoryException("Already a role " + name); + throw new IllegalArgumentException("Already a role " + name); BasicAttributes attrs = new BasicAttributes(true); // attrs.put(LdifName.dn.name(), dn.toString()); Rdn nameRdn = dn.getRdn(dn.size() - 1); @@ -350,7 +357,7 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory attrs.put(objClass); newRole = new LdifGroup(this, dn, attrs); } else - throw new UserDirectoryException("Unsupported type " + type); + throw new IllegalArgumentException("Unsupported type " + type); return newRole; } @@ -358,7 +365,7 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory public boolean removeRole(String name) { checkEdit(); UserDirectoryWorkingCopy wc = getWorkingCopy(); - LdapName dn = toDn(name); + LdapName dn = toLdapName(name); boolean actuallyDeleted; if (daoHasRole(dn) || wc.getNewUsers().containsKey(dn)) { DirectoryUser user = (DirectoryUser) getRole(name); @@ -387,15 +394,6 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory } - // UTILITIES - protected LdapName toDn(String name) { - try { - return new LdapName(name); - } catch (InvalidNameException e) { - throw new UserDirectoryException("Badly formatted name", e); - } - } - // GETTERS protected String getMemberAttributeId() { return memberAttributeId; @@ -514,4 +512,14 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory return scoped; } + /* + * STATIC UTILITIES + */ + static LdapName toLdapName(String name) { + try { + return new LdapName(name); + } catch (InvalidNameException e) { + throw new IllegalArgumentException(name + " is not an LDAP name", e); + } + } } 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 c274ed97e..5613c2848 100644 --- a/org.argeo.util/src/org/argeo/osgi/useradmin/AggregatingUserAdmin.java +++ b/org.argeo.util/src/org/argeo/osgi/useradmin/AggregatingUserAdmin.java @@ -1,5 +1,7 @@ package org.argeo.osgi.useradmin; +import static org.argeo.osgi.useradmin.AbstractUserDirectory.toLdapName; + import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -75,9 +77,9 @@ public class AggregatingUserAdmin implements UserAdmin { public User getUser(String key, String value) { List res = new ArrayList(); for (UserAdmin userAdmin : businessRoles.values()) { - User u = userAdmin.getUser(key, value); - if (u != null) - res.add(u); + User u = userAdmin.getUser(key, value); + if (u != null) + res.add(u); } // Note: node roles cannot contain users, so it is not searched return res.size() == 1 ? res.get(0) : null; @@ -153,15 +155,19 @@ public class AggregatingUserAdmin implements UserAdmin { // // USER ADMIN AGGREGATOR // - protected void addUserDirectory(AbstractUserDirectory userDirectory) { - LdapName baseDn = userDirectory.getBaseDn(); - if (isSystemRolesBaseDn(baseDn)) { + protected void addUserDirectory(UserDirectory ud) { + if (!(ud instanceof AbstractUserDirectory)) + throw new IllegalArgumentException("Only " + AbstractUserDirectory.class.getName() + " is supported"); + AbstractUserDirectory userDirectory = (AbstractUserDirectory) ud; + String basePath = userDirectory.getBasePath(); + if (isSystemRolesBaseDn(basePath)) { this.systemRoles = userDirectory; systemRoles.setExternalRoles(this); - } else if (isTokensBaseDn(baseDn)) { + } else if (isTokensBaseDn(basePath)) { this.tokens = userDirectory; tokens.setExternalRoles(this); } else { + LdapName baseDn = toLdapName(basePath); if (businessRoles.containsKey(baseDn)) throw new UserDirectoryException("There is already a user admin for " + baseDn); businessRoles.put(baseDn, userDirectory); @@ -171,20 +177,9 @@ public class AggregatingUserAdmin implements UserAdmin { } /** Called after a new user directory has been added */ - protected void postAdd(AbstractUserDirectory userDirectory) { + protected void postAdd(UserDirectory userDirectory) { } -// private UserAdmin findUserAdmin(User user) { -// if (user == null) -// throw new IllegalArgumentException("User should not be null"); -// AbstractUserDirectory userAdmin = findUserAdmin(user.getName()); -// if (user instanceof DirectoryUser) { -// return userAdmin; -// } else { -// return userAdmin.scope(user); -// } -// } - private AbstractUserDirectory findUserAdmin(String name) { try { return findUserAdmin(new LdapName(name)); @@ -223,12 +218,12 @@ public class AggregatingUserAdmin implements UserAdmin { return res.get(0); } - protected boolean isSystemRolesBaseDn(LdapName baseDn) { - return baseDn.equals(systemRolesBaseDn); + protected boolean isSystemRolesBaseDn(String basePath) { + return toLdapName(basePath).equals(systemRolesBaseDn); } - protected boolean isTokensBaseDn(LdapName baseDn) { - return tokensBaseDn != null && baseDn.equals(tokensBaseDn); + protected boolean isTokensBaseDn(String basePath) { + return tokensBaseDn != null && toLdapName(basePath).equals(tokensBaseDn); } // protected Dictionary currentState() { @@ -258,9 +253,10 @@ public class AggregatingUserAdmin implements UserAdmin { userDirectory.destroy(); } - protected void removeUserDirectory(LdapName baseDn) { - if (isSystemRolesBaseDn(baseDn)) + protected void removeUserDirectory(String basePath) { + if (isSystemRolesBaseDn(basePath)) throw new UserDirectoryException("System roles cannot be removed "); + LdapName baseDn = toLdapName(basePath); if (!businessRoles.containsKey(baseDn)) throw new UserDirectoryException("No user directory registered for " + baseDn); AbstractUserDirectory userDirectory = businessRoles.remove(baseDn); @@ -271,7 +267,7 @@ public class AggregatingUserAdmin implements UserAdmin { * Called before each user directory is destroyed, so that additional actions * can be performed. */ - protected void preDestroy(AbstractUserDirectory userDirectory) { + protected void preDestroy(UserDirectory userDirectory) { } } diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/OsUserUtils.java b/org.argeo.util/src/org/argeo/osgi/useradmin/OsUserUtils.java index ad6bf8816..5d0cbf687 100644 --- a/org.argeo.util/src/org/argeo/osgi/useradmin/OsUserUtils.java +++ b/org.argeo.util/src/org/argeo/osgi/useradmin/OsUserUtils.java @@ -10,9 +10,10 @@ import javax.security.auth.login.Configuration; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; +/** Log in based on JDK-provided OS integration. */ public class OsUserUtils { - private static String LOGIN_CONTEXT_USER_NIX = "USER_NIX"; - private static String LOGIN_CONTEXT_USER_NT = "USER_NT"; + private final static String LOGIN_CONTEXT_USER_NIX = "USER_NIX"; + private final static String LOGIN_CONTEXT_USER_NT = "USER_NT"; public static String getOsUsername() { return System.getProperty("user.name"); diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/UserDirectory.java b/org.argeo.util/src/org/argeo/osgi/useradmin/UserDirectory.java index ff80c5ac8..7d773a9e7 100644 --- a/org.argeo.util/src/org/argeo/osgi/useradmin/UserDirectory.java +++ b/org.argeo.util/src/org/argeo/osgi/useradmin/UserDirectory.java @@ -1,15 +1,22 @@ package org.argeo.osgi.useradmin; -import javax.naming.ldap.LdapName; -import javax.transaction.xa.XAResource; +import java.util.Optional; + +import org.argeo.osgi.transaction.WorkControl; /** Information about a user directory. */ public interface UserDirectory { - /** The base DN of all entries in this user directory */ - LdapName getBaseDn(); + /** + * The base of the hierarchy defined by this directory. This could typically be + * an LDAP base DN. + */ + String getBasePath(); + +// /** The base DN of all entries in this user directory */ +// LdapName getBaseDn(); - /** The related {@link XAResource} */ - XAResource getXaResource(); +// /** The related {@link XAResource} */ +// XAResource getXaResource(); boolean isReadOnly(); @@ -22,4 +29,9 @@ public interface UserDirectory { String getGroupObjectClass(); String getGroupBase(); + + Optional getRealm(); + + @Deprecated + void setTransactionControl(WorkControl transactionControl); } diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/UserDirectoryException.java b/org.argeo.util/src/org/argeo/osgi/useradmin/UserDirectoryException.java index 613d0fdf0..0140a196d 100644 --- a/org.argeo.util/src/org/argeo/osgi/useradmin/UserDirectoryException.java +++ b/org.argeo.util/src/org/argeo/osgi/useradmin/UserDirectoryException.java @@ -6,6 +6,7 @@ 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;