X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=org.argeo.cms%2Fsrc%2Forg%2Fargeo%2Fcms%2Finternal%2Fauth%2FCmsUserManagerImpl.java;h=94262a52178d1df83f6a9b98b4de66857356cce3;hb=e018ad9078249a806f2e2ef86a6adcbd8cca3188;hp=84562ebd16660a860df397778421037581f9ba64;hpb=e168383bac50637131fef8c41e119db7eb2284a7;p=lgpl%2Fargeo-commons.git 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 84562ebd1..94262a521 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 @@ -1,41 +1,48 @@ package org.argeo.cms.internal.auth; -import static org.argeo.util.naming.LdapAttrs.cn; -import static org.argeo.util.naming.LdapAttrs.description; -import static org.argeo.util.naming.LdapAttrs.owner; +import static org.argeo.api.acr.ldap.LdapAttrs.cn; +import static org.argeo.api.acr.ldap.LdapAttrs.description; +import static org.argeo.api.acr.ldap.LdapAttrs.owner; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.Dictionary; import java.util.HashMap; import java.util.HashSet; -import java.util.Hashtable; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.NavigableMap; +import java.util.Objects; import java.util.Set; +import java.util.TreeMap; import java.util.TreeSet; import java.util.UUID; import javax.naming.InvalidNameException; import javax.naming.ldap.LdapName; import javax.security.auth.Subject; +import javax.xml.namespace.QName; +import org.argeo.api.acr.NamespaceUtils; +import org.argeo.api.acr.ldap.LdapAttrs; +import org.argeo.api.acr.ldap.NamingUtils; import org.argeo.api.cms.CmsConstants; import org.argeo.api.cms.CmsLog; +import org.argeo.api.cms.directory.CmsGroup; +import org.argeo.api.cms.directory.CmsUser; +import org.argeo.api.cms.directory.HierarchyUnit; +import org.argeo.api.cms.directory.UserDirectory; +import org.argeo.api.cms.transaction.WorkTransaction; import org.argeo.cms.CmsUserManager; import org.argeo.cms.auth.CurrentUser; import org.argeo.cms.auth.UserAdminUtils; -import org.argeo.osgi.transaction.WorkTransaction; -import org.argeo.osgi.useradmin.TokenUtils; -import org.argeo.osgi.useradmin.UserAdminConf; -import org.argeo.osgi.useradmin.UserDirectory; -import org.argeo.util.naming.LdapAttrs; -import org.argeo.util.naming.NamingUtils; -import org.argeo.util.naming.SharedSecret; +import org.argeo.cms.directory.ldap.LdapEntry; +import org.argeo.cms.directory.ldap.SharedSecret; +import org.argeo.cms.osgi.useradmin.AggregatingUserAdmin; +import org.argeo.cms.osgi.useradmin.TokenUtils; +import org.argeo.cms.runtime.DirectoryConf; import org.osgi.framework.InvalidSyntaxException; import org.osgi.service.useradmin.Authorization; import org.osgi.service.useradmin.Group; @@ -62,8 +69,21 @@ public class CmsUserManagerImpl implements CmsUserManager { // private Map serviceProperties; private WorkTransaction userTransaction; - private Map> userDirectories = Collections - .synchronizedMap(new LinkedHashMap<>()); + private final String[] knownProps = { LdapAttrs.cn.name(), LdapAttrs.sn.name(), LdapAttrs.givenName.name(), + LdapAttrs.uid.name() }; + +// private Map> userDirectories = Collections +// .synchronizedMap(new LinkedHashMap<>()); + + private Set userDirectories = new HashSet<>(); + + public void start() { + log.debug(() -> "CMS user manager available"); + } + + public void stop() { + + } @Override public String getMyMail() { @@ -77,9 +97,9 @@ public class CmsUserManagerImpl implements CmsUserManager { // ALL USER: WARNING access to this will be later reduced - /** Retrieve a user given his dn */ - public User getUser(String dn) { - return (User) getUserAdmin().getRole(dn); + /** Retrieve a user given his dn, or null if it doesn't exist. */ + public CmsUser getUser(String dn) { + return (CmsUser) getUserAdmin().getRole(dn); } /** Can be a group or a user */ @@ -114,34 +134,47 @@ public class CmsUserManagerImpl implements CmsUserManager { return false; } - private final String[] knownProps = { LdapAttrs.cn.name(), LdapAttrs.sn.name(), LdapAttrs.givenName.name(), - LdapAttrs.uid.name() }; - - public Set listUsersInGroup(String groupDn, String filter) { + public Set listUsersInGroup(String groupDn, String filter) { Group group = (Group) userAdmin.getRole(groupDn); if (group == null) throw new IllegalArgumentException("Group " + groupDn + " not found"); - Set users = new HashSet(); + Set users = new HashSet<>(); addUsers(users, group, filter); return users; } +// @Override +// public Set listAccounts(HierarchyUnit hierarchyUnit, boolean deep) { +// if(!hierarchyUnit.isFunctional()) +// throw new IllegalArgumentException("Hierarchy unit "+hierarchyUnit.getBase()+" is not functional"); +// UserDirectory directory = (UserDirectory)hierarchyUnit.getDirectory(); +// Set res = new HashSet<>(); +// for(HierarchyUnit technicalHu:hierarchyUnit.getDirectHierarchyUnits(false)) { +// if(technicalHu.isFunctional()) +// continue; +// for(Role role:directory.getHierarchyUnitRoles(technicalHu, null, false)) { +// if(role) +// } +// } +// return res; +// } + /** Recursively add users to list */ - private void addUsers(Set users, Group group, String filter) { + private void addUsers(Set users, Group group, String filter) { Role[] roles = group.getMembers(); for (Role role : roles) { if (role.getType() == Role.GROUP) { - addUsers(users, (Group) role, filter); + addUsers(users, (CmsGroup) role, filter); } else if (role.getType() == Role.USER) { if (match(role, filter)) - users.add((User) role); + users.add((CmsUser) role); } else { // ignore } } } - public List listGroups(String filter, boolean includeUsers, boolean includeSystemRoles) { + public List listGroups(String filter, boolean includeUsers, boolean includeSystemRoles) { Role[] roles = null; try { roles = getUserAdmin().getRoles(filter); @@ -149,12 +182,13 @@ public class CmsUserManagerImpl implements CmsUserManager { throw new IllegalArgumentException("Unable to get roles with filter: " + filter, e); } - List users = new ArrayList(); + List users = new ArrayList<>(); for (Role role : roles) { if ((includeUsers && role.getType() == Role.USER || role.getType() == Role.GROUP) && !users.contains(role) - && (includeSystemRoles || !role.getName().toLowerCase().endsWith(CmsConstants.ROLES_BASEDN))) { + && (includeSystemRoles + || !role.getName().toLowerCase().endsWith(CmsConstants.SYSTEM_ROLES_BASEDN))) { if (match(role, filter)) - users.add((User) role); + users.add((CmsUser) role); } } return users; @@ -183,10 +217,10 @@ public class CmsUserManagerImpl implements CmsUserManager { } @Override - public User getUserFromLocalId(String localId) { - User user = getUserAdmin().getUser(LdapAttrs.uid.name(), localId); + public CmsUser getUserFromLocalId(String localId) { + CmsUser user = (CmsUser) getUserAdmin().getUser(LdapAttrs.uid.name(), localId); if (user == null) - user = getUserAdmin().getUser(LdapAttrs.cn.name(), localId); + user = (CmsUser) getUserAdmin().getUser(LdapAttrs.cn.name(), localId); return user; } @@ -195,6 +229,188 @@ public class CmsUserManagerImpl implements CmsUserManager { return buildDistinguishedName(localId, getDefaultDomainName(), type); } + /* + * EDITION + */ + @Override + public CmsUser createUser(String username, Map properties, Map credentials) { + try { + userTransaction.begin(); + CmsUser user = (CmsUser) userAdmin.createRole(username, Role.USER); + if (properties != null) { + for (String key : properties.keySet()) + user.getProperties().put(key, properties.get(key)); + } + if (credentials != null) { + for (String key : credentials.keySet()) + user.getCredentials().put(key, credentials.get(key)); + } + userTransaction.commit(); + return user; + } catch (Exception e) { + try { + userTransaction.rollback(); + } catch (Exception e1) { + log.error("Could not roll back", e1); + } + if (e instanceof RuntimeException) + throw (RuntimeException) e; + else + throw new RuntimeException("Cannot create user " + username, e); + } + } + + @Override + public CmsGroup getOrCreateGroup(HierarchyUnit groups, String commonName) { + try { + String dn = LdapAttrs.cn.name() + "=" + commonName + "," + groups.getBase(); + CmsGroup group = (CmsGroup) getUserAdmin().getRole(dn); + if (group != null) + return group; + userTransaction.begin(); + group = (CmsGroup) userAdmin.createRole(dn, Role.GROUP); + userTransaction.commit(); + return group; + } catch (Exception e) { + try { + userTransaction.rollback(); + } catch (Exception e1) { + log.error("Could not roll back", e1); + } + if (e instanceof RuntimeException) + throw (RuntimeException) e; + else + throw new RuntimeException("Cannot create group " + commonName + " in " + groups, e); + } + } + + @Override + public CmsGroup getOrCreateSystemRole(HierarchyUnit roles, QName systemRole) { + try { + String dn = LdapAttrs.cn.name() + "=" + NamespaceUtils.toPrefixedName(systemRole) + "," + + roles.getBase(); + CmsGroup group = (CmsGroup) getUserAdmin().getRole(dn); + if (group != null) + return group; + userTransaction.begin(); + group = (CmsGroup) userAdmin.createRole(dn, Role.GROUP); + userTransaction.commit(); + return group; + } catch (Exception e) { + try { + userTransaction.rollback(); + } catch (Exception e1) { + log.error("Could not roll back", e1); + } + if (e instanceof RuntimeException) + throw (RuntimeException) e; + else + throw new RuntimeException("Cannot create system role " + systemRole + " in " + roles, e); + } + } + + @Override + public HierarchyUnit getOrCreateHierarchyUnit(UserDirectory directory, String path) { + HierarchyUnit hi = directory.getHierarchyUnit(path); + if (hi != null) + return hi; + try { + userTransaction.begin(); + HierarchyUnit hierarchyUnit = directory.createHierarchyUnit(path); + userTransaction.commit(); + return hierarchyUnit; + } catch (Exception e1) { + try { + if (!userTransaction.isNoTransactionStatus()) + userTransaction.rollback(); + } catch (Exception e2) { + if (log.isTraceEnabled()) + log.trace("Cannot rollback transaction", e2); + } + throw new RuntimeException("Cannot create hierarchy unit " + path + " in directory " + directory, e1); + } + } + + @Override + public void addObjectClasses(Role role, Set objectClasses, Map additionalProperties) { + try { + userTransaction.begin(); + LdapEntry.addObjectClasses(role.getProperties(), objectClasses); + for (String key : additionalProperties.keySet()) { + role.getProperties().put(key, additionalProperties.get(key)); + } + userTransaction.commit(); + } catch (Exception e1) { + try { + if (!userTransaction.isNoTransactionStatus()) + userTransaction.rollback(); + } catch (Exception e2) { + if (log.isTraceEnabled()) + log.trace("Cannot rollback transaction", e2); + } + throw new RuntimeException("Cannot add object classes " + objectClasses + " to " + role, e1); + } + } + + @Override + public void addObjectClasses(HierarchyUnit hierarchyUnit, Set objectClasses, + Map additionalProperties) { + try { + userTransaction.begin(); + LdapEntry.addObjectClasses(hierarchyUnit.getProperties(), objectClasses); + for (String key : additionalProperties.keySet()) { + hierarchyUnit.getProperties().put(key, additionalProperties.get(key)); + } + userTransaction.commit(); + } catch (Exception e1) { + try { + if (!userTransaction.isNoTransactionStatus()) + userTransaction.rollback(); + } catch (Exception e2) { + if (log.isTraceEnabled()) + log.trace("Cannot rollback transaction", e2); + } + throw new RuntimeException("Cannot add object classes " + objectClasses + " to " + hierarchyUnit, e1); + } + } + + @Override + public void edit(Runnable action) { + Objects.requireNonNull(action); + try { + userTransaction.begin(); + action.run(); + userTransaction.commit(); + } catch (Exception e1) { + try { + if (!userTransaction.isNoTransactionStatus()) + userTransaction.rollback(); + } catch (Exception e2) { + if (log.isTraceEnabled()) + log.trace("Cannot rollback transaction", e2); + } + throw new RuntimeException("Cannot edit", e1); + } + } + + @Override + public void addMember(CmsGroup group, Role role) { + try { + userTransaction.begin(); + group.addMember(role); + userTransaction.commit(); + } catch (Exception e1) { + try { + if (!userTransaction.isNoTransactionStatus()) + userTransaction.rollback(); + } catch (Exception e2) { + if (log.isTraceEnabled()) + log.trace("Cannot rollback transaction", e2); + } + throw new RuntimeException("Cannot add object classes " + role + " to group " + group, e1); + } + } + @Override public String getDefaultDomainName() { Map dns = getKnownBaseDns(true); @@ -205,59 +421,38 @@ public class CmsUserManagerImpl implements CmsUserManager { + dns.keySet().toString() + ". Unable to chose a default one."); } -// public Map getKnownBaseDns(boolean onlyWritable) { -// Map dns = new HashMap(); -// String[] propertyKeys = serviceProperties.keySet().toArray(new String[serviceProperties.size()]); -// for (String uri : propertyKeys) { -// if (!uri.startsWith("/")) -// continue; -// Dictionary props = UserAdminConf.uriAsProperties(uri); -// String readOnly = UserAdminConf.readOnly.getValue(props); -// String baseDn = UserAdminConf.baseDn.getValue(props); -// -// if (onlyWritable && "true".equals(readOnly)) -// continue; -// if (baseDn.equalsIgnoreCase(NodeConstants.ROLES_BASEDN)) -// continue; -// if (baseDn.equalsIgnoreCase(NodeConstants.TOKENS_BASEDN)) -// continue; -// dns.put(baseDn, uri); -// } -// return dns; -// } - public Map getKnownBaseDns(boolean onlyWritable) { Map dns = new HashMap(); - for (UserDirectory userDirectory : userDirectories.keySet()) { + for (UserDirectory userDirectory : userDirectories) { Boolean readOnly = userDirectory.isReadOnly(); - String baseDn = userDirectory.getBasePath(); + String baseDn = userDirectory.getBase(); if (onlyWritable && readOnly) continue; - if (baseDn.equalsIgnoreCase(CmsConstants.ROLES_BASEDN)) + if (baseDn.equalsIgnoreCase(CmsConstants.SYSTEM_ROLES_BASEDN)) continue; if (baseDn.equalsIgnoreCase(CmsConstants.TOKENS_BASEDN)) continue; - dns.put(baseDn, UserAdminConf.propertiesAsUri(userDirectories.get(userDirectory)).toString()); + dns.put(baseDn, DirectoryConf.propertiesAsUri(userDirectory.getProperties()).toString()); } return dns; } public Set getUserDirectories() { - TreeSet res = new TreeSet<>((o1, o2) -> o1.getBasePath().compareTo(o2.getBasePath())); - res.addAll(userDirectories.keySet()); + TreeSet res = new TreeSet<>((o1, o2) -> o1.getBase().compareTo(o2.getBase())); + res.addAll(userDirectories); return res; } public String buildDistinguishedName(String localId, String baseDn, int type) { Map dns = getKnownBaseDns(true); - Dictionary props = UserAdminConf.uriAsProperties(dns.get(baseDn)); + Dictionary props = DirectoryConf.uriAsProperties(dns.get(baseDn)); String dn = null; if (Role.GROUP == type) - dn = LdapAttrs.cn.name() + "=" + localId + "," + UserAdminConf.groupBase.getValue(props) + "," + baseDn; + dn = LdapAttrs.cn.name() + "=" + localId + "," + DirectoryConf.groupBase.getValue(props) + "," + baseDn; else if (Role.USER == type) - dn = LdapAttrs.uid.name() + "=" + localId + "," + UserAdminConf.userBase.getValue(props) + "," + baseDn; + dn = LdapAttrs.uid.name() + "=" + localId + "," + DirectoryConf.userBase.getValue(props) + "," + baseDn; else throw new IllegalStateException("Unknown role type. " + "Cannot deduce dn for " + localId); return dn; @@ -438,6 +633,20 @@ public class CmsUserManagerImpl implements CmsUserManager { } } + @Override + public UserDirectory getDirectory(Role user) { + String name = user.getName(); + NavigableMap possible = new TreeMap<>(); + for (UserDirectory userDirectory : userDirectories) { + if (name.endsWith(userDirectory.getBase())) { + possible.put(userDirectory.getBase(), userDirectory); + } + } + if (possible.size() == 0) + throw new IllegalStateException("No user directory found for user " + name); + return possible.lastEntry().getValue(); + } + // public User createUserFromPerson(Node person) { // String email = JcrUtils.get(person, LdapAttrs.mail.property()); // String dn = buildDefaultDN(email, Role.USER); @@ -480,6 +689,13 @@ public class CmsUserManagerImpl implements CmsUserManager { /* DEPENDENCY INJECTION */ public void setUserAdmin(UserAdmin userAdmin) { this.userAdmin = userAdmin; + + if (userAdmin instanceof AggregatingUserAdmin) { + userDirectories = ((AggregatingUserAdmin) userAdmin).getUserDirectories(); + } else { + throw new IllegalArgumentException("Only " + AggregatingUserAdmin.class.getName() + " is supported."); + } + // this.serviceProperties = serviceProperties; } @@ -487,12 +703,12 @@ public class CmsUserManagerImpl implements CmsUserManager { this.userTransaction = userTransaction; } - public void addUserDirectory(UserDirectory userDirectory, Map properties) { - userDirectories.put(userDirectory, new Hashtable<>(properties)); - } - - public void removeUserDirectory(UserDirectory userDirectory, Map properties) { - userDirectories.remove(userDirectory); - } +// public void addUserDirectory(UserDirectory userDirectory, Map properties) { +// userDirectories.put(userDirectory, new Hashtable<>(properties)); +// } +// +// public void removeUserDirectory(UserDirectory userDirectory, Map properties) { +// userDirectories.remove(userDirectory); +// } }