From e86e3691db8b4a426a6d5fd3cf255dc82fe05fc1 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Fri, 4 Sep 2015 10:01:12 +0000 Subject: [PATCH 1/1] Start generalizing LDIF/LDAP user admin git-svn-id: https://svn.argeo.org/commons/trunk@8363 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- .../osgi/useradmin/AbstractLdapUserAdmin.java | 14 +++ .../org/argeo/osgi/useradmin/LdifGroup.java | 65 ++++++++++---- .../argeo/osgi/useradmin/LdifUserAdmin.java | 90 +++++++++++++++++-- .../osgi/useradmin/UserAdminAggregator.java | 9 ++ .../useradmin/cm/LdapUserAdminFactory.java | 53 +++++++++++ 5 files changed, 204 insertions(+), 27 deletions(-) create mode 100644 org.argeo.security.core/src/org/argeo/osgi/useradmin/UserAdminAggregator.java create mode 100644 org.argeo.security.core/src/org/argeo/osgi/useradmin/cm/LdapUserAdminFactory.java diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/AbstractLdapUserAdmin.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/AbstractLdapUserAdmin.java index df2ad4e8a..254e5423c 100644 --- a/org.argeo.security.core/src/org/argeo/osgi/useradmin/AbstractLdapUserAdmin.java +++ b/org.argeo.security.core/src/org/argeo/osgi/useradmin/AbstractLdapUserAdmin.java @@ -10,6 +10,8 @@ public abstract class AbstractLdapUserAdmin implements UserAdmin { private boolean isReadOnly; private URI uri; + private UserAdmin externalRoles; + public AbstractLdapUserAdmin() { } @@ -45,8 +47,20 @@ public abstract class AbstractLdapUserAdmin implements UserAdmin { return isReadOnly; } + public void init() { + + } + public void destroy() { } + UserAdmin getExternalRoles() { + return externalRoles; + } + + public void setExternalRoles(UserAdmin externalRoles) { + this.externalRoles = externalRoles; + } + } diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifGroup.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifGroup.java index 4154d55a7..fbc678c52 100644 --- a/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifGroup.java +++ b/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifGroup.java @@ -15,13 +15,24 @@ public class LdifGroup extends LdifUser implements Group { // optimisation List directMembers = null; + private String memberAttrName = "member"; + public LdifGroup(LdapName dn, Attributes attributes) { super(dn, attributes); } @Override public boolean addMember(Role role) { - throw new UnsupportedOperationException(); + Attribute member = getAttributes().get(memberAttrName); + if (member != null) { + if (member.contains(role.getName())) + return false; + } else + getAttributes().put(memberAttrName, role.getName()); + directMembers.add(role); + if (role instanceof LdifUser) + ((LdifUser) role).directMemberOf.add(this); + return true; } @Override @@ -31,7 +42,17 @@ public class LdifGroup extends LdifUser implements Group { @Override public boolean removeMember(Role role) { - throw new UnsupportedOperationException(); + Attribute member = getAttributes().get(memberAttrName); + if (member != null) { + if (!member.contains(role.getName())) + return false; + member.remove(role.getName()); + directMembers.remove(role); + if (role instanceof LdifUser) + ((LdifUser) role).directMemberOf.remove(this); + return true; + } else + return false; } @Override @@ -41,7 +62,7 @@ public class LdifGroup extends LdifUser implements Group { else throw new ArgeoUserAdminException("Members have not been loaded."); - // Attribute memberAttribute = getAttributes().get("member"); + // Attribute memberAttribute = getAttributes().get(memberAttrName); // if (memberAttribute == null) // return new Role[0]; // try { @@ -57,24 +78,24 @@ public class LdifGroup extends LdifUser implements Group { // } } - void loadMembers(LdifUserAdmin userAdmin) { - directMembers = new ArrayList(); - for (LdapName ldapName : getMemberNames()) { - LdifUser role; - if (userAdmin.groups.containsKey(ldapName)) - role = userAdmin.groups.get(ldapName); - else if (userAdmin.users.containsKey(ldapName)) - role = userAdmin.users.get(ldapName); - else - throw new ArgeoUserAdminException("No roel found for " - + ldapName); - role.directMemberOf.add(this); - directMembers.add(role); - } - } +// void loadMembers(LdifUserAdmin userAdmin) { +// directMembers = new ArrayList(); +// for (LdapName ldapName : getMemberNames()) { +// LdifUser role; +// if (userAdmin.groups.containsKey(ldapName)) +// role = userAdmin.groups.get(ldapName); +// else if (userAdmin.users.containsKey(ldapName)) +// role = userAdmin.users.get(ldapName); +// else +// throw new ArgeoUserAdminException("No role found for " +// + ldapName); +// role.directMemberOf.add(this); +// directMembers.add(role); +// } +// } List getMemberNames() { - Attribute memberAttribute = getAttributes().get("member"); + Attribute memberAttribute = getAttributes().get(memberAttrName); if (memberAttribute == null) return new ArrayList(); try { @@ -99,4 +120,10 @@ public class LdifGroup extends LdifUser implements Group { public int getType() { return GROUP; } + + public String getMemberAttrName() { + return memberAttrName; + } + + } 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 b1e9ceb49..dacae7964 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 @@ -14,7 +14,9 @@ import java.util.TreeMap; import javax.naming.InvalidNameException; import javax.naming.NamingEnumeration; import javax.naming.directory.Attributes; +import javax.naming.directory.BasicAttributes; import javax.naming.ldap.LdapName; +import javax.naming.ldap.Rdn; import org.osgi.framework.Filter; import org.osgi.framework.FrameworkUtil; @@ -46,11 +48,6 @@ public class LdifUserAdmin extends AbstractLdapUserAdmin { throw new UnsupportedOperationException(getUri().getScheme() + "not supported read-write."); - try { - load(getUri().toURL().openStream()); - } catch (Exception e) { - throw new ArgeoUserAdminException("Cannot open URL " + getUri(), e); - } } public LdifUserAdmin(InputStream in) { @@ -59,6 +56,14 @@ public class LdifUserAdmin extends AbstractLdapUserAdmin { setUri(null); } + public void init() { + try { + load(getUri().toURL().openStream()); + } catch (Exception e) { + throw new ArgeoUserAdminException("Cannot open URL " + getUri(), e); + } + } + protected void load(InputStream in) { try { LdifParser ldifParser = new LdifParser(); @@ -81,7 +86,7 @@ public class LdifUserAdmin extends AbstractLdapUserAdmin { // optimise for (LdifGroup group : groups.values()) - group.loadMembers(this); + loadMembers(group); // indexes for (String attr : getIndexedUserProperties()) @@ -140,12 +145,60 @@ public class LdifUserAdmin extends AbstractLdapUserAdmin { @Override public Role createRole(String name, int type) { - throw new UnsupportedOperationException(); + try { + LdapName dn = new LdapName(name); + if (users.containsKey(dn) || groups.containsKey(dn)) + throw new ArgeoUserAdminException("Already a role " + name); + + BasicAttributes attrs = new BasicAttributes(); + attrs.put("dn", dn.toString()); + Rdn nameRdn = dn.getRdn(dn.size() - 1); + // TODO deal with multiple attr RDN + attrs.put(nameRdn.getType(), nameRdn.getValue()); + LdifUser newRole; + if (type == Role.USER) { + newRole = new LdifUser(dn, attrs); + users.put(dn, newRole); + } else if (type == Role.GROUP) { + newRole = new LdifGroup(dn, attrs); + groups.put(dn, (LdifGroup) newRole); + } else + throw new ArgeoUserAdminException("Unsupported type " + type); + return newRole; + } catch (InvalidNameException e) { + throw new ArgeoUserAdminException("Cannot create role " + name, e); + } } @Override public boolean removeRole(String name) { - throw new UnsupportedOperationException(); + try { + LdapName dn = new LdapName(name); + LdifUser role = null; + if (users.containsKey(dn)) + role = users.remove(dn); + else if (groups.containsKey(dn)) + role = groups.remove(dn); + else + throw new ArgeoUserAdminException("There is no role " + name); + if (role == null) + return false; + for (LdifGroup group : role.directMemberOf) { + group.directMembers.remove(role); + group.getAttributes().get(group.getMemberAttrName()) + .remove(dn.toString()); + } + if (role instanceof LdifGroup) { + LdifGroup group = (LdifGroup) role; + for (Role user : group.directMembers) { + if (user instanceof LdifUser) + ((LdifUser) user).directMemberOf.remove(group); + } + } + return true; + } catch (InvalidNameException e) { + throw new ArgeoUserAdminException("Cannot create role " + name, e); + } } @Override @@ -199,4 +252,25 @@ public class LdifUserAdmin extends AbstractLdapUserAdmin { // throw new UnsupportedOperationException(); } + protected void loadMembers(LdifGroup group) { + group.directMembers = new ArrayList(); + for (LdapName ldapName : group.getMemberNames()) { + LdifUser role = null; + if (groups.containsKey(ldapName)) + role = groups.get(ldapName); + else if (users.containsKey(ldapName)) + role = users.get(ldapName); + else { + if (getExternalRoles() != null) + role = (LdifUser) getExternalRoles().getRole( + ldapName.toString()); + if (role == null) + throw new ArgeoUserAdminException("No role found for " + + ldapName); + } + role.directMemberOf.add(group); + group.directMembers.add(role); + } + } + } diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/UserAdminAggregator.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/UserAdminAggregator.java new file mode 100644 index 000000000..9113117aa --- /dev/null +++ b/org.argeo.security.core/src/org/argeo/osgi/useradmin/UserAdminAggregator.java @@ -0,0 +1,9 @@ +package org.argeo.osgi.useradmin; + +import org.osgi.service.useradmin.UserAdmin; + +public interface UserAdminAggregator { + public void addUserAdmin(String baseDn, UserAdmin userAdmin); + + public void removeUserAdmin(String baseDn); +} diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/cm/LdapUserAdminFactory.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/cm/LdapUserAdminFactory.java new file mode 100644 index 000000000..64fdea0b0 --- /dev/null +++ b/org.argeo.security.core/src/org/argeo/osgi/useradmin/cm/LdapUserAdminFactory.java @@ -0,0 +1,53 @@ +package org.argeo.osgi.useradmin.cm; + +import java.util.Dictionary; +import java.util.HashMap; +import java.util.Map; + +import org.argeo.osgi.useradmin.AbstractLdapUserAdmin; +import org.argeo.osgi.useradmin.ArgeoUserAdminException; +import org.argeo.osgi.useradmin.LdapUserAdmin; +import org.argeo.osgi.useradmin.LdifUserAdmin; +import org.argeo.osgi.useradmin.UserAdminAggregator; +import org.osgi.service.cm.ConfigurationException; +import org.osgi.service.cm.ManagedServiceFactory; + +public class LdapUserAdminFactory implements ManagedServiceFactory { + private final UserAdminAggregator userAdminAggregator; + + private Map index = new HashMap(); + + public LdapUserAdminFactory(UserAdminAggregator userAdminAggregator) { + this.userAdminAggregator = userAdminAggregator; + } + + @Override + public String getName() { + return "LDAP/LDIF User Source"; + } + + @Override + public synchronized void updated(String pid, + Dictionary properties) throws ConfigurationException { + String baseDn = properties.get("baseDn").toString(); + String userAdminUri = properties.get("uri").toString(); + AbstractLdapUserAdmin userAdmin; + if (userAdminUri.startsWith("ldap")) + userAdmin = new LdapUserAdmin(userAdminUri); + else + userAdmin = new LdifUserAdmin(userAdminUri); + userAdminAggregator.addUserAdmin(baseDn, userAdmin); + index.put(pid, baseDn); + } + + @Override + public synchronized void deleted(String pid) { + if (index.containsKey(pid)) + userAdminAggregator.removeUserAdmin(index.get(pid)); + else + throw new ArgeoUserAdminException("No user admin registered for " + + pid); + index.remove(pid); + } + +} -- 2.39.2