X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;ds=sidebyside;f=org.argeo.security.core%2Fsrc%2Forg%2Fargeo%2Fosgi%2Fuseradmin%2FLdifUserAdmin.java;h=521ae8bb6e89916c6b88ea490767658e8b3012fa;hb=8260f4470f514ea347ca53f5b4dfc632c4a4de66;hp=5796b46c4e0e19cb7c22b94c3dc5e7362289affd;hpb=e96c7f26228b70f604e41b7a56ce6c5836da9e12;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifUserAdmin.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifUserAdmin.java index 5796b46c4..521ae8bb6 100644 --- a/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifUserAdmin.java +++ b/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifUserAdmin.java @@ -1,88 +1,238 @@ package org.argeo.osgi.useradmin; +import static org.argeo.osgi.useradmin.LdifName.inetOrgPerson; +import static org.argeo.osgi.useradmin.LdifName.objectClass; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Dictionary; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.List; +import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; -import javax.naming.InvalidNameException; import javax.naming.NamingEnumeration; import javax.naming.directory.Attributes; import javax.naming.ldap.LdapName; +import javax.transaction.TransactionManager; -import org.osgi.framework.InvalidSyntaxException; -import org.osgi.service.useradmin.Authorization; +import org.argeo.util.naming.LdifParser; +import org.argeo.util.naming.LdifWriter; +import org.osgi.framework.Filter; import org.osgi.service.useradmin.Role; -import org.osgi.service.useradmin.User; -import org.osgi.service.useradmin.UserAdmin; -public class LdifUserAdmin implements UserAdmin { - private SortedMap roles = new TreeMap(); +/** + * A user admin based on a LDIF files. Requires a {@link TransactionManager} and + * an open transaction for write access. + */ +public class LdifUserAdmin extends AbstractUserDirectory { + private SortedMap users = new TreeMap(); + private SortedMap groups = new TreeMap(); + + public LdifUserAdmin(String uri, String baseDn) { + this(fromUri(uri, baseDn)); + } + + public LdifUserAdmin(Dictionary properties) { + super(properties); + } public LdifUserAdmin(InputStream in) { + super(new Hashtable()); + load(in); + } + + private static Dictionary fromUri(String uri, String baseDn) { + Hashtable res = new Hashtable(); + res.put(UserAdminConf.uri.name(), uri); + res.put(UserAdminConf.baseDn.name(), baseDn); + return res; + } + + public void init() { + try { + if (getUri().getScheme().equals("file")) { + File file = new File(getUri()); + if (!file.exists()) + return; + } + load(getUri().toURL().openStream()); + } catch (Exception e) { + throw new UserDirectoryException("Cannot open URL " + getUri(), e); + } + } + + public void save() { + if (getUri() == null) + throw new UserDirectoryException("Cannot save LDIF user admin: no URI is set"); + if (isReadOnly()) + throw new UserDirectoryException("Cannot save LDIF user admin: " + getUri() + " is read-only"); + try (FileOutputStream out = new FileOutputStream(new File(getUri()))) { + save(out); + } catch (IOException e) { + throw new UserDirectoryException("Cannot save user admin to " + getUri(), e); + } + } + + public void save(OutputStream out) throws IOException { + try { + LdifWriter ldifWriter = new LdifWriter(out); + for (LdapName name : groups.keySet()) + ldifWriter.writeEntry(name, groups.get(name).getAttributes()); + for (LdapName name : users.keySet()) + ldifWriter.writeEntry(name, users.get(name).getAttributes()); + } finally { + out.close(); + } + } + + protected void load(InputStream in) { try { + users.clear(); + groups.clear(); + LdifParser ldifParser = new LdifParser(); SortedMap allEntries = ldifParser.read(in); for (LdapName key : allEntries.keySet()) { Attributes attributes = allEntries.get(key); - NamingEnumeration objectClasses = attributes.get("objectClass") - .getAll(); + // check for inconsistency + Set lowerCase = new HashSet(); + NamingEnumeration ids = attributes.getIDs(); + while (ids.hasMoreElements()) { + String id = ids.nextElement().toLowerCase(); + if (lowerCase.contains(id)) + throw new UserDirectoryException(key + " has duplicate id " + id); + lowerCase.add(id); + } + + // analyse object classes + NamingEnumeration objectClasses = attributes.get(objectClass.name()).getAll(); + // System.out.println(key); objectClasses: while (objectClasses.hasMore()) { String objectClass = objectClasses.next().toString(); - if (objectClass.equals("inetOrgPerson")) { - roles.put(key, new LdifUser(key, attributes)); + // System.out.println(" " + objectClass); + if (objectClass.equals(inetOrgPerson.name())) { + users.put(key, new LdifUser(this, key, attributes)); break objectClasses; - } else if (objectClass.equals("groupOfNames")) { - roles.put(key, new LdifGroup(key, attributes)); + } else if (objectClass.equals(getGroupObjectClass())) { + groups.put(key, new LdifGroup(this, key, attributes)); break objectClasses; } } } } catch (Exception e) { - throw new ArgeoUserAdminException( - "Cannot initialise user admin service from LDIF", e); + throw new UserDirectoryException("Cannot load user admin service from LDIF", e); } } - @Override - public Role getRole(String name) { - LdapName key; - try { - key = new LdapName(name); - } catch (InvalidNameException e) { - // TODO implements default base DN - throw new IllegalArgumentException("Badly formatted role name: " - + name, e); - } - - if (!roles.containsKey(key)) - return null; - return roles.get(key); + public void destroy() { + if (users == null || groups == null) + throw new UserDirectoryException("User directory " + getBaseDn() + " is already destroyed"); + users.clear(); + users = null; + groups.clear(); + groups = null; } - @Override - public Authorization getAuthorization(User user) { - // TODO Auto-generated method stub + protected DirectoryUser daoGetRole(LdapName key) { + if (groups.containsKey(key)) + return groups.get(key); + if (users.containsKey(key)) + return users.get(key); return null; } + protected Boolean daoHasRole(LdapName dn) { + return users.containsKey(dn) || groups.containsKey(dn); + } + + @SuppressWarnings("unchecked") + protected List doGetRoles(Filter f) { + ArrayList res = new ArrayList(); + if (f == null) { + res.addAll(users.values()); + res.addAll(groups.values()); + } else { + for (DirectoryUser user : users.values()) { + // System.out.println("\n" + user.getName()); + // Dictionary props = user.getProperties(); + // for (Enumeration keys = props.keys(); keys + // .hasMoreElements();) { + // String key = keys.nextElement(); + // System.out.println(" " + key + "=" + props.get(key)); + // } + if (f.match(user.getProperties())) + res.add(user); + } + for (DirectoryUser group : groups.values()) + if (f.match(group.getProperties())) + res.add(group); + } + return res; + } + @Override - public Role createRole(String name, int type) { - throw new UnsupportedOperationException(); + protected List getDirectGroups(LdapName dn) { + List directGroups = new ArrayList(); + for (LdapName name : groups.keySet()) { + DirectoryGroup group = groups.get(name); + if (group.getMemberNames().contains(dn)) + directGroups.add(group.getDn()); + } + return directGroups; } @Override - public boolean removeRole(String name) { - throw new UnsupportedOperationException(); + protected void prepare(UserDirectoryWorkingCopy wc) { + // delete + for (LdapName dn : wc.getDeletedUsers().keySet()) { + if (users.containsKey(dn)) + users.remove(dn); + else if (groups.containsKey(dn)) + groups.remove(dn); + else + throw new UserDirectoryException("User to delete not found " + dn); + } + // add + for (LdapName dn : wc.getNewUsers().keySet()) { + DirectoryUser user = wc.getNewUsers().get(dn); + if (users.containsKey(dn) || groups.containsKey(dn)) + throw new UserDirectoryException("User to create found " + dn); + else if (Role.USER == user.getType()) + users.put(dn, user); + else if (Role.GROUP == user.getType()) + groups.put(dn, (DirectoryGroup) user); + else + throw new UserDirectoryException("Unsupported role type " + user.getType() + " for new user " + dn); + } + // modify + for (LdapName dn : wc.getModifiedUsers().keySet()) { + Attributes modifiedAttrs = wc.getModifiedUsers().get(dn); + DirectoryUser user; + if (users.containsKey(dn)) + user = users.get(dn); + else if (groups.containsKey(dn)) + user = groups.get(dn); + else + throw new UserDirectoryException("User to modify no found " + dn); + user.publishAttributes(modifiedAttrs); + } } @Override - public Role[] getRoles(String filter) throws InvalidSyntaxException { - throw new UnsupportedOperationException(); + protected void commit(UserDirectoryWorkingCopy wc) { + save(); } @Override - public User getUser(String key, String value) { - throw new UnsupportedOperationException(); + protected void rollback(UserDirectoryWorkingCopy wc) { + init(); } }