import javax.annotation.PreDestroy;
import javax.inject.Inject;
+import org.argeo.cms.auth.UserAdminUtils;
import org.argeo.cms.ui.eclipse.forms.AbstractFormPart;
import org.argeo.cms.ui.eclipse.forms.IManagedForm;
import org.argeo.cms.ui.eclipse.forms.ManagedForm;
-import org.argeo.cms.util.UserAdminUtils;
import org.argeo.eclipse.ui.EclipseUiUtils;
import org.argeo.naming.LdapAttrs;
import org.eclipse.core.runtime.IProgressMonitor;
*/
package org.argeo.cms.e4.users;
-import static org.argeo.cms.util.UserAdminUtils.setProperty;
+import static org.argeo.cms.auth.UserAdminUtils.setProperty;
import static org.argeo.naming.LdapAttrs.businessCategory;
import static org.argeo.naming.LdapAttrs.description;
import static org.argeo.node.NodeInstance.WORKGROUP;
import javax.transaction.UserTransaction;
import org.argeo.cms.CmsException;
+import org.argeo.cms.auth.UserAdminUtils;
import org.argeo.cms.e4.users.providers.CommonNameLP;
import org.argeo.cms.e4.users.providers.MailLP;
import org.argeo.cms.e4.users.providers.RoleIconLP;
import org.argeo.cms.ui.eclipse.forms.AbstractFormPart;
import org.argeo.cms.ui.eclipse.forms.IManagedForm;
import org.argeo.cms.util.CmsUtils;
-import org.argeo.cms.util.UserAdminUtils;
import org.argeo.eclipse.ui.ColumnDefinition;
import org.argeo.eclipse.ui.EclipseUiUtils;
import org.argeo.eclipse.ui.parts.LdifUsersTable;
import org.apache.commons.logging.LogFactory;
import org.argeo.cms.CmsException;
import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.auth.UserAdminUtils;
import org.argeo.cms.e4.users.providers.CommonNameLP;
import org.argeo.cms.e4.users.providers.DomainNameLP;
import org.argeo.cms.e4.users.providers.MailLP;
import org.argeo.cms.e4.users.providers.UserNameLP;
-import org.argeo.cms.util.UserAdminUtils;
import org.argeo.eclipse.ui.ColumnDefinition;
import org.argeo.eclipse.ui.EclipseUiUtils;
import org.argeo.eclipse.ui.parts.LdifUsersTable;
*/
package org.argeo.cms.e4.users;
-import static org.argeo.cms.util.UserAdminUtils.getProperty;
+import static org.argeo.cms.auth.UserAdminUtils.getProperty;
import static org.argeo.naming.LdapAttrs.cn;
import static org.argeo.naming.LdapAttrs.givenName;
import static org.argeo.naming.LdapAttrs.mail;
import javax.inject.Inject;
import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.auth.UserAdminUtils;
import org.argeo.cms.e4.users.providers.CommonNameLP;
import org.argeo.cms.e4.users.providers.DomainNameLP;
import org.argeo.cms.e4.users.providers.RoleIconLP;
//import org.argeo.cms.ui.eclipse.forms.FormToolkit;
import org.argeo.cms.ui.eclipse.forms.IManagedForm;
import org.argeo.cms.util.CmsUtils;
-import org.argeo.cms.util.UserAdminUtils;
import org.argeo.eclipse.ui.ColumnDefinition;
import org.argeo.eclipse.ui.EclipseUiUtils;
import org.argeo.eclipse.ui.parts.LdifUsersTable;
import javax.inject.Inject;
import javax.inject.Named;
+import org.argeo.cms.auth.UserAdminUtils;
import org.argeo.cms.e4.users.GroupsView;
import org.argeo.cms.e4.users.UserAdminWrapper;
-import org.argeo.cms.util.UserAdminUtils;
import org.eclipse.e4.core.di.annotations.CanExecute;
import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import javax.inject.Inject;
import javax.inject.Named;
+import org.argeo.cms.auth.UserAdminUtils;
import org.argeo.cms.e4.users.UserAdminWrapper;
import org.argeo.cms.e4.users.UsersView;
-import org.argeo.cms.util.UserAdminUtils;
import org.eclipse.e4.core.di.annotations.CanExecute;
import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import javax.naming.ldap.Rdn;
import org.argeo.cms.CmsException;
+import org.argeo.cms.auth.UserAdminUtils;
import org.argeo.cms.e4.users.UiAdminUtils;
import org.argeo.cms.e4.users.UserAdminWrapper;
-import org.argeo.cms.util.UserAdminUtils;
import org.argeo.eclipse.ui.EclipseUiUtils;
import org.argeo.eclipse.ui.dialogs.ErrorFeedback;
import org.argeo.naming.LdapAttrs;
package org.argeo.cms.e4.users.providers;
-import org.argeo.cms.util.UserAdminUtils;
+import org.argeo.cms.auth.UserAdminUtils;
import org.argeo.naming.LdapAttrs;
import org.osgi.service.useradmin.User;
package org.argeo.cms.e4.users.providers;
-import org.argeo.cms.util.UserAdminUtils;
+import org.argeo.cms.auth.UserAdminUtils;
import org.osgi.service.useradmin.User;
/** The human friendly domain name for the corresponding user. */
package org.argeo.cms.e4.users.providers;
-import org.argeo.cms.util.UserAdminUtils;
+import org.argeo.cms.auth.UserAdminUtils;
import org.argeo.naming.LdapAttrs;
import org.osgi.service.useradmin.User;
package org.argeo.cms.e4.users.providers;
+import org.argeo.cms.auth.UserAdminUtils;
import org.argeo.cms.e4.users.SecurityAdminImages;
-import org.argeo.cms.util.UserAdminUtils;
import org.argeo.naming.LdapAttrs;
import org.argeo.node.NodeConstants;
import org.argeo.node.NodeInstance;
import javax.naming.ldap.LdapName;
import org.argeo.cms.CmsException;
-import org.argeo.cms.util.UserAdminUtils;
+import org.argeo.cms.auth.UserAdminUtils;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.swt.SWT;
import static org.argeo.eclipse.ui.EclipseUiUtils.notEmpty;
-import org.argeo.cms.util.UserAdminUtils;
+import org.argeo.cms.auth.UserAdminUtils;
import org.argeo.naming.LdapAttrs;
import org.argeo.node.NodeConstants;
import org.eclipse.jface.viewers.Viewer;
package org.argeo.cms.ui.useradmin;
-import org.argeo.cms.util.UserAdminUtils;
+import org.argeo.cms.auth.UserAdminUtils;
import org.argeo.node.NodeConstants;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.ColumnLabelProvider;
+++ /dev/null
-package org.argeo.cms.util;
-
-import java.util.List;
-
-import javax.naming.InvalidNameException;
-import javax.naming.ldap.LdapName;
-import javax.naming.ldap.Rdn;
-
-import org.argeo.cms.CmsException;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.naming.LdapAttrs;
-import org.argeo.node.NodeConstants;
-import org.osgi.service.useradmin.Role;
-import org.osgi.service.useradmin.User;
-import org.osgi.service.useradmin.UserAdmin;
-
-/** Centralise common patterns to manage users with a {@link UserAdmin} */
-public class UserAdminUtils {
-
- // CURRENTUSER HELPERS
- /** Checks if current user is the same as the passed one */
- public static boolean isCurrentUser(User user) {
- String userUsername = getProperty(user, LdapAttrs.DN);
- LdapName userLdapName = getLdapName(userUsername);
- LdapName selfUserName = getCurrentUserLdapName();
- return userLdapName.equals(selfUserName);
- }
-
- /** Retrieves the current logged-in {@link User} */
- public static User getCurrentUser(UserAdmin userAdmin) {
- return (User) userAdmin.getRole(CurrentUser.getUsername());
- }
-
- /** Retrieves the current logged-in user {@link LdapName} */
- public final static LdapName getCurrentUserLdapName() {
- String name = CurrentUser.getUsername();
- return getLdapName(name);
- }
-
- /** Retrieves the current logged-in user mail */
- public static String getCurrentUserMail(UserAdmin userAdmin) {
- String username = CurrentUser.getUsername();
- return getUserMail(userAdmin, username);
- }
-
- /** Retrieves the current logged-in user common name */
- public final static String getCommonName(User user) {
- return getProperty(user, LdapAttrs.cn.name());
- }
-
- // OTHER USERS HELPERS
- /**
- * Retrieves the local id of a user or group, that is respectively the uid or cn
- * of the passed dn with no {@link UserAdmin}
- */
- public static String getUserLocalId(String dn) {
- LdapName ldapName = getLdapName(dn);
- Rdn last = ldapName.getRdn(ldapName.size() - 1);
- if (last.getType().toLowerCase().equals(LdapAttrs.uid.name())
- || last.getType().toLowerCase().equals(LdapAttrs.cn.name()))
- return (String) last.getValue();
- else
- throw new CmsException("Cannot retrieve user local id, non valid dn: " + dn);
- }
-
- /**
- * Returns the local username if no user with this dn is found or if the found
- * user has no defined display name
- */
- public static String getUserDisplayName(UserAdmin userAdmin, String dn) {
- Role user = userAdmin.getRole(dn);
- String dName;
- if (user == null)
- dName = getUserLocalId(dn);
- else {
- dName = getProperty(user, LdapAttrs.displayName.name());
- if (EclipseUiUtils.isEmpty(dName))
- dName = getProperty(user, LdapAttrs.cn.name());
- if (EclipseUiUtils.isEmpty(dName))
- dName = getUserLocalId(dn);
- }
- return dName;
- }
-
- /**
- * Returns null if no user with this dn is found or if the found user has no
- * defined mail
- */
- public static String getUserMail(UserAdmin userAdmin, String dn) {
- Role user = userAdmin.getRole(dn);
- if (user == null)
- return null;
- else
- return getProperty(user, LdapAttrs.mail.name());
- }
-
- // LDAP NAMES HELPERS
- /**
- * Easily retrieves one of the {@link Role}'s property or an empty String if the
- * requested property is not defined
- */
- public final static String getProperty(Role role, String key) {
- Object obj = role.getProperties().get(key);
- if (obj != null)
- return (String) obj;
- else
- return "";
- }
-
- public final static String getProperty(Role role, Enum<?> key) {
- Object obj = role.getProperties().get(key.name());
- if (obj != null)
- return (String) obj;
- else
- return "";
- }
-
- @SuppressWarnings("unchecked")
- public final static void setProperty(Role role, String key, String value) {
- role.getProperties().put(key, value);
- }
-
- public final static void setProperty(Role role, Enum<?> key, String value) {
- setProperty(role, key.name(), value);
- }
-
- /**
- * Simply retrieves a LDAP name from a {@link LdapAttrs.DN} with no exception
- */
- private static LdapName getLdapName(String dn) {
- try {
- return new LdapName(dn);
- } catch (InvalidNameException e) {
- throw new CmsException("Cannot parse LDAP name " + dn, e);
- }
- }
-
- /** Simply retrieves a display name of the relevant domain */
- public final static String getDomainName(User user) {
- String dn = user.getName();
- if (dn.endsWith(NodeConstants.ROLES_BASEDN))
- return "System roles";
- if (dn.endsWith(NodeConstants.TOKENS_BASEDN))
- return "Tokens";
- try {
- // FIXME deal with non-DC
- LdapName name = new LdapName(dn);
- List<Rdn> rdns = name.getRdns();
- String dname = null;
- int i = 0;
- loop: while (i < rdns.size()) {
- Rdn currrRdn = rdns.get(i);
- if (!LdapAttrs.dc.name().equals(currrRdn.getType()))
- break loop;
- else {
- String currVal = (String) currrRdn.getValue();
- dname = dname == null ? currVal : currVal + "." + dname;
- }
- i++;
- }
- return dname;
- } catch (InvalidNameException e) {
- throw new CmsException("Unable to get domain name for " + dn, e);
- }
- }
-
- // VARIOUS HELPERS
- public final static String buildDefaultCn(String firstName, String lastName) {
- return (firstName.trim() + " " + lastName.trim() + " ").trim();
- }
-}
<arguments>
</arguments>
</buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ds.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="User Admin Service">
+ <implementation class="org.argeo.cms.internal.auth.CmsUserManagerImpl"/>
+ <service>
+ <provide interface="org.argeo.cms.CmsUserManager"/>
+ </service>
+ <reference bind="setUserAdmin" cardinality="1..1" interface="org.osgi.service.useradmin.UserAdmin" name="UserAdmin" policy="static"/>
+ <reference bind="setUserTransaction" cardinality="1..1" interface="javax.transaction.UserTransaction" name="UserTransaction" policy="static"/>
+</scr:component>
\ No newline at end of file
org.osgi.*;version=0.0.0,\
*
+Service-Component: OSGI-INF/cmsUserManager.xml
+
Provide-Capability: cms.datamodel;name=argeo;cnd=/org/argeo/cms/argeo.cnd;abstract=true
.,\
OSGI-INF/,\
bin/,\
- OSGI-INF/org.argeo.cms.internal.kernel.KernelInitOld.xml
-source.. = src/
+ OSGI-INF/cmsUserManager.xml
+source.. = src/,\
+ ext/test/
additional.bundles = org.apache.jackrabbit.data,\
org.argeo.jcr,\
org.junit
--- /dev/null
+package org.argeo.cms;
+
+import java.util.List;
+import java.util.Set;
+
+import javax.jcr.Node;
+import javax.security.auth.Subject;
+import javax.transaction.UserTransaction;
+
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
+
+/**
+ * Provide method interfaces to manage user concepts without accessing directly
+ * the userAdmin.
+ */
+public interface CmsUserManager {
+
+ // CurrentUser
+ /** Returns the e-mail of the current logged in user */
+ public String getMyMail();
+
+ // Other users
+ /** Returns a {@link User} given a username */
+ public User getUser(String username);
+
+ /** Can be a group or a user */
+ public String getUserDisplayName(String dn);
+
+ /** Can be a group or a user */
+ public String getUserMail(String dn);
+
+ /** Lists all roles of the given user */
+ public String[] getUserRoles(String dn);
+
+ /** Checks if the passed user belongs to the passed role */
+ public boolean isUserInRole(String userDn, String roleDn);
+
+ // Search
+ /** Returns a filtered list of roles */
+ public Role[] getRoles(String filter) throws InvalidSyntaxException;
+
+ /** Recursively lists users in a given group. */
+ public Set<User> listUsersInGroup(String groupDn, String filter);
+
+ /** Search among groups including system roles and users if needed */
+ public List<User> listGroups(String filter, boolean includeUsers, boolean includeSystemRoles);
+
+ /* MISCELLANEOUS */
+ /** Returns the dn of a role given its local ID */
+ public String buildDefaultDN(String localId, int type);
+
+ /** Exposes the main default domain name for this instance */
+ public String getDefaultDomainName();
+
+ /**
+ * Search for a {@link User} (might also be a group) whose uid or cn is equals
+ * to localId within the various user repositories defined in the current
+ * context.
+ */
+ public User getUserFromLocalId(String localId);
+
+ void changeOwnPassword(char[] oldPassword, char[] newPassword);
+
+ void resetPassword(String username, char[] newPassword);
+
+ @Deprecated
+ String addSharedSecret(String username, int hours);
+
+// String addSharedSecret(String username, String authInfo, String authToken);
+
+ void addAuthToken(String userDn, String token, Integer hours, String... roles);
+
+ void expireAuthToken(String token);
+
+ void expireAuthTokens(Subject subject);
+
+ User createUserFromPerson(Node person);
+
+ @Deprecated
+ public UserAdmin getUserAdmin();
+
+ @Deprecated
+ public UserTransaction getUserTransaction();
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.auth;
+
+import java.util.List;
+
+import javax.naming.InvalidNameException;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
+
+import org.argeo.cms.CmsException;
+import org.argeo.naming.LdapAttrs;
+import org.argeo.node.NodeConstants;
+import org.osgi.service.useradmin.Role;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
+
+/** Centralise common patterns to manage users with a {@link UserAdmin} */
+public class UserAdminUtils {
+
+ // CURRENTUSER HELPERS
+ /** Checks if current user is the same as the passed one */
+ public static boolean isCurrentUser(User user) {
+ String userUsername = getProperty(user, LdapAttrs.DN);
+ LdapName userLdapName = getLdapName(userUsername);
+ LdapName selfUserName = getCurrentUserLdapName();
+ return userLdapName.equals(selfUserName);
+ }
+
+ /** Retrieves the current logged-in {@link User} */
+ public static User getCurrentUser(UserAdmin userAdmin) {
+ return (User) userAdmin.getRole(CurrentUser.getUsername());
+ }
+
+ /** Retrieves the current logged-in user {@link LdapName} */
+ public final static LdapName getCurrentUserLdapName() {
+ String name = CurrentUser.getUsername();
+ return getLdapName(name);
+ }
+
+ /** Retrieves the current logged-in user mail */
+ public static String getCurrentUserMail(UserAdmin userAdmin) {
+ String username = CurrentUser.getUsername();
+ return getUserMail(userAdmin, username);
+ }
+
+ /** Retrieves the current logged-in user common name */
+ public final static String getCommonName(User user) {
+ return getProperty(user, LdapAttrs.cn.name());
+ }
+
+ // OTHER USERS HELPERS
+ /**
+ * Retrieves the local id of a user or group, that is respectively the uid or cn
+ * of the passed dn with no {@link UserAdmin}
+ */
+ public static String getUserLocalId(String dn) {
+ LdapName ldapName = getLdapName(dn);
+ Rdn last = ldapName.getRdn(ldapName.size() - 1);
+ if (last.getType().toLowerCase().equals(LdapAttrs.uid.name())
+ || last.getType().toLowerCase().equals(LdapAttrs.cn.name()))
+ return (String) last.getValue();
+ else
+ throw new CmsException("Cannot retrieve user local id, non valid dn: " + dn);
+ }
+
+ /**
+ * Returns the local username if no user with this dn is found or if the found
+ * user has no defined display name
+ */
+ public static String getUserDisplayName(UserAdmin userAdmin, String dn) {
+ Role user = userAdmin.getRole(dn);
+ String dName;
+ if (user == null)
+ dName = getUserLocalId(dn);
+ else {
+ dName = getProperty(user, LdapAttrs.displayName.name());
+ if (isEmpty(dName))
+ dName = getProperty(user, LdapAttrs.cn.name());
+ if (isEmpty(dName))
+ dName = getUserLocalId(dn);
+ }
+ return dName;
+ }
+
+ /**
+ * Returns null if no user with this dn is found or if the found user has no
+ * defined mail
+ */
+ public static String getUserMail(UserAdmin userAdmin, String dn) {
+ Role user = userAdmin.getRole(dn);
+ if (user == null)
+ return null;
+ else
+ return getProperty(user, LdapAttrs.mail.name());
+ }
+
+ // LDAP NAMES HELPERS
+ /**
+ * Easily retrieves one of the {@link Role}'s property or an empty String if the
+ * requested property is not defined
+ */
+ public final static String getProperty(Role role, String key) {
+ Object obj = role.getProperties().get(key);
+ if (obj != null)
+ return (String) obj;
+ else
+ return "";
+ }
+
+ public final static String getProperty(Role role, Enum<?> key) {
+ Object obj = role.getProperties().get(key.name());
+ if (obj != null)
+ return (String) obj;
+ else
+ return "";
+ }
+
+ public final static void setProperty(Role role, String key, String value) {
+ role.getProperties().put(key, value);
+ }
+
+ public final static void setProperty(Role role, Enum<?> key, String value) {
+ setProperty(role, key.name(), value);
+ }
+
+ /**
+ * Simply retrieves a LDAP name from a {@link LdapAttrs.DN} with no exception
+ */
+ private static LdapName getLdapName(String dn) {
+ try {
+ return new LdapName(dn);
+ } catch (InvalidNameException e) {
+ throw new CmsException("Cannot parse LDAP name " + dn, e);
+ }
+ }
+
+ /** Simply retrieves a display name of the relevant domain */
+ public final static String getDomainName(User user) {
+ String dn = user.getName();
+ if (dn.endsWith(NodeConstants.ROLES_BASEDN))
+ return "System roles";
+ if (dn.endsWith(NodeConstants.TOKENS_BASEDN))
+ return "Tokens";
+ try {
+ // FIXME deal with non-DC
+ LdapName name = new LdapName(dn);
+ List<Rdn> rdns = name.getRdns();
+ String dname = null;
+ int i = 0;
+ loop: while (i < rdns.size()) {
+ Rdn currrRdn = rdns.get(i);
+ if (!LdapAttrs.dc.name().equals(currrRdn.getType()))
+ break loop;
+ else {
+ String currVal = (String) currrRdn.getValue();
+ dname = dname == null ? currVal : currVal + "." + dname;
+ }
+ i++;
+ }
+ return dname;
+ } catch (InvalidNameException e) {
+ throw new CmsException("Unable to get domain name for " + dn, e);
+ }
+ }
+
+ // VARIOUS HELPERS
+ public final static String buildDefaultCn(String firstName, String lastName) {
+ return (firstName.trim() + " " + lastName.trim() + " ").trim();
+ }
+
+ /** Simply checks if a string is null or empty */
+ private static boolean isEmpty(String stringToTest) {
+ return stringToTest == null || "".equals(stringToTest.trim());
+ }
+
+}
--- /dev/null
+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 java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+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.cms.CmsUserManager;
+import org.argeo.cms.auth.CurrentUser;
+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.TokenUtils;
+import org.argeo.osgi.useradmin.UserAdminConf;
+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;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
+
+/**
+ * Canonical implementation of the people {@link CmsUserManager}. Wraps
+ * interaction with users and groups.
+ *
+ * In a *READ-ONLY* mode. We want to be able to:
+ * <ul>
+ * <li>Retrieve my user and corresponding information (main info,
+ * groups...)</li>
+ * <li>List all local groups (not the system roles)</li>
+ * <li>If sufficient rights: retrieve a given user and its information</li>
+ * </ul>
+ */
+public class CmsUserManagerImpl implements CmsUserManager {
+ private final static Log log = LogFactory.getLog(CmsUserManagerImpl.class);
+
+ private UserAdmin userAdmin;
+ @Deprecated
+ private ServiceReference<UserAdmin> userAdminServiceReference;
+ private Map<String, String> serviceProperties;
+ private UserTransaction userTransaction;
+
+ @Override
+ public String getMyMail() {
+ return getUserMail(CurrentUser.getUsername());
+ }
+
+ @Override
+ public Role[] getRoles(String filter) throws InvalidSyntaxException {
+ return userAdmin.getRoles(filter);
+ }
+
+ // 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);
+ }
+
+ /** Can be a group or a user */
+ public String getUserDisplayName(String dn) {
+ // FIXME: during initialisation phase, the system logs "admin" as user
+ // name rather than the corresponding dn
+ if ("admin".equals(dn))
+ return "System Administrator";
+ else
+ return UserAdminUtils.getUserDisplayName(getUserAdmin(), dn);
+ }
+
+ @Override
+ public String getUserMail(String dn) {
+ return UserAdminUtils.getUserMail(getUserAdmin(), dn);
+ }
+
+ /** Lists all roles of the given user */
+ @Override
+ public String[] getUserRoles(String dn) {
+ Authorization currAuth = getUserAdmin().getAuthorization(getUser(dn));
+ return currAuth.getRoles();
+ }
+
+ @Override
+ public boolean isUserInRole(String userDn, String roleDn) {
+ String[] roles = getUserRoles(userDn);
+ for (String role : roles) {
+ if (role.equalsIgnoreCase(roleDn))
+ return true;
+ }
+ 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)
+ throw new IllegalArgumentException("Group " + groupDn + " not found");
+ Set<User> users = new HashSet<User>();
+ addUsers(users, group, filter);
+ return users;
+ }
+
+ /** Recursively add users to list */
+ private void addUsers(Set<User> users, Group group, String filter) {
+ Role[] roles = group.getMembers();
+ for (Role role : roles) {
+ if (role.getType() == Role.GROUP) {
+ addUsers(users, (Group) role, filter);
+ } else if (role.getType() == Role.USER) {
+ if (match(role, filter))
+ users.add((User) role);
+ } else {
+ // ignore
+ }
+ }
+ }
+
+ public List<User> listGroups(String filter, boolean includeUsers, boolean includeSystemRoles) {
+ Role[] roles = null;
+ try {
+ roles = getUserAdmin().getRoles(filter);
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalArgumentException("Unable to get roles with filter: " + filter, e);
+ }
+
+ 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))) {
+ if (match(role, filter))
+ users.add((User) role);
+ }
+ }
+ return users;
+ }
+
+ private boolean match(Role role, String filter) {
+ boolean doFilter = filter != null && !"".equals(filter);
+ if (doFilter) {
+ for (String prop : knownProps) {
+ Object currProp = null;
+ try {
+ currProp = role.getProperties().get(prop);
+ } catch (Exception e) {
+ throw e;
+ }
+ if (currProp != null) {
+ String currPropStr = ((String) currProp).toLowerCase();
+ if (currPropStr.contains(filter.toLowerCase())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ } else
+ return true;
+ }
+
+ @Override
+ public User getUserFromLocalId(String localId) {
+ User user = getUserAdmin().getUser(LdapAttrs.uid.name(), localId);
+ if (user == null)
+ user = getUserAdmin().getUser(LdapAttrs.cn.name(), localId);
+ return user;
+ }
+
+ @Override
+ public String buildDefaultDN(String localId, int type) {
+ return buildDistinguishedName(localId, getDefaultDomainName(), type);
+ }
+
+ @Override
+ public String getDefaultDomainName() {
+ Map<String, String> dns = getKnownBaseDns(true);
+ if (dns.size() == 1)
+ return dns.keySet().iterator().next();
+ else
+ throw new IllegalStateException("Current context contains " + dns.size() + " base dns: "
+ + dns.keySet().toString() + ". Unable to chose a default one.");
+ }
+
+ 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);
+
+ 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 String buildDistinguishedName(String localId, String baseDn, int type) {
+ Map<String, String> dns = getKnownBaseDns(true);
+ Dictionary<String, ?> props = UserAdminConf.uriAsProperties(dns.get(baseDn));
+ String dn = null;
+ if (Role.GROUP == type)
+ dn = LdapAttrs.cn.name() + "=" + localId + "," + UserAdminConf.groupBase.getValue(props) + "," + baseDn;
+ else if (Role.USER == type)
+ dn = LdapAttrs.uid.name() + "=" + localId + "," + UserAdminConf.userBase.getValue(props) + "," + baseDn;
+ else
+ throw new IllegalStateException("Unknown role type. " + "Cannot deduce dn for " + localId);
+ return dn;
+ }
+
+ @Override
+ public void changeOwnPassword(char[] oldPassword, char[] newPassword) {
+ String name = CurrentUser.getUsername();
+ LdapName dn;
+ try {
+ dn = new LdapName(name);
+ } catch (InvalidNameException e) {
+ throw new IllegalArgumentException("Invalid user dn " + name, e);
+ }
+ User user = (User) userAdmin.getRole(dn.toString());
+ if (!user.hasCredential(null, oldPassword))
+ throw new IllegalArgumentException("Invalid password");
+ if (Arrays.equals(newPassword, new char[0]))
+ throw new IllegalArgumentException("New password empty");
+ try {
+ userTransaction.begin();
+ user.getCredentials().put(null, newPassword);
+ 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 change password", e);
+ }
+ }
+
+ public void resetPassword(String username, char[] newPassword) {
+ LdapName dn;
+ try {
+ dn = new LdapName(username);
+ } catch (InvalidNameException e) {
+ throw new IllegalArgumentException("Invalid user dn " + username, e);
+ }
+ User user = (User) userAdmin.getRole(dn.toString());
+ if (Arrays.equals(newPassword, new char[0]))
+ throw new IllegalArgumentException("New password empty");
+ try {
+ userTransaction.begin();
+ user.getCredentials().put(null, newPassword);
+ 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 change password", e);
+ }
+ }
+
+ public String addSharedSecret(String email, int hours) {
+ User user = (User) userAdmin.getUser(LdapAttrs.mail.name(), email);
+ try {
+ userTransaction.begin();
+ String uuid = UUID.randomUUID().toString();
+ SharedSecret sharedSecret = new SharedSecret(hours, uuid);
+ user.getCredentials().put(SharedSecret.X_SHARED_SECRET, sharedSecret.toAuthPassword());
+ String tokenStr = sharedSecret.getAuthInfo() + '$' + sharedSecret.getAuthValue();
+ userTransaction.commit();
+ return tokenStr;
+ } 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 change password", e);
+ }
+ }
+
+ @Deprecated
+ public String addSharedSecret(String username, String authInfo, String authToken) {
+ try {
+ userTransaction.begin();
+ User user = (User) userAdmin.getRole(username);
+ SharedSecret sharedSecret = new SharedSecret(authInfo, authToken);
+ user.getCredentials().put(SharedSecret.X_SHARED_SECRET, sharedSecret.toAuthPassword());
+ String tokenStr = sharedSecret.getAuthInfo() + '$' + sharedSecret.getAuthValue();
+ userTransaction.commit();
+ return tokenStr;
+ } catch (Exception e1) {
+ try {
+ if (userTransaction.getStatus() != Status.STATUS_NO_TRANSACTION)
+ userTransaction.rollback();
+ } catch (Exception e2) {
+ if (log.isTraceEnabled())
+ log.trace("Cannot rollback transaction", e2);
+ }
+ throw new RuntimeException("Cannot add shared secret", e1);
+ }
+ }
+
+ @Override
+ public void expireAuthToken(String token) {
+ try {
+ userTransaction.begin();
+ String dn = cn + "=" + token + "," + NodeConstants.TOKENS_BASEDN;
+ Group tokenGroup = (Group) userAdmin.getRole(dn);
+ String ldapDate = NamingUtils.instantToLdapDate(ZonedDateTime.now(ZoneOffset.UTC));
+ tokenGroup.getProperties().put(description.name(), ldapDate);
+ userTransaction.commit();
+ if (log.isDebugEnabled())
+ log.debug("Token " + token + " expired.");
+ } catch (Exception e1) {
+ try {
+ if (userTransaction.getStatus() != Status.STATUS_NO_TRANSACTION)
+ userTransaction.rollback();
+ } catch (Exception e2) {
+ if (log.isTraceEnabled())
+ log.trace("Cannot rollback transaction", e2);
+ }
+ throw new RuntimeException("Cannot expire token", e1);
+ }
+ }
+
+ @Override
+ public void expireAuthTokens(Subject subject) {
+ Set<String> tokens = TokenUtils.tokensUsed(subject, NodeConstants.TOKENS_BASEDN);
+ for (String token : tokens)
+ expireAuthToken(token);
+ }
+
+ @Override
+ public void addAuthToken(String userDn, String token, Integer hours, String... roles) {
+ try {
+ userTransaction.begin();
+ User user = (User) userAdmin.getRole(userDn);
+ String tokenDn = cn + "=" + token + "," + NodeConstants.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);
+ }
+ }
+ }
+ tokenGroup.getProperties().put(owner.name(), user.getName());
+ if (hours != null) {
+ String ldapDate = NamingUtils.instantToLdapDate(ZonedDateTime.now().plusHours(hours));
+ tokenGroup.getProperties().put(description.name(), ldapDate);
+ }
+ userTransaction.commit();
+ } catch (Exception e1) {
+ try {
+ if (userTransaction.getStatus() != Status.STATUS_NO_TRANSACTION)
+ userTransaction.rollback();
+ } catch (Exception e2) {
+ if (log.isTraceEnabled())
+ log.trace("Cannot rollback transaction", e2);
+ }
+ throw new RuntimeException("Cannot add token", e1);
+ }
+ }
+
+ 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;
+ }
+
+ /* DEPENDENCY INJECTION */
+ public void setUserAdmin(UserAdmin userAdmin, Map<String, String> serviceProperties) {
+ this.userAdmin = userAdmin;
+ this.serviceProperties = serviceProperties;
+ }
+
+ public void setUserTransaction(UserTransaction userTransaction) {
+ this.userTransaction = userTransaction;
+ }
+}