From: Mathieu Baudier Date: Thu, 22 Sep 2022 06:51:25 +0000 (+0200) Subject: Multi-referentials bind working X-Git-Tag: v2.3.10~29 X-Git-Url: https://git.argeo.org/?p=lgpl%2Fargeo-commons.git;a=commitdiff_plain;h=da78fca0c8b99cabab454d704136e0313342292c Multi-referentials bind working --- diff --git a/org.argeo.cms/src/org/argeo/cms/auth/UserAdminLoginModule.java b/org.argeo.cms/src/org/argeo/cms/auth/UserAdminLoginModule.java index dd6575538..0ae84ff8a 100644 --- a/org.argeo.cms/src/org/argeo/cms/auth/UserAdminLoginModule.java +++ b/org.argeo.cms/src/org/argeo/cms/auth/UserAdminLoginModule.java @@ -31,8 +31,6 @@ import org.argeo.osgi.useradmin.AuthenticatingUser; import org.argeo.osgi.useradmin.TokenUtils; import org.argeo.util.directory.ldap.IpaUtils; import org.argeo.util.naming.LdapAttrs; -import org.osgi.framework.BundleContext; -import org.osgi.framework.FrameworkUtil; import org.osgi.service.useradmin.Authorization; import org.osgi.service.useradmin.Group; import org.osgi.service.useradmin.User; @@ -53,7 +51,7 @@ public class UserAdminLoginModule implements LoginModule { LdapAttrs.uid.name(), LdapAttrs.employeeNumber.name(), LdapAttrs.authPassword.name() }); // private state - private BundleContext bc; +// private BundleContext bc; private User authenticatedUser = null; private Locale locale; @@ -67,7 +65,7 @@ public class UserAdminLoginModule implements LoginModule { Map options) { this.subject = subject; try { - bc = FrameworkUtil.getBundle(UserAdminLoginModule.class).getBundleContext(); +// bc = FrameworkUtil.getBundle(UserAdminLoginModule.class).getBundleContext(); this.callbackHandler = callbackHandler; this.sharedState = (Map) sharedState; } catch (Exception e) { diff --git a/org.argeo.cms/src/org/argeo/cms/auth/UserAdminUtils.java b/org.argeo.cms/src/org/argeo/cms/auth/UserAdminUtils.java index 0d4830663..e3eb44249 100644 --- a/org.argeo.cms/src/org/argeo/cms/auth/UserAdminUtils.java +++ b/org.argeo.cms/src/org/argeo/cms/auth/UserAdminUtils.java @@ -76,6 +76,8 @@ public class UserAdminUtils { String dName = getProperty(user, LdapAttrs.displayName.name()); if (isEmpty(dName)) dName = getProperty(user, LdapAttrs.cn.name()); + if (isEmpty(dName)) + dName = getProperty(user, LdapAttrs.uid.name()); if (isEmpty(dName)) dName = getUserLocalId(user.getName()); return dName; 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 179099bad..83b2f1709 100644 --- a/org.argeo.util/src/org/argeo/osgi/useradmin/AggregatingUserAdmin.java +++ b/org.argeo.util/src/org/argeo/osgi/useradmin/AggregatingUserAdmin.java @@ -9,6 +9,7 @@ import java.util.HashSet; import java.util.Hashtable; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.TreeSet; @@ -88,6 +89,7 @@ public class AggregatingUserAdmin implements UserAdmin { return res.size() == 1 ? res.get(0) : null; } + /** Builds an authorisation by scanning all referentials. */ @Override public Authorization getAuthorization(User user) { if (user == null) {// anonymous @@ -120,21 +122,17 @@ public class AggregatingUserAdmin implements UserAdmin { for (LdapName otherBaseDn : businessRoles.keySet()) { if (otherBaseDn.equals(userReferentialOfThisUser.getBaseDn())) continue; - DirectoryUserAdmin otherUserAdmin = businessRoles.get(otherBaseDn); + DirectoryUserAdmin otherUserAdmin = userAdminToUse(user, businessRoles.get(otherBaseDn)); + if (otherUserAdmin == null) + continue; Authorization auth = otherUserAdmin.getAuthorization(retrievedUser); allRoles.addAll(Arrays.asList(auth.getRoles())); } // integrate system roles - final DirectoryUserAdmin userAdminToUse;// possibly scoped when authenticating - if (user instanceof DirectoryUser) { - userAdminToUse = userReferentialOfThisUser; - } else if (user instanceof AuthenticatingUser) { - userAdminToUse = (DirectoryUserAdmin) userReferentialOfThisUser.scope(user); - } else { - throw new IllegalArgumentException("Unsupported user type " + user.getClass()); - } + final DirectoryUserAdmin userAdminToUse = userAdminToUse(retrievedUser, userReferentialOfThisUser); + Objects.requireNonNull(userAdminToUse); try { Set sysRoles = new HashSet(); @@ -159,6 +157,18 @@ public class AggregatingUserAdmin implements UserAdmin { } } + /** Decide whether to scope or not */ + private DirectoryUserAdmin userAdminToUse(User user, DirectoryUserAdmin userAdmin) { + if (user instanceof DirectoryUser) { + return userAdmin; + } else if (user instanceof AuthenticatingUser) { + return userAdmin.scope(user).orElse(null); + } else { + throw new IllegalArgumentException("Unsupported user type " + user.getClass()); + } + + } + /** * Enrich with application-specific roles which are strictly programmatic, such * as anonymous/user semantics. diff --git a/org.argeo.util/src/org/argeo/osgi/useradmin/DirectoryUserAdmin.java b/org.argeo.util/src/org/argeo/osgi/useradmin/DirectoryUserAdmin.java index 1ed3d7ccb..3903a23f4 100644 --- a/org.argeo.util/src/org/argeo/osgi/useradmin/DirectoryUserAdmin.java +++ b/org.argeo.util/src/org/argeo/osgi/useradmin/DirectoryUserAdmin.java @@ -14,6 +14,7 @@ import java.util.Dictionary; import java.util.Hashtable; import java.util.Iterator; import java.util.List; +import java.util.Optional; import javax.naming.Context; import javax.naming.InvalidNameException; @@ -47,12 +48,8 @@ import org.osgi.service.useradmin.UserAdmin; public class DirectoryUserAdmin extends AbstractLdapDirectory implements UserAdmin, UserDirectory { private UserAdmin externalRoles; - // private List indexedUserProperties = Arrays - // .asList(new String[] { LdapAttrs.uid.name(), LdapAttrs.mail.name(), - // LdapAttrs.cn.name() }); // Transaction -// private TransactionManager transactionManager; public DirectoryUserAdmin(URI uriArg, Dictionary props) { this(uriArg, props, false); } @@ -69,7 +66,7 @@ public class DirectoryUserAdmin extends AbstractLdapDirectory implements UserAdm * ABSTRACT METHODS */ - protected AbstractLdapDirectory scope(User user) { + protected Optional scope(User user) { if (getDirectoryDao() instanceof LdapDao) { return scopeLdap(user); } else if (getDirectoryDao() instanceof LdifDao) { @@ -79,7 +76,7 @@ public class DirectoryUserAdmin extends AbstractLdapDirectory implements UserAdm } } - protected DirectoryUserAdmin scopeLdap(User user) { + protected Optional scopeLdap(User user) { Dictionary credentials = user.getCredentials(); String username = (String) credentials.get(SHARED_STATE_USERNAME); if (username == null) @@ -96,10 +93,13 @@ public class DirectoryUserAdmin extends AbstractLdapDirectory implements UserAdm } DirectoryUserAdmin scopedDirectory = new DirectoryUserAdmin(null, properties, true); scopedDirectory.init(); - return scopedDirectory; + // check connection + if (!scopedDirectory.getDirectoryDao().checkConnection()) + return Optional.empty(); + return Optional.of(scopedDirectory); } - protected DirectoryUserAdmin scopeLdif(User user) { + protected Optional scopeLdif(User user) { Dictionary credentials = user.getCredentials(); String username = (String) credentials.get(SHARED_STATE_USERNAME); if (username == null) @@ -117,12 +117,11 @@ public class DirectoryUserAdmin extends AbstractLdapDirectory implements UserAdm Dictionary properties = cloneConfigProperties(); properties.put(DirectoryConf.readOnly.name(), "true"); DirectoryUserAdmin scopedUserAdmin = new DirectoryUserAdmin(null, properties, true); -// scopedUserAdmin.groups = Collections.unmodifiableNavigableMap(groups); -// scopedUserAdmin.users = Collections.unmodifiableNavigableMap(users); // FIXME do it better ((LdifDao) getDirectoryDao()).scope((LdifDao) scopedUserAdmin.getDirectoryDao()); + // no need to check authentication scopedUserAdmin.init(); - return scopedUserAdmin; + return Optional.of(scopedUserAdmin); } @Override @@ -166,33 +165,6 @@ public class DirectoryUserAdmin extends AbstractLdapDirectory implements UserAdm if (e instanceof Role) allRoles.add((Role) e); } -// Attributes attrs = user.getAttributes(); -// // TODO centralize attribute name -// Attribute memberOf = attrs.get(LdapAttrs.memberOf.name()); -// // if user belongs to this directory, we only check memberOf -// if (memberOf != null && user.getDn().startsWith(getBaseDn())) { -// try { -// NamingEnumeration values = memberOf.getAll(); -// while (values.hasMore()) { -// Object value = values.next(); -// LdapName groupDn = new LdapName(value.toString()); -// DirectoryUser group = doGetRole(groupDn); -// if (group != null) -// allRoles.add(group); -// } -// } catch (NamingException e) { -// throw new IllegalStateException("Cannot get memberOf groups for " + user, e); -// } -// } else { -// for (LdapName groupDn : getDirectoryDao().getDirectGroups(user.getDn())) { -// // TODO check for loops -// DirectoryUser group = doGetRole(groupDn); -// if (group != null) { -// allRoles.add(group); -// collectRoles(group, allRoles); -// } -// } -// } } private void collectAnonymousRoles(List allRoles) { @@ -234,21 +206,6 @@ public class DirectoryUserAdmin extends AbstractLdapDirectory implements UserAdm // no need to check modified users, // since doGetRoles was already based on the modified attributes } - - // 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); -// } -// } return res; } @@ -299,9 +256,9 @@ public class DirectoryUserAdmin extends AbstractLdapDirectory implements UserAdm // TODO not only Kerberos but also bind scope with kept password ? Authorization auth = currentSubject.getPrivateCredentials(Authorization.class).iterator().next(); // bind with authenticating user - DirectoryUserAdmin scopedUserAdmin = Subject.doAs(currentSubject, - (PrivilegedAction) () -> (DirectoryUserAdmin) scope( - new AuthenticatingUser(auth.getName(), new Hashtable<>()))); + DirectoryUserAdmin scopedUserAdmin = CurrentSubject.callAs(currentSubject, () -> { + return scope(new AuthenticatingUser(auth.getName(), new Hashtable<>())).orElseThrow(); + }); return getAuthorizationFromScoped(scopedUserAdmin, user); } @@ -309,7 +266,7 @@ public class DirectoryUserAdmin extends AbstractLdapDirectory implements UserAdm return new LdifAuthorization(user, getAllRoles((DirectoryUser) user)); } else { // bind with authenticating user - DirectoryUserAdmin scopedUserAdmin = (DirectoryUserAdmin) scope(user); + DirectoryUserAdmin scopedUserAdmin = scope(user).orElseThrow(); return getAuthorizationFromScoped(scopedUserAdmin, user); } } @@ -384,22 +341,6 @@ public class DirectoryUserAdmin extends AbstractLdapDirectory implements UserAdm @Override public boolean removeRole(String name) { return removeEntry(LdapNameUtils.toLdapName(name)); -// checkEdit(); -// LdapEntryWorkingCopy wc = getWorkingCopy(); -// LdapName dn = toLdapName(name); -// boolean actuallyDeleted; -// if (getDirectoryDao().daoHasEntry(dn) || wc.getNewData().containsKey(dn)) { -// DirectoryUser user = (DirectoryUser) getRole(name); -// wc.getDeletedData().put(dn, user); -// actuallyDeleted = true; -// } else {// just removing from groups (e.g. system roles) -// actuallyDeleted = false; -// } -// for (LdapName groupDn : getDirectoryDao().getDirectGroups(dn)) { -// LdapEntry group = doGetRole(groupDn); -// group.getAttributes().get(getMemberAttributeId()).remove(dn.toString()); -// } -// return actuallyDeleted; } /* @@ -447,10 +388,6 @@ public class DirectoryUserAdmin extends AbstractLdapDirectory implements UserAdm this.externalRoles = externalRoles; } -// public void setTransactionManager(TransactionManager transactionManager) { -// this.transactionManager = transactionManager; -// } - /* * STATIC UTILITIES */ 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 80a9eea30..d7f6ad960 100644 --- a/org.argeo.util/src/org/argeo/osgi/useradmin/LdifAuthorization.java +++ b/org.argeo.util/src/org/argeo/osgi/useradmin/LdifAuthorization.java @@ -71,11 +71,11 @@ class LdifAuthorization implements Authorization { final static String extractDisplayName(User user) { Dictionary props = user.getProperties(); - Object displayName = props.get(LdapAttrs.displayName); + Object displayName = props.get(LdapAttrs.displayName.name()); if (displayName == null) - displayName = props.get(LdapAttrs.cn); + displayName = props.get(LdapAttrs.cn.name()); if (displayName == null) - displayName = props.get(LdapAttrs.uid); + displayName = props.get(LdapAttrs.uid.name()); if (displayName == null) displayName = user.getName(); if (displayName == null) 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 e1ad5edf5..5d7e97dde 100644 --- a/org.argeo.util/src/org/argeo/osgi/useradmin/OsUserDirectory.java +++ b/org.argeo.util/src/org/argeo/osgi/useradmin/OsUserDirectory.java @@ -40,10 +40,15 @@ public class OsUserDirectory extends AbstractLdapDirectoryDao { } @Override - public Boolean entryExists(LdapName dn) { + public boolean entryExists(LdapName dn) { return osUserDn.equals(dn); } + @Override + public boolean checkConnection() { + return true; + } + @Override public LdapEntry doGetEntry(LdapName key) throws NameNotFoundException { if (osUserDn.equals(key)) @@ -85,13 +90,13 @@ public class OsUserDirectory extends AbstractLdapDirectoryDao { @Override public void init() { // TODO Auto-generated method stub - + } @Override public void destroy() { // TODO Auto-generated method stub - + } @Override @@ -102,5 +107,5 @@ public class OsUserDirectory extends AbstractLdapDirectoryDao { throw new IllegalStateException(name + " doe not exist in " + getDirectory().getBaseDn(), e); } } - + } diff --git a/org.argeo.util/src/org/argeo/util/directory/ldap/AbstractLdapDirectory.java b/org.argeo.util/src/org/argeo/util/directory/ldap/AbstractLdapDirectory.java index 54d9776b5..04398bb4b 100644 --- a/org.argeo.util/src/org/argeo/util/directory/ldap/AbstractLdapDirectory.java +++ b/org.argeo.util/src/org/argeo/util/directory/ldap/AbstractLdapDirectory.java @@ -255,10 +255,6 @@ public abstract class AbstractLdapDirectory implements Directory, XAResourceProv } else { // user doesn't have the right to retrieve role, but we know it exists // otherwise memberOf would not work -// Attributes a = new BasicAttributes(); -// a.put(LdapNameUtils.getLastRdn(groupDn).getType(), -// LdapNameUtils.getLastRdn(groupDn).getValue()); -// a.put(LdapAttrs.objectClass.name(), LdapObjs.groupOfNames.name()); group = newGroup(groupDn); allRoles.add(group); } diff --git a/org.argeo.util/src/org/argeo/util/directory/ldap/LdapDao.java b/org.argeo.util/src/org/argeo/util/directory/ldap/LdapDao.java index e5ce0a4c1..0f6e324ad 100644 --- a/org.argeo.util/src/org/argeo/util/directory/ldap/LdapDao.java +++ b/org.argeo.util/src/org/argeo/util/directory/ldap/LdapDao.java @@ -27,10 +27,6 @@ import org.argeo.util.naming.LdapObjs; public class LdapDao extends AbstractLdapDirectoryDao { private LdapConnection ldapConnection; -// public LdapUserAdmin(Dictionary properties) { -// this(properties, false); -// } - public LdapDao(AbstractLdapDirectory directory) { super(directory); } @@ -44,31 +40,17 @@ public class LdapDao extends AbstractLdapDirectoryDao { ldapConnection.destroy(); } -// @Override -// protected AbstractUserDirectory scope(User user) { -// Dictionary credentials = user.getCredentials(); -// String username = (String) credentials.get(SHARED_STATE_USERNAME); -// if (username == null) -// username = user.getName(); -// Dictionary properties = cloneProperties(); -// properties.put(Context.SECURITY_PRINCIPAL, username.toString()); -// Object pwdCred = credentials.get(SHARED_STATE_PASSWORD); -// byte[] pwd = (byte[]) pwdCred; -// if (pwd != null) { -// char[] password = DirectoryDigestUtils.bytesToChars(pwd); -// properties.put(Context.SECURITY_CREDENTIALS, new String(password)); -// } else { -// properties.put(Context.SECURITY_AUTHENTICATION, "GSSAPI"); -// } -// return new LdapUserAdmin(properties, true); -// } - -// protected InitialLdapContext getLdapContext() { -// return initialLdapContext; -// } + @Override + public boolean checkConnection() { + try { + return ldapConnection.entryExists(getDirectory().getBaseDn()); + } catch (NamingException e) { + return false; + } + } @Override - public Boolean entryExists(LdapName dn) { + public boolean entryExists(LdapName dn) { try { return ldapConnection.entryExists(dn); } catch (NameNotFoundException e) { @@ -119,18 +101,6 @@ public class LdapDao extends AbstractLdapDirectoryDao { } } -// protected boolean isGroup(LdapName dn) { -// Rdn technicalRdn = LdapNameUtils.getParentRdn(dn); -// if (getDirectory().getGroupBaseRdn().equals(technicalRdn) -// || getDirectory().getSystemRoleBaseRdn().equals(technicalRdn)) -// return true; -// else if (getDirectory().getUserBaseRdn().equals(technicalRdn)) -// return false; -// else -// throw new IllegalArgumentException( -// "Cannot find role type, " + technicalRdn + " is not a technical RDN for " + dn); -// } - @Override public Attributes doGetAttributes(LdapName name) { try { diff --git a/org.argeo.util/src/org/argeo/util/directory/ldap/LdapDirectoryDao.java b/org.argeo.util/src/org/argeo/util/directory/ldap/LdapDirectoryDao.java index a4e65998c..f31780011 100644 --- a/org.argeo.util/src/org/argeo/util/directory/ldap/LdapDirectoryDao.java +++ b/org.argeo.util/src/org/argeo/util/directory/ldap/LdapDirectoryDao.java @@ -10,7 +10,9 @@ import org.argeo.util.directory.HierarchyUnit; import org.argeo.util.transaction.WorkingCopyProcessor; public interface LdapDirectoryDao extends WorkingCopyProcessor { - Boolean entryExists(LdapName dn); + boolean checkConnection(); + + boolean entryExists(LdapName dn); LdapEntry doGetEntry(LdapName name) throws NameNotFoundException; diff --git a/org.argeo.util/src/org/argeo/util/directory/ldap/LdifDao.java b/org.argeo.util/src/org/argeo/util/directory/ldap/LdifDao.java index 27a934377..c200faa27 100644 --- a/org.argeo.util/src/org/argeo/util/directory/ldap/LdifDao.java +++ b/org.argeo.util/src/org/argeo/util/directory/ldap/LdifDao.java @@ -160,7 +160,12 @@ public class LdifDao extends AbstractLdapDirectoryDao { } @Override - public Boolean entryExists(LdapName dn) { + public boolean checkConnection() { + return true; + } + + @Override + public boolean entryExists(LdapName dn) { return entries.containsKey(dn);// || groups.containsKey(dn); }