package org.argeo.cms.internal.auth;
-import static org.argeo.naming.LdapAttrs.cn;
-import static org.argeo.naming.LdapAttrs.description;
-import static org.argeo.naming.LdapAttrs.owner;
+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 java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.NavigableMap;
import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
import java.util.UUID;
-import javax.jcr.Node;
import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
import javax.security.auth.Subject;
-import javax.transaction.Status;
-import javax.transaction.UserTransaction;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import org.argeo.api.acr.NamespaceUtils;
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.api.cms.CmsLog;
import org.argeo.cms.CmsUserManager;
import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.auth.SystemRole;
import org.argeo.cms.auth.UserAdminUtils;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.naming.LdapAttrs;
-import org.argeo.naming.NamingUtils;
-import org.argeo.naming.SharedSecret;
-import org.argeo.node.NodeConstants;
+import org.argeo.osgi.useradmin.AggregatingUserAdmin;
import org.argeo.osgi.useradmin.TokenUtils;
-import org.argeo.osgi.useradmin.UserAdminConf;
+import org.argeo.osgi.useradmin.UserDirectory;
+import org.argeo.util.directory.DirectoryConf;
+import org.argeo.util.directory.HierarchyUnit;
+import org.argeo.util.directory.ldap.LdapEntry;
+import org.argeo.util.directory.ldap.SharedSecret;
+import org.argeo.util.naming.LdapAttrs;
+import org.argeo.util.naming.NamingUtils;
+import org.argeo.util.transaction.WorkTransaction;
import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
import org.osgi.service.useradmin.Authorization;
import org.osgi.service.useradmin.Group;
import org.osgi.service.useradmin.Role;
* </ul>
*/
public class CmsUserManagerImpl implements CmsUserManager {
- private final static Log log = LogFactory.getLog(CmsUserManagerImpl.class);
+ private final static CmsLog log = CmsLog.getLog(CmsUserManagerImpl.class);
private UserAdmin userAdmin;
- @Deprecated
- private ServiceReference<UserAdmin> userAdminServiceReference;
- private Map<String, String> serviceProperties;
- private UserTransaction userTransaction;
+// private Map<String, String> serviceProperties;
+ private WorkTransaction userTransaction;
+
+ private final String[] knownProps = { LdapAttrs.cn.name(), LdapAttrs.sn.name(), LdapAttrs.givenName.name(),
+ LdapAttrs.uid.name() };
+
+// private Map<UserDirectory, Hashtable<String, Object>> userDirectories = Collections
+// .synchronizedMap(new LinkedHashMap<>());
+
+ private Set<UserDirectory> userDirectories = new HashSet<>();
+
+ public void start() {
+ log.debug(() -> "CMS user manager available");
+ }
+
+ public void stop() {
+
+ }
@Override
public String getMyMail() {
return false;
}
- private final String[] knownProps = { LdapAttrs.cn.name(), LdapAttrs.sn.name(), LdapAttrs.givenName.name(),
- LdapAttrs.uid.name() };
-
public Set<User> listUsersInGroup(String groupDn, String filter) {
Group group = (Group) userAdmin.getRole(groupDn);
if (group == null)
addUsers(users, group, filter);
return users;
}
+
+
+
+// @Override
+// public Set<User> listAccounts(HierarchyUnit hierarchyUnit, boolean deep) {
+// if(!hierarchyUnit.isFunctional())
+// throw new IllegalArgumentException("Hierarchy unit "+hierarchyUnit.getBase()+" is not functional");
+// UserDirectory directory = (UserDirectory)hierarchyUnit.getDirectory();
+// Set<User> 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<User> users, Group group, String filter) {
List<User> users = new ArrayList<User>();
for (Role role : roles) {
if ((includeUsers && role.getType() == Role.USER || role.getType() == Role.GROUP) && !users.contains(role)
- && (includeSystemRoles || !role.getName().toLowerCase().endsWith(NodeConstants.ROLES_BASEDN))) {
+ && (includeSystemRoles || !role.getName().toLowerCase().endsWith(CmsConstants.SYSTEM_ROLES_BASEDN))) {
if (match(role, filter))
users.add((User) role);
}
return buildDistinguishedName(localId, getDefaultDomainName(), type);
}
+ /*
+ * EDITION
+ */
+ @Override
+ public User createUser(String username, Map<String, Object> properties, Map<String, Object> credentials) {
+ try {
+ userTransaction.begin();
+ User user = (User) 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 Group getOrCreateGroup(HierarchyUnit groups, String commonName) {
+ try {
+ String dn = LdapAttrs.cn.name() + "=" + commonName + "," + groups.getBase();
+ Group group = (Group) getUserAdmin().getRole(dn);
+ if (group != null)
+ return group;
+ userTransaction.begin();
+ group = (Group) 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 Group getOrCreateSystemRole(HierarchyUnit roles, SystemRole systemRole) {
+ try {
+ String dn = LdapAttrs.cn.name() + "=" + NamespaceUtils.toPrefixedName(systemRole.getName()) + ","
+ + roles.getBase();
+ Group group = (Group) getUserAdmin().getRole(dn);
+ if (group != null)
+ return group;
+ userTransaction.begin();
+ group = (Group) 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<String> objectClasses, Map<String, Object> 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 addMember(Group 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<String, String> dns = getKnownBaseDns(true);
public Map<String, String> getKnownBaseDns(boolean onlyWritable) {
Map<String, String> dns = new HashMap<String, String>();
- String[] propertyKeys = userAdminServiceReference != null ? userAdminServiceReference.getPropertyKeys()
- : serviceProperties.keySet().toArray(new String[serviceProperties.size()]);
- for (String uri : propertyKeys) {
- if (!uri.startsWith("/"))
- continue;
- Dictionary<String, ?> props = UserAdminConf.uriAsProperties(uri);
- String readOnly = UserAdminConf.readOnly.getValue(props);
- String baseDn = UserAdminConf.baseDn.getValue(props);
+ for (UserDirectory userDirectory : userDirectories) {
+ Boolean readOnly = userDirectory.isReadOnly();
+ String baseDn = userDirectory.getBase();
- if (onlyWritable && "true".equals(readOnly))
+ if (onlyWritable && readOnly)
continue;
- if (baseDn.equalsIgnoreCase(NodeConstants.ROLES_BASEDN))
+ if (baseDn.equalsIgnoreCase(CmsConstants.SYSTEM_ROLES_BASEDN))
continue;
- if (baseDn.equalsIgnoreCase(NodeConstants.TOKENS_BASEDN))
+ if (baseDn.equalsIgnoreCase(CmsConstants.TOKENS_BASEDN))
continue;
- dns.put(baseDn, uri);
+ dns.put(baseDn, DirectoryConf.propertiesAsUri(userDirectory.getProperties()).toString());
+
}
return dns;
}
+ public Set<UserDirectory> getUserDirectories() {
+ TreeSet<UserDirectory> 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<String, String> dns = getKnownBaseDns(true);
- Dictionary<String, ?> props = UserAdminConf.uriAsProperties(dns.get(baseDn));
+ Dictionary<String, ?> 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;
return tokenStr;
} catch (Exception e1) {
try {
- if (userTransaction.getStatus() != Status.STATUS_NO_TRANSACTION)
+ if (!userTransaction.isNoTransactionStatus())
userTransaction.rollback();
} catch (Exception e2) {
if (log.isTraceEnabled())
public void expireAuthToken(String token) {
try {
userTransaction.begin();
- String dn = cn + "=" + token + "," + NodeConstants.TOKENS_BASEDN;
+ String dn = cn + "=" + token + "," + CmsConstants.TOKENS_BASEDN;
Group tokenGroup = (Group) userAdmin.getRole(dn);
String ldapDate = NamingUtils.instantToLdapDate(ZonedDateTime.now(ZoneOffset.UTC));
tokenGroup.getProperties().put(description.name(), ldapDate);
log.debug("Token " + token + " expired.");
} catch (Exception e1) {
try {
- if (userTransaction.getStatus() != Status.STATUS_NO_TRANSACTION)
+ if (!userTransaction.isNoTransactionStatus())
userTransaction.rollback();
} catch (Exception e2) {
if (log.isTraceEnabled())
@Override
public void expireAuthTokens(Subject subject) {
- Set<String> tokens = TokenUtils.tokensUsed(subject, NodeConstants.TOKENS_BASEDN);
+ Set<String> tokens = TokenUtils.tokensUsed(subject, CmsConstants.TOKENS_BASEDN);
for (String token : tokens)
expireAuthToken(token);
}
@Override
public void addAuthToken(String userDn, String token, Integer hours, String... roles) {
+ addAuthToken(userDn, token, ZonedDateTime.now().plusHours(hours), roles);
+ }
+
+ @Override
+ public void addAuthToken(String userDn, String token, ZonedDateTime expiryDate, String... roles) {
try {
userTransaction.begin();
User user = (User) userAdmin.getRole(userDn);
- String tokenDn = cn + "=" + token + "," + NodeConstants.TOKENS_BASEDN;
+ String tokenDn = cn + "=" + token + "," + CmsConstants.TOKENS_BASEDN;
Group tokenGroup = (Group) userAdmin.createRole(tokenDn, Role.GROUP);
- for (String role : roles) {
- Role r = userAdmin.getRole(role);
- if (r != null)
- tokenGroup.addMember(r);
- else {
- if (!role.equals(NodeConstants.ROLE_USER)) {
- throw new IllegalStateException(
- "Cannot add role " + role + " to token " + token + " for " + userDn);
+ if (roles != null)
+ for (String role : roles) {
+ Role r = userAdmin.getRole(role);
+ if (r != null)
+ tokenGroup.addMember(r);
+ else {
+ if (!role.equals(CmsConstants.ROLE_USER)) {
+ throw new IllegalStateException(
+ "Cannot add role " + role + " to token " + token + " for " + userDn);
+ }
}
}
- }
tokenGroup.getProperties().put(owner.name(), user.getName());
- if (hours != null) {
- String ldapDate = NamingUtils.instantToLdapDate(ZonedDateTime.now().plusHours(hours));
+ if (expiryDate != null) {
+ String ldapDate = NamingUtils.instantToLdapDate(expiryDate);
tokenGroup.getProperties().put(description.name(), ldapDate);
}
userTransaction.commit();
} catch (Exception e1) {
try {
- if (userTransaction.getStatus() != Status.STATUS_NO_TRANSACTION)
+ if (!userTransaction.isNoTransactionStatus())
userTransaction.rollback();
} catch (Exception e2) {
if (log.isTraceEnabled())
}
}
- public User createUserFromPerson(Node person) {
- String email = JcrUtils.get(person, LdapAttrs.mail.property());
- String dn = buildDefaultDN(email, Role.USER);
- User user;
- try {
- userTransaction.begin();
- user = (User) userAdmin.createRole(dn, Role.USER);
- Dictionary<String, Object> userProperties = user.getProperties();
- String name = JcrUtils.get(person, LdapAttrs.displayName.property());
- userProperties.put(LdapAttrs.cn.name(), name);
- userProperties.put(LdapAttrs.displayName.name(), name);
- String givenName = JcrUtils.get(person, LdapAttrs.givenName.property());
- String surname = JcrUtils.get(person, LdapAttrs.sn.property());
- userProperties.put(LdapAttrs.givenName.name(), givenName);
- userProperties.put(LdapAttrs.sn.name(), surname);
- userProperties.put(LdapAttrs.mail.name(), email.toLowerCase());
- userTransaction.commit();
- } catch (Exception e) {
- try {
- userTransaction.rollback();
- } catch (Exception e1) {
- log.error("Could not roll back", e1);
+ @Override
+ public UserDirectory getDirectory(Role user) {
+ String name = user.getName();
+ NavigableMap<String, UserDirectory> possible = new TreeMap<>();
+ for (UserDirectory userDirectory : userDirectories) {
+ if (name.endsWith(userDirectory.getBase())) {
+ possible.put(userDirectory.getBase(), userDirectory);
}
- if (e instanceof RuntimeException)
- throw (RuntimeException) e;
- else
- throw new RuntimeException("Cannot create user", e);
}
- return user;
+ 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);
+// User user;
+// try {
+// userTransaction.begin();
+// user = (User) userAdmin.createRole(dn, Role.USER);
+// Dictionary<String, Object> userProperties = user.getProperties();
+// String name = JcrUtils.get(person, LdapAttrs.displayName.property());
+// userProperties.put(LdapAttrs.cn.name(), name);
+// userProperties.put(LdapAttrs.displayName.name(), name);
+// String givenName = JcrUtils.get(person, LdapAttrs.givenName.property());
+// String surname = JcrUtils.get(person, LdapAttrs.sn.property());
+// userProperties.put(LdapAttrs.givenName.name(), givenName);
+// userProperties.put(LdapAttrs.sn.name(), surname);
+// userProperties.put(LdapAttrs.mail.name(), email.toLowerCase());
+// userTransaction.commit();
+// } 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", e);
+// }
+// return user;
+// }
+
public UserAdmin getUserAdmin() {
return userAdmin;
}
- public UserTransaction getUserTransaction() {
- return userTransaction;
- }
+// public UserTransaction getUserTransaction() {
+// return userTransaction;
+// }
/* DEPENDENCY INJECTION */
- public void setUserAdmin(UserAdmin userAdmin, Map<String, String> serviceProperties) {
+ public void setUserAdmin(UserAdmin userAdmin) {
this.userAdmin = userAdmin;
- this.serviceProperties = serviceProperties;
+
+ if (userAdmin instanceof AggregatingUserAdmin) {
+ userDirectories = ((AggregatingUserAdmin) userAdmin).getUserDirectories();
+ } else {
+ throw new IllegalArgumentException("Only " + AggregatingUserAdmin.class.getName() + " is supported.");
+ }
+
+// this.serviceProperties = serviceProperties;
}
- public void setUserTransaction(UserTransaction userTransaction) {
+ public void setUserTransaction(WorkTransaction userTransaction) {
this.userTransaction = userTransaction;
}
+
+// public void addUserDirectory(UserDirectory userDirectory, Map<String, Object> properties) {
+// userDirectories.put(userDirectory, new Hashtable<>(properties));
+// }
+//
+// public void removeUserDirectory(UserDirectory userDirectory, Map<String, Object> properties) {
+// userDirectories.remove(userDirectory);
+// }
+
}