import javax.security.auth.Subject;
import org.argeo.osgi.useradmin.UserDirectory;
+import org.argeo.util.directory.HierarchyUnit;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.service.useradmin.Role;
import org.osgi.service.useradmin.User;
* the userAdmin.
*/
public interface CmsUserManager {
- public Map<String, String> getKnownBaseDns(boolean onlyWritable);
- public Set<UserDirectory> getUserDirectories();
-
+ Map<String, String> getKnownBaseDns(boolean onlyWritable);
+
+ Set<UserDirectory> getUserDirectories();
+
// CurrentUser
/** Returns the e-mail of the current logged in user */
- public String getMyMail();
+ String getMyMail();
// Other users
/** Returns a {@link User} given a username */
- public User getUser(String username);
+ User getUser(String username);
/** Can be a group or a user */
- public String getUserDisplayName(String dn);
+ String getUserDisplayName(String dn);
/** Can be a group or a user */
- public String getUserMail(String dn);
+ String getUserMail(String dn);
/** Lists all roles of the given user */
- public String[] getUserRoles(String dn);
+ String[] getUserRoles(String dn);
/** Checks if the passed user belongs to the passed role */
- public boolean isUserInRole(String userDn, String roleDn);
+ boolean isUserInRole(String userDn, String roleDn);
// Search
/** Returns a filtered list of roles */
- public Role[] getRoles(String filter) throws InvalidSyntaxException;
+ Role[] getRoles(String filter) throws InvalidSyntaxException;
/** Recursively lists users in a given group. */
- public Set<User> listUsersInGroup(String groupDn, String filter);
+ 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);
+ List<User> listGroups(String filter, boolean includeUsers, boolean includeSystemRoles);
+
+ /*
+ * EDITION
+ */
+ /** Creates a new user.*/
+ User createUser(String username, Map<String, Object> properties, Map<String, Object> credentials);
/* MISCELLANEOUS */
/** Returns the dn of a role given its local ID */
- public String buildDefaultDN(String localId, int type);
+ String buildDefaultDN(String localId, int type);
/** Exposes the main default domain name for this instance */
- public String getDefaultDomainName();
+ 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);
+ User getUserFromLocalId(String localId);
void changeOwnPassword(char[] oldPassword, char[] newPassword);
void expireAuthToken(String token);
void expireAuthTokens(Subject subject);
-
- UserDirectory getDirectory(Role role);
-// User createUserFromPerson(Node person);
+ UserDirectory getDirectory(Role role);
-// @Deprecated
-// public UserAdmin getUserAdmin();
-//
-// @Deprecated
-// public UserTransaction getUserTransaction();
+ /** Create a new hierarchy unit. Does nothing if it already exists. */
+ HierarchyUnit createHierarchyUnit(UserDirectory directory, String path);
}
\ No newline at end of file
import org.argeo.osgi.useradmin.TokenUtils;
import org.argeo.osgi.useradmin.UserDirectory;
import org.argeo.util.directory.DirectoryConf;
+import org.argeo.util.directory.HierarchyUnit;
import org.argeo.util.directory.ldap.SharedSecret;
import org.argeo.util.naming.LdapAttrs;
import org.argeo.util.naming.NamingUtils;
// 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<>());
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)
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 String getDefaultDomainName() {
Map<String, String> dns = getKnownBaseDns(true);
+ 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 = 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 Map<String, String> getKnownBaseDns(boolean onlyWritable) {
Map<String, String> dns = new HashMap<String, String>();
for (UserDirectory userDirectory : userDirectories) {
return possible.lastEntry().getValue();
}
+ public HierarchyUnit createHierarchyUnit(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);
+ }
+ }
+
// public User createUserFromPerson(Node person) {
// String email = JcrUtils.get(person, LdapAttrs.mail.property());
// String dn = buildDefaultDN(email, Role.USER);
return res;
}
+ /** Converts a {@link Dictionary} to a {@link Map}. */
+ public static Map<String, Object> dictToMap(Dictionary<String, ?> properties) {
+ if (properties == null) {
+ return null;
+ }
+ Map<String, Object> res = new HashMap<>(properties.size());
+ Enumeration<String> keys = properties.keys();
+ while (keys.hasMoreElements()) {
+ String key = keys.nextElement();
+ res.put(key, properties.get(key));
+ }
+ return res;
+ }
+
/**
* Get a string property from this map, expecting to find it, or
* <code>null</code> if not found.
import org.argeo.util.transaction.WorkControl;
+/** An information directory (typicylly LDAP). */
public interface Directory extends HierarchyUnit {
/**
* The base of the hierarchy defined by this directory. This could typically be
String getName();
+ /** Whether this directory is read only. */
boolean isReadOnly();
+ /** Whether this directory is disabled. */
boolean isDisabled();
+ /** The realm (typically Kerberos) of this directory. */
Optional<String> getRealm();
+ /** Sets the transaction control used by this directory when editing. */
void setTransactionControl(WorkControl transactionControl);
/*
* METADATA
*/
+ /** Metadata of this directory. */
public Dictionary<String, Object> getProperties();
/*
* HIERARCHY
*/
-
+ /** The first level of hierarchy units. */
Iterable<HierarchyUnit> getDirectHierarchyUnits(boolean functionalOnly);
+ /** The hierarchy unit at this path. */
HierarchyUnit getHierarchyUnit(String path);
+ /** Create a new hierarchy unit. */
+ HierarchyUnit createHierarchyUnit(String path);
}
import org.argeo.util.transaction.WorkingCopyXaResource;
import org.argeo.util.transaction.XAResourceProvider;
+/** A {@link Directory} based either on LDAP or LDIF. */
public abstract class AbstractLdapDirectory implements Directory, XAResourceProvider {
protected static final String SHARED_STATE_USERNAME = "javax.security.auth.login.name";
protected static final String SHARED_STATE_PASSWORD = "javax.security.auth.login.password";
}
/*
- * ABSTRACT METHODS
- */
-
-// public abstract HierarchyUnit doGetHierarchyUnit(LdapName dn);
-//
-// public abstract Iterable<HierarchyUnit> doGetDirectHierarchyUnits(LdapName searchBase, boolean functionalOnly);
-//
-// protected abstract Boolean daoHasEntry(LdapName dn);
-//
-// protected abstract LdapEntry daoGetEntry(LdapName key) throws NameNotFoundException;
-//
-// protected abstract List<LdapEntry> doGetEntries(LdapName searchBase, Filter f, boolean deep);
-//
-// /** Returns the groups this user is a direct member of. */
-// protected abstract List<LdapName> getDirectGroups(LdapName dn);
- /*
- * INITIALIZATION
+ * INITIALISATION
*/
public void init() {
return this;
}
+ @Override
+ public HierarchyUnit createHierarchyUnit(String path) {
+ checkEdit();
+ LdapEntryWorkingCopy wc = getWorkingCopy();
+ LdapName dn = pathToName(path);
+ if ((getDirectoryDao().entryExists(dn) && !wc.getDeletedData().containsKey(dn))
+ || wc.getNewData().containsKey(dn))
+ throw new IllegalArgumentException("Already a hierarchy unit " + path);
+ BasicAttributes attrs = new BasicAttributes(true);
+ attrs.put(LdapAttrs.objectClass.name(), LdapObjs.organizationalUnit.name());
+ Rdn nameRdn = dn.getRdn(dn.size() - 1);
+ // TODO deal with multiple attr RDN
+ attrs.put(nameRdn.getType(), nameRdn.getValue());
+ wc.getModifiedData().put(dn, attrs);
+ LdapHierarchyUnit newHierarchyUnit = new LdapHierarchyUnit(this, dn, attrs);
+ wc.getNewData().put(dn, newHierarchyUnit);
+ return newHierarchyUnit;
+ }
+
/*
* PATHS
*/
public Dictionary<String, Object> getCredentials() {
if (credentials == null)
- credentials = new AttributeDictionary(false);
+ credentials = new AttributeDictionary(true);
return credentials;
}
@Override
public Object put(String key, Object value) {
- if (key == null) {
- // TODO persist to other sources (like PKCS12)
- char[] password = DirectoryDigestUtils.bytesToChars(value);
- byte[] hashedPassword = sha1hash(password);
- return put(LdapAttrs.userPassword.name(), hashedPassword);
- }
- if (key.startsWith("X-")) {
- return put(LdapAttrs.authPassword.name(), value);
- }
+ try {
+ if (key == null) {
+ // TODO persist to other sources (like PKCS12)
+ char[] password = DirectoryDigestUtils.bytesToChars(value);
+ byte[] hashedPassword = sha1hash(password);
+ return put(LdapAttrs.userPassword.name(), hashedPassword);
+ }
+ if (key.startsWith("X-")) {
+ return put(LdapAttrs.authPassword.name(), value);
+ }
+ if (key.equals(LdapAttrs.objectClasses.name())) {
+ Attribute attribute = new BasicAttribute(LdapAttrs.objectClass.name());
+ String[] objectClasses = value.toString().split("\n");
+ for (String objectClass : objectClasses) {
+ if (objectClass.trim().equals(""))
+ continue;
+ attribute.add(objectClass);
+ }
+ Attribute previousAttribute = getModifiedAttributes().put(attribute);
+ if (previousAttribute != null)
+ return previousAttribute.get();
+ else
+ return null;
+ }
- getDirectory().checkEdit();
- if (!isEditing())
- startEditing();
+ getDirectory().checkEdit();
+ if (!isEditing())
+ startEditing();
- if (!(value instanceof String || value instanceof byte[]))
- throw new IllegalArgumentException("Value must be String or byte[]");
+ if (!(value instanceof String || value instanceof byte[]))
+ throw new IllegalArgumentException("Value must be String or byte[]");
- if (includeFilter && !attrFilter.contains(key))
- throw new IllegalArgumentException("Key " + key + " not included");
- else if (!includeFilter && attrFilter.contains(key))
- throw new IllegalArgumentException("Key " + key + " excluded");
+ if (includeFilter && !attrFilter.contains(key))
+ throw new IllegalArgumentException("Key " + key + " not included");
+ else if (!includeFilter && attrFilter.contains(key))
+ throw new IllegalArgumentException("Key " + key + " excluded");
- try {
Attribute attribute = getModifiedAttributes().get(key.toString());
// if (attribute == null) // block unit tests
attribute = new BasicAttribute(key.toString());
throw new IllegalArgumentException(dn + " does not start with base DN " + getDirectory().getBaseDn());
Attributes attrs = ldapConnection.getAttributes(dn);
return new LdapHierarchyUnit(getDirectory(), dn, attrs);
+ } catch (NameNotFoundException e) {
+ return null;
} catch (NamingException e) {
throw new IllegalStateException("Cannot get hierarchy unit " + dn, e);
}