X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;f=org.argeo.security.core%2Fsrc%2Forg%2Fargeo%2Fosgi%2Fuseradmin%2FAbstractUserDirectory.java;h=3f5bf850d55a890093804df97993f27f1eb809e4;hb=8260f4470f514ea347ca53f5b4dfc632c4a4de66;hp=0ed712c0b8b8c311a9e2f955fc9e9b989e564572;hpb=25e98954db6faeec4ba9950f651e81fbea595b0c;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java index 0ed712c0b..3f5bf850d 100644 --- a/org.argeo.security.core/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java +++ b/org.argeo.security.core/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java @@ -1,15 +1,10 @@ package org.argeo.osgi.useradmin; -import static org.argeo.osgi.useradmin.LdifName.gidNumber; -import static org.argeo.osgi.useradmin.LdifName.homeDirectory; import static org.argeo.osgi.useradmin.LdifName.inetOrgPerson; import static org.argeo.osgi.useradmin.LdifName.objectClass; import static org.argeo.osgi.useradmin.LdifName.organizationalPerson; import static org.argeo.osgi.useradmin.LdifName.person; -import static org.argeo.osgi.useradmin.LdifName.posixAccount; import static org.argeo.osgi.useradmin.LdifName.top; -import static org.argeo.osgi.useradmin.LdifName.uid; -import static org.argeo.osgi.useradmin.LdifName.uidNumber; import java.io.File; import java.net.URI; @@ -23,7 +18,6 @@ import java.util.Iterator; import java.util.List; import javax.naming.InvalidNameException; -import javax.naming.NamingException; import javax.naming.directory.Attributes; import javax.naming.directory.BasicAttribute; import javax.naming.directory.BasicAttributes; @@ -35,7 +29,6 @@ import javax.transaction.TransactionManager; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.argeo.ArgeoException; import org.osgi.framework.Filter; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; @@ -45,35 +38,28 @@ import org.osgi.service.useradmin.User; import org.osgi.service.useradmin.UserAdmin; /** Base class for a {@link UserDirectory}. */ -abstract class AbstractUserDirectory implements UserAdmin, UserDirectory { - private final static Log log = LogFactory - .getLog(AbstractUserDirectory.class); +public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory { + private final static Log log = LogFactory.getLog(AbstractUserDirectory.class); private final Hashtable properties; - private final String baseDn; - private final String userObjectClass; - private final String groupObjectClass; + private final LdapName baseDn; + private final String userObjectClass, userBase, groupObjectClass, groupBase; private final boolean readOnly; private final URI uri; private UserAdmin externalRoles; - private List indexedUserProperties = Arrays.asList(new String[] { - LdifName.uid.name(), LdifName.mail.name(), LdifName.cn.name() }); + private List indexedUserProperties = Arrays + .asList(new String[] { LdifName.uid.name(), LdifName.mail.name(), LdifName.cn.name() }); private String memberAttributeId = "member"; - private List credentialAttributeIds = Arrays - .asList(new String[] { LdifName.userPassword.name() }); + private List credentialAttributeIds = Arrays.asList(new String[] { LdifName.userPassword.name() }); + // JTA private TransactionManager transactionManager; - // private TransactionSynchronizationRegistry transactionRegistry; - // private Xid editingTransactionXid = null; private WcXaResource xaResource = new WcXaResource(this); - // POSIX - private String homeDirectoryBase = "/home"; - - AbstractUserDirectory(Dictionary props) { + public AbstractUserDirectory(Dictionary props) { properties = new Hashtable(); for (Enumeration keys = props.keys(); keys.hasMoreElements();) { String key = keys.nextElement(); @@ -87,21 +73,25 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory { try { uri = new URI(uriStr); } catch (URISyntaxException e) { - throw new UserDirectoryException("Badly formatted URI " - + uriStr, e); + throw new UserDirectoryException("Badly formatted URI " + uriStr, e); } - baseDn = UserAdminConf.baseDn.getValue(properties).toString(); + try { + baseDn = new LdapName(UserAdminConf.baseDn.getValue(properties)); + } catch (InvalidNameException e) { + throw new UserDirectoryException("Badly formated base DN " + UserAdminConf.baseDn.getValue(properties), e); + } String readOnlyStr = UserAdminConf.readOnly.getValue(properties); if (readOnlyStr == null) { readOnly = readOnlyDefault(uri); - properties.put(UserAdminConf.readOnly.property(), - Boolean.toString(readOnly)); + properties.put(UserAdminConf.readOnly.name(), Boolean.toString(readOnly)); } else readOnly = new Boolean(readOnlyStr); userObjectClass = UserAdminConf.userObjectClass.getValue(properties); + userBase = UserAdminConf.userBase.getValue(properties); groupObjectClass = UserAdminConf.groupObjectClass.getValue(properties); + groupBase = UserAdminConf.groupBase.getValue(properties); } /** Returns the groups this user is a direct member of. */ @@ -121,26 +111,18 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory { } - boolean isEditing() { - // if (editingTransactionXid == null) - // return false; - // return workingCopy.get() != null; + protected boolean isEditing() { return xaResource.wc() != null; } protected UserDirectoryWorkingCopy getWorkingCopy() { - // UserDirectoryWorkingCopy wc = workingCopy.get(); UserDirectoryWorkingCopy wc = xaResource.wc(); if (wc == null) return null; - // if (wc.getXid() == null) { - // workingCopy.set(null); - // return null; - // } return wc; } - void checkEdit() { + protected void checkEdit() { Transaction transaction; try { transaction = transactionManager.getTransaction(); @@ -148,32 +130,18 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory { throw new UserDirectoryException("Cannot get transaction", e); } if (transaction == null) - throw new UserDirectoryException( - "A transaction needs to be active in order to edit"); + throw new UserDirectoryException("A transaction needs to be active in order to edit"); if (xaResource.wc() == null) { - // UserDirectoryWorkingCopy wc = new UserDirectoryWorkingCopy(this); try { transaction.enlistResource(xaResource); - // editingTransactionXid = wc.getXid(); - // workingCopy.set(wc); } catch (Exception e) { - throw new UserDirectoryException("Cannot enlist " + xaResource, - e); + throw new UserDirectoryException("Cannot enlist " + xaResource, e); } } else { - // UserDirectoryWorkingCopy wc = xaResource.wc(); - // if (wc == null) - // throw new UserDirectoryException("Transaction " - // + editingTransactionXid + " already editing"); - // else if - // (!editingTransactionXid.equals(workingCopy.get().getXid())) - // throw new UserDirectoryException("Working copy Xid " - // + workingCopy.get().getXid() + " inconsistent with" - // + editingTransactionXid); } } - List getAllRoles(DirectoryUser user) { + protected List getAllRoles(DirectoryUser user) { List allRoles = new ArrayList(); if (user != null) { collectRoles(user, allRoles); @@ -240,8 +208,7 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory { @Override public User getUser(String key, String value) { // TODO check value null or empty - List collectedUsers = new ArrayList( - getIndexedUserProperties().size()); + List collectedUsers = new ArrayList(getIndexedUserProperties().size()); if (key != null) { doGetUser(key, value, collectedUsers); } else { @@ -261,28 +228,23 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory { if (collectedUsers.size() == 1) return collectedUsers.get(0); else if (collectedUsers.size() > 1) - log.warn(collectedUsers.size() + " users for " - + (key != null ? key + "=" : "") + value); + log.warn(collectedUsers.size() + " users for " + (key != null ? key + "=" : "") + value); return null; } - protected void doGetUser(String key, String value, - List collectedUsers) { + protected void doGetUser(String key, String value, List collectedUsers) { try { - Filter f = FrameworkUtil - .createFilter("(" + key + "=" + value + ")"); + Filter f = FrameworkUtil.createFilter("(" + key + "=" + value + ")"); List users = doGetRoles(f); collectedUsers.addAll(users); } catch (InvalidSyntaxException e) { - throw new UserDirectoryException("Cannot get user with " + key - + "=" + value, e); + throw new UserDirectoryException("Cannot get user with " + key + "=" + value, e); } } @Override public Authorization getAuthorization(User user) { - return new LdifAuthorization((DirectoryUser) user, - getAllRoles((DirectoryUser) user)); + return new LdifAuthorization((DirectoryUser) user, getAllRoles((DirectoryUser) user)); } @Override @@ -290,11 +252,10 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory { checkEdit(); UserDirectoryWorkingCopy wc = getWorkingCopy(); LdapName dn = toDn(name); - if ((daoHasRole(dn) && !wc.getDeletedUsers().containsKey(dn)) - || wc.getNewUsers().containsKey(dn)) + if ((daoHasRole(dn) && !wc.getDeletedUsers().containsKey(dn)) || wc.getNewUsers().containsKey(dn)) throw new UserDirectoryException("Already a role " + name); - BasicAttributes attrs = new BasicAttributes(); - attrs.put("dn", dn.toString()); + BasicAttributes attrs = new BasicAttributes(true); + // attrs.put(LdifName.dn.name(), dn.toString()); Rdn nameRdn = dn.getRdn(dn.size() - 1); // TODO deal with multiple attr RDN attrs.put(nameRdn.getType(), nameRdn.getValue()); @@ -315,41 +276,20 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory { if (type == Role.USER) { String userObjClass = newUserObjectClass(dn); objClass.add(userObjClass); - if (posixAccount.name().equals(userObjClass)) { - objClass.add(inetOrgPerson.name()); - objClass.add(organizationalPerson.name()); - objClass.add(person.name()); - - String username; - try { - username = dn.getRdn(dn.size() - 1).toAttributes() - .get(uid.name()).get().toString(); - } catch (NamingException e) { - throw new UserDirectoryException( - "Cannot extract username from " + dn, e); - } - // TODO look for uid in attributes too? - attrs.put(uidNumber.name(), new Long(max(uidNumber.name()) + 1)); - attrs.put(homeDirectory.name(), generateHomeDirectory(username)); - // TODO create user private group - // NB: on RHEL, the 'users' group has gid 100 - attrs.put(gidNumber.name(), 100); - // attrs.put(LdifName.loginShell.name(),"/sbin/nologin"); - } else if (inetOrgPerson.name().equals(userObjClass)) { + if (inetOrgPerson.name().equals(userObjClass)) { objClass.add(organizationalPerson.name()); objClass.add(person.name()); } else if (organizationalPerson.name().equals(userObjClass)) { objClass.add(person.name()); } - objClass.add(top); + objClass.add(top.name()); attrs.put(objClass); newRole = new LdifUser(this, dn, attrs); } else if (type == Role.GROUP) { String groupObjClass = getGroupObjectClass(); objClass.add(groupObjClass); - objClass.add(LdifName.extensibleObject.name()); - attrs.put(gidNumber.name(), new Long(max(gidNumber.name()) + 1)); - objClass.add(top); + // objClass.add(LdifName.extensibleObject.name()); + objClass.add(top.name()); attrs.put(objClass); newRole = new LdifGroup(this, dn, attrs); } else @@ -372,66 +312,11 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory { } for (LdapName groupDn : getDirectGroups(dn)) { DirectoryUser group = doGetRole(groupDn); - group.getAttributes().get(getMemberAttributeId()) - .remove(dn.toString()); + group.getAttributes().get(getMemberAttributeId()).remove(dn.toString()); } return actuallyDeleted; } - // POSIX - /** Generate path for a new user home */ - protected String generateHomeDirectory(String username) { - String base = homeDirectoryBase; - int atIndex = username.indexOf('@'); - if (atIndex > 0) { - String domain = username.substring(0, atIndex); - String name = username.substring(atIndex + 1); - return base + '/' + firstCharsToPath(domain, 2) + '/' + domain - + '/' + firstCharsToPath(name, 2) + '/' + name; - } else if (atIndex == 0 || atIndex == (username.length() - 1)) { - throw new ArgeoException("Unsupported username " + username); - } else { - return base + '/' + firstCharsToPath(username, 2) + '/' + username; - } - } - - protected long max(String attr) { - long max; - try { - List users = doGetRoles(FrameworkUtil - .createFilter("(" + attr + "=*)")); - max = 1000; - for (DirectoryUser user : users) { - long uid = Long.parseLong(user.getAttributes().get(attr).get() - .toString()); - if (uid > max) - max = uid; - } - } catch (Exception e) { - throw new UserDirectoryException("Cannot get max of " + attr, e); - } - return max; - } - - /** - * Creates depth from a string (typically a username) by adding levels based - * on its first characters: "aBcD",2 => a/aB - */ - public static String firstCharsToPath(String str, Integer nbrOfChars) { - if (str.length() < nbrOfChars) - throw new ArgeoException("String " + str - + " length must be greater or equal than " + nbrOfChars); - StringBuffer path = new StringBuffer(""); - StringBuffer curr = new StringBuffer(""); - for (int i = 0; i < nbrOfChars; i++) { - curr.append(str.charAt(i)); - path.append(curr); - if (i < nbrOfChars - 1) - path.append('/'); - } - return path.toString(); - } - // TRANSACTION protected void prepare(UserDirectoryWorkingCopy wc) { @@ -445,10 +330,6 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory { } - // void clearEditingTransactionXid() { - // editingTransactionXid = null; - // } - // UTILITIES protected LdapName toDn(String name) { try { @@ -459,12 +340,11 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory { } // GETTERS - - String getMemberAttributeId() { + protected String getMemberAttributeId() { return memberAttributeId; } - List getCredentialAttributeIds() { + protected List getCredentialAttributeIds() { return credentialAttributeIds; } @@ -497,32 +377,37 @@ abstract class AbstractUserDirectory implements UserAdmin, UserDirectory { return readOnly; } - UserAdmin getExternalRoles() { + protected UserAdmin getExternalRoles() { return externalRoles; } - public String getBaseDn() { - return baseDn; + public LdapName getBaseDn() { + // always clone so that the property is not modified by reference + return (LdapName) baseDn.clone(); } /** dn can be null, in that case a default should be returned. */ - protected String getUserObjectClass() { + public String getUserObjectClass() { return userObjectClass; } + public String getUserBase() { + return userBase; + } + protected String newUserObjectClass(LdapName dn) { - if (dn != null - && dn.getRdn(dn.size() - 1).toAttributes().get(uid.name()) != null) - return posixAccount.name(); - else - return getUserObjectClass(); + return getUserObjectClass(); } - protected String getGroupObjectClass() { + public String getGroupObjectClass() { return groupObjectClass; } - public Dictionary getProperties() { + public String getGroupBase() { + return groupBase; + } + + public Dictionary getProperties() { return properties; }