From 08fac35eeedb151c2fd1cc85ed4a36adf66e02fc Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Fri, 4 Sep 2015 10:01:43 +0000 Subject: [PATCH] Introduce aggregating node user admin git-svn-id: https://svn.argeo.org/commons/trunk@8364 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- .../cms/internal/kernel/KernelConstants.java | 1 + .../cms/internal/kernel/NodeSecurity.java | 44 +++++- .../cms/internal/kernel/NodeUserAdmin.java | 149 ++++++++++++++++++ .../internal/kernel/dc=example,dc=com.ldif | 41 +++++ .../org/argeo/cms/internal/kernel/demo.ldif | 42 ----- 5 files changed, 229 insertions(+), 48 deletions(-) create mode 100644 org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeUserAdmin.java create mode 100644 org.argeo.cms/src/org/argeo/cms/internal/kernel/dc=example,dc=com.ldif diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java index f273242c5..2663650b9 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java @@ -19,6 +19,7 @@ public interface KernelConstants { // Node Security /** URI to an LDIF file used as initialization or backend */ final static String USERADMIN_URI = "argeo.node.useradmin.uri"; + final static String ROLES_BASEDN = "ou=system,ou=node"; final static String[] DEFAULT_CNDS = { "/org/argeo/jcr/argeo.cnd", "/org/argeo/cms/cms.cnd" }; diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java index 5e9877935..83216d048 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java @@ -1,10 +1,15 @@ package org.argeo.cms.internal.kernel; +import java.io.File; +import java.io.IOException; + import javax.jcr.RepositoryException; +import org.apache.commons.io.FileUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.cms.CmsException; +import org.argeo.cms.KernelHeader; import org.argeo.cms.internal.useradmin.SimpleJcrSecurityModel; import org.argeo.cms.internal.useradmin.jackrabbit.JackrabbitUserAdminService; import org.argeo.osgi.useradmin.AbstractLdapUserAdmin; @@ -17,6 +22,7 @@ import org.argeo.security.core.InternalAuthenticationProvider; import org.argeo.security.core.OsAuthenticationProvider; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; +import org.osgi.service.useradmin.Role; import org.osgi.service.useradmin.UserAdmin; import org.springframework.security.authentication.AnonymousAuthenticationProvider; import org.springframework.security.authentication.AnonymousAuthenticationToken; @@ -36,7 +42,7 @@ class NodeSecurity implements AuthenticationManager { private final InternalAuthenticationProvider internalAuth; private final AnonymousAuthenticationProvider anonymousAuth; private final JackrabbitUserAdminService userAdminService; - private final AbstractLdapUserAdmin userAdmin; + private final NodeUserAdmin userAdmin; private ServiceRegistration authenticationManagerReg; private ServiceRegistration userAdminServiceReg; @@ -60,15 +66,41 @@ class NodeSecurity implements AuthenticationManager { userAdminService.setSecurityModel(new SimpleJcrSecurityModel()); userAdminService.init(); + userAdmin = new NodeUserAdmin(); + + String baseDn = "dc=example,dc=com"; String userAdminUri = KernelUtils .getFrameworkProp(KernelConstants.USERADMIN_URI); if (userAdminUri == null) - userAdminUri = getClass().getResource("demo.ldif").toString(); + userAdminUri = getClass().getResource(baseDn + ".ldif").toString(); + AbstractLdapUserAdmin businessRoles; if (userAdminUri.startsWith("ldap")) - userAdmin = new LdapUserAdmin(userAdminUri); - else - userAdmin = new LdifUserAdmin(userAdminUri); + businessRoles = new LdapUserAdmin(userAdminUri); + else { + businessRoles = new LdifUserAdmin(userAdminUri); + } + businessRoles.init(); + userAdmin.addUserAdmin(baseDn, businessRoles); + + File osgiInstanceDir = KernelUtils.getOsgiInstanceDir(); + File homeDir = new File(osgiInstanceDir, "node"); + + String baseNodeRoleDn = KernelConstants.ROLES_BASEDN; + File nodeRolesFile = new File(homeDir, baseNodeRoleDn + ".ldif"); + try { + FileUtils.copyInputStreamToFile( + getClass().getResourceAsStream("demo.ldif"), nodeRolesFile); + } catch (IOException e) { + throw new CmsException("Cannot copy demo resource", e); + } + LdifUserAdmin nodeRoles = new LdifUserAdmin(nodeRolesFile.toURI() + .toString()); + nodeRoles.setExternalRoles(userAdmin); + nodeRoles.init(); + // nodeRoles.createRole(KernelHeader.ROLE_ADMIN, Role.GROUP); + userAdmin.addUserAdmin(baseNodeRoleDn, nodeRoles); + } public void publish() { @@ -92,7 +124,7 @@ class NodeSecurity implements AuthenticationManager { userAdminServiceReg.unregister(); authenticationManagerReg.unregister(); - userAdmin.destroy(); + // userAdmin.destroy(); userAdminReg.unregister(); } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeUserAdmin.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeUserAdmin.java new file mode 100644 index 000000000..d8dcf0e36 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeUserAdmin.java @@ -0,0 +1,149 @@ +package org.argeo.cms.internal.kernel; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.naming.InvalidNameException; +import javax.naming.ldap.LdapName; + +import org.argeo.osgi.useradmin.ArgeoUserAdminException; +import org.argeo.osgi.useradmin.UserAdminAggregator; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.service.useradmin.Authorization; +import org.osgi.service.useradmin.Role; +import org.osgi.service.useradmin.User; +import org.osgi.service.useradmin.UserAdmin; + +public class NodeUserAdmin implements UserAdmin, UserAdminAggregator { + final static LdapName ROLES_BASE; + static { + try { + ROLES_BASE = new LdapName(KernelConstants.ROLES_BASEDN); + } catch (InvalidNameException e) { + throw new ArgeoUserAdminException("Cannot initialize " + + NodeUserAdmin.class, e); + } + } + + private UserAdmin nodeRoles = null; + private Map userAdmins = new HashMap(); + + @Override + public Role createRole(String name, int type) { + return findUserAdmin(name).createRole(name, type); + } + + @Override + public boolean removeRole(String name) { + return findUserAdmin(name).removeRole(name); + } + + @Override + public Role getRole(String name) { + return findUserAdmin(name).getRole(name); + } + + @Override + public Role[] getRoles(String filter) throws InvalidSyntaxException { + List res = new ArrayList(); + for (UserAdmin userAdmin : userAdmins.values()) { + res.addAll(Arrays.asList(userAdmin.getRoles(filter))); + } + res.addAll(Arrays.asList(nodeRoles.getRoles(filter))); + return res.toArray(new Role[res.size()]); + } + + @Override + public User getUser(String key, String value) { + List res = new ArrayList(); + for (UserAdmin userAdmin : userAdmins.values()) { + User u = userAdmin.getUser(key, value); + if (u != null) + res.add(u); + } + // Note: node roles cannot contain users, so it is not searched + return res.size() == 1 ? res.get(0) : null; + } + + @Override + public Authorization getAuthorization(User user) { + UserAdmin userAdmin = findUserAdmin(user.getName()); + // FIXME clarify assumptions + return userAdmin.getAuthorization(user); + // String[] roles = auth.getRoles(); + // // Gather system roles + // Set systemRoles = new HashSet(); + // for(String businessRole:roles){ + // + // } + // return null; + } + + // + // USER ADMIN AGGREGATOR + // + @Override + public synchronized void addUserAdmin(String baseDn, UserAdmin userAdmin) { + if (baseDn.equals(KernelConstants.ROLES_BASEDN)) { + nodeRoles = userAdmin; + return; + } + + if (userAdmins.containsKey(baseDn)) + throw new ArgeoUserAdminException( + "There is already a user admin for " + baseDn); + try { + userAdmins.put(new LdapName(baseDn), userAdmin); + } catch (InvalidNameException e) { + throw new ArgeoUserAdminException("Badly formatted base DN " + + baseDn, e); + } + } + + @Override + public synchronized void removeUserAdmin(String baseDn) { + if (baseDn.equals(KernelConstants.ROLES_BASEDN)) + throw new ArgeoUserAdminException("Node roles cannot be removed."); + LdapName base; + try { + base = new LdapName(baseDn); + } catch (InvalidNameException e) { + throw new ArgeoUserAdminException("Badly formatted base DN " + + baseDn, e); + } + if (!userAdmins.containsKey(base)) + throw new ArgeoUserAdminException("There is no user admin for " + + base); + userAdmins.remove(base); + } + + private UserAdmin findUserAdmin(String name) { + try { + return findUserAdmin(new LdapName(name)); + } catch (InvalidNameException e) { + throw new ArgeoUserAdminException("Badly formatted name " + name, e); + } + } + + private UserAdmin findUserAdmin(LdapName name) { + if (name.startsWith(ROLES_BASE)) + return nodeRoles; + List res = new ArrayList(1); + for (LdapName baseDn : userAdmins.keySet()) { + if (name.startsWith(baseDn)) + res.add(userAdmins.get(baseDn)); + } + if (res.size() == 0) + throw new ArgeoUserAdminException("Cannot find user admin for " + + name); + if (res.size() > 1) + throw new ArgeoUserAdminException("Multiple user admin found for " + + name); + return res.get(0); + } +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/dc=example,dc=com.ldif b/org.argeo.cms/src/org/argeo/cms/internal/kernel/dc=example,dc=com.ldif new file mode 100644 index 000000000..fda4eadf7 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/dc=example,dc=com.ldif @@ -0,0 +1,41 @@ +dn: dc=example,dc=com +objectClass: domain +objectClass: extensibleObject +objectClass: top +dc: example + +dn: ou=groups,dc=example,dc=com +objectClass: organizationalUnit +objectClass: top +ou: groups + +dn: ou=users,dc=example,dc=com +objectClass: organizationalUnit +objectClass: top +ou: users + +dn: uid=demo,ou=users,dc=example,dc=com +objectClass: inetOrgPerson +objectClass: organizationalPerson +objectClass: person +objectClass: top +cn: Demo User +description: Demo user +givenname: Demo +mail: demo@localhost +sn: User +uid: demo +userpassword:: e1NIQX1pZVNWNTVRYytlUU9hWURSU2hhL0Fqek5USkU9 + +dn: uid=root,ou=users,dc=example,dc=com +objectClass: inetOrgPerson +objectClass: person +objectClass: organizationalPerson +objectClass: top +cn: Super User +description: Superuser +givenname: Super +mail: root@localhost +sn: User +uid: root +userpassword:: e1NIQX1pZVNWNTVRYytlUU9hWURSU2hhL0Fqek5USkU9 diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/demo.ldif b/org.argeo.cms/src/org/argeo/cms/internal/kernel/demo.ldif index 1f172b29c..7370ea5af 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/demo.ldif +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/demo.ldif @@ -1,45 +1,3 @@ -dn: dc=example,dc=com -objectClass: domain -objectClass: extensibleObject -objectClass: top -dc: example - -dn: ou=groups,dc=example,dc=com -objectClass: organizationalUnit -objectClass: top -ou: groups - -dn: ou=users,dc=example,dc=com -objectClass: organizationalUnit -objectClass: top -ou: users - -dn: uid=demo,ou=users,dc=example,dc=com -objectClass: inetOrgPerson -objectClass: organizationalPerson -objectClass: person -objectClass: top -cn: Demo User -description: Demo user -givenname: Demo -mail: demo@localhost -sn: User -uid: demo -userpassword:: e1NIQX1pZVNWNTVRYytlUU9hWURSU2hhL0Fqek5USkU9 - -dn: uid=root,ou=users,dc=example,dc=com -objectClass: inetOrgPerson -objectClass: person -objectClass: organizationalPerson -objectClass: top -cn: Super User -description: Superuser -givenname: Super -mail: root@localhost -sn: User -uid: root -userpassword:: e1NIQX1pZVNWNTVRYytlUU9hWURSU2hhL0Fqek5USkU9 - dn: ou=node objectClass: organizationalUnit objectClass: top -- 2.30.2