From e96c7f26228b70f604e41b7a56ce6c5836da9e12 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Mon, 24 Aug 2015 18:36:11 +0000 Subject: [PATCH] Introduce LDIF OSGi User Admin implementation git-svn-id: https://svn.argeo.org/commons/trunk@8336 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- .../osgi/useradmin/BasicTestConstants.java | 6 ++ .../argeo/osgi/useradmin/LdifParserTest.java | 11 ++- .../osgi/useradmin/LdifUserAdminTest.java | 22 +++++ .../osgi/useradmin/{test.ldif => basic.ldif} | 0 .../useradmin/ArgeoUserAdminException.java | 19 ++++ .../osgi/useradmin/AttributeDictionary.java | 73 +++++++++++++++ .../org/argeo/osgi/useradmin/LdifGroup.java | 63 +++++++++++++ .../org/argeo/osgi/useradmin/LdifParser.java | 4 +- .../org/argeo/osgi/useradmin/LdifUser.java | 59 +++++++++++++ .../argeo/osgi/useradmin/LdifUserAdmin.java | 88 +++++++++++++++++++ 10 files changed, 337 insertions(+), 8 deletions(-) create mode 100644 org.argeo.security.core/ext/test/org/argeo/osgi/useradmin/BasicTestConstants.java create mode 100644 org.argeo.security.core/ext/test/org/argeo/osgi/useradmin/LdifUserAdminTest.java rename org.argeo.security.core/ext/test/org/argeo/osgi/useradmin/{test.ldif => basic.ldif} (100%) create mode 100644 org.argeo.security.core/src/org/argeo/osgi/useradmin/ArgeoUserAdminException.java create mode 100644 org.argeo.security.core/src/org/argeo/osgi/useradmin/AttributeDictionary.java create mode 100644 org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifGroup.java create mode 100644 org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifUser.java create mode 100644 org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifUserAdmin.java diff --git a/org.argeo.security.core/ext/test/org/argeo/osgi/useradmin/BasicTestConstants.java b/org.argeo.security.core/ext/test/org/argeo/osgi/useradmin/BasicTestConstants.java new file mode 100644 index 000000000..f608cce86 --- /dev/null +++ b/org.argeo.security.core/ext/test/org/argeo/osgi/useradmin/BasicTestConstants.java @@ -0,0 +1,6 @@ +package org.argeo.osgi.useradmin; + +interface BasicTestConstants { + final static String ROOT_USER_DN = "uid=root+cn=Super Admin,ou=People,dc=demo,dc=example,dc=org"; + final static String ADMIN_GROUP_DN = "cn=admin,ou=Roles,dc=demo,dc=example,dc=org"; +} diff --git a/org.argeo.security.core/ext/test/org/argeo/osgi/useradmin/LdifParserTest.java b/org.argeo.security.core/ext/test/org/argeo/osgi/useradmin/LdifParserTest.java index ae584a18c..75a5c34b3 100644 --- a/org.argeo.security.core/ext/test/org/argeo/osgi/useradmin/LdifParserTest.java +++ b/org.argeo.security.core/ext/test/org/argeo/osgi/useradmin/LdifParserTest.java @@ -14,13 +14,12 @@ import junit.framework.TestCase; import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.digest.DigestUtils; -public class LdifParserTest extends TestCase { - public void testSimpleLdif() throws Exception { +public class LdifParserTest extends TestCase implements BasicTestConstants { + public void testBasicLdif() throws Exception { LdifParser ldifParser = new LdifParser(); SortedMap res = ldifParser.read(getClass() - .getResourceAsStream("test.ldif")); - LdapName rootDn = new LdapName( - "uid=root+cn=Super Admin,ou=People,dc=demo,dc=example,dc=org"); + .getResourceAsStream("basic.ldif")); + LdapName rootDn = new LdapName(ROOT_USER_DN); Attributes rootAttributes = res.get(rootDn); assertNotNull(rootAttributes); assertEquals("Superuser", rootAttributes.get("description").get()); @@ -32,7 +31,7 @@ public class LdifParserTest extends TestCase { new String(rawPwEntry)); LdapName adminDn = new LdapName( - "cn=admin,ou=Roles,dc=demo,dc=example,dc=org"); + ADMIN_GROUP_DN); Attributes adminAttributes = res.get(adminDn); assertNotNull(adminAttributes); Attribute memberAttribute = adminAttributes.get("member"); diff --git a/org.argeo.security.core/ext/test/org/argeo/osgi/useradmin/LdifUserAdminTest.java b/org.argeo.security.core/ext/test/org/argeo/osgi/useradmin/LdifUserAdminTest.java new file mode 100644 index 000000000..75a58d0d3 --- /dev/null +++ b/org.argeo.security.core/ext/test/org/argeo/osgi/useradmin/LdifUserAdminTest.java @@ -0,0 +1,22 @@ +package org.argeo.osgi.useradmin; + +import junit.framework.TestCase; + +import org.osgi.service.useradmin.Group; +import org.osgi.service.useradmin.Role; +import org.osgi.service.useradmin.User; + +public class LdifUserAdminTest extends TestCase implements BasicTestConstants { + + public void testBasicUserAdmin() { + LdifUserAdmin userAdmin = new LdifUserAdmin(getClass() + .getResourceAsStream("basic.ldif")); + User rootUser = (User) userAdmin.getRole(ROOT_USER_DN); + assertNotNull(rootUser); + Group adminGroup = (Group) userAdmin.getRole(ADMIN_GROUP_DN); + assertNotNull(adminGroup); + Role[] members = adminGroup.getMembers(); + assertEquals(1, members.length); + assertEquals(rootUser.getName(), members[0].getName()); + } +} diff --git a/org.argeo.security.core/ext/test/org/argeo/osgi/useradmin/test.ldif b/org.argeo.security.core/ext/test/org/argeo/osgi/useradmin/basic.ldif similarity index 100% rename from org.argeo.security.core/ext/test/org/argeo/osgi/useradmin/test.ldif rename to org.argeo.security.core/ext/test/org/argeo/osgi/useradmin/basic.ldif diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/ArgeoUserAdminException.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/ArgeoUserAdminException.java new file mode 100644 index 000000000..70724a743 --- /dev/null +++ b/org.argeo.security.core/src/org/argeo/osgi/useradmin/ArgeoUserAdminException.java @@ -0,0 +1,19 @@ +package org.argeo.osgi.useradmin; + +import org.osgi.service.useradmin.UserAdmin; + +/** + * Exceptions related to Argeo's implementation of OSGi {@link UserAdmin} + * service. + */ +public class ArgeoUserAdminException extends RuntimeException { + private static final long serialVersionUID = 1419352360062048603L; + + public ArgeoUserAdminException(String message) { + super(message); + } + + public ArgeoUserAdminException(String message, Throwable e) { + super(message, e); + } +} diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/AttributeDictionary.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/AttributeDictionary.java new file mode 100644 index 000000000..7691d8a94 --- /dev/null +++ b/org.argeo.security.core/src/org/argeo/osgi/useradmin/AttributeDictionary.java @@ -0,0 +1,73 @@ +package org.argeo.osgi.useradmin; + +import java.util.Dictionary; +import java.util.Enumeration; + +import javax.naming.NamingException; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; +import javax.naming.directory.BasicAttribute; + +class AttributeDictionary extends Dictionary { + private final Attributes attributes; + + public AttributeDictionary(Attributes attributes) { + this.attributes = attributes; + } + + @Override + public int size() { + return attributes.size(); + } + + @Override + public boolean isEmpty() { + return attributes.size() == 0; + } + + @Override + public Enumeration keys() { + return attributes.getIDs(); + } + + @Override + public Enumeration elements() { + throw new UnsupportedOperationException(); + } + + @Override + public Object get(Object key) { + try { + return attributes.get(key.toString()).get(); + } catch (NamingException e) { + throw new ArgeoUserAdminException("Cannot get value for attribute " + + key, e); + } + } + + @Override + public Object put(Object key, Object value) { + if (!(value instanceof String || value instanceof byte[])) + throw new IllegalArgumentException( + "Value muste be String or byte[]"); + try { + Attribute attribute = attributes.get(key.toString()); + attribute = new BasicAttribute(key.toString()); + attribute.add(value); + Attribute previousAttribute = attributes.put(attribute); + if (previousAttribute != null) + return previousAttribute.get(); + else + return null; + } catch (NamingException e) { + throw new ArgeoUserAdminException("Cannot get value for attribute " + + key, e); + } + } + + @Override + public Object remove(Object key) { + throw new UnsupportedOperationException(); + } + +} 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 new file mode 100644 index 000000000..c2c666700 --- /dev/null +++ b/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifGroup.java @@ -0,0 +1,63 @@ +package org.argeo.osgi.useradmin; + +import java.util.ArrayList; +import java.util.List; + +import javax.naming.NamingEnumeration; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; +import javax.naming.ldap.LdapName; + +import org.osgi.service.useradmin.Group; +import org.osgi.service.useradmin.Role; + +public class LdifGroup extends LdifUser implements Group { + + public LdifGroup(LdapName dn, Attributes attributes) { + super(dn, attributes); + } + + @Override + public boolean addMember(Role role) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addRequiredMember(Role role) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeMember(Role role) { + throw new UnsupportedOperationException(); + } + + @Override + public Role[] getMembers() { + Attribute memberAttribute = getAttributes().get("member"); + if (memberAttribute == null) + return new Role[0]; + try { + List roles = new ArrayList(); + NamingEnumeration values = memberAttribute.getAll(); + while (values.hasMore()) { + LdapName dn = new LdapName(values.next().toString()); + roles.add(new LdifUser(dn, null)); + } + return roles.toArray(new Role[roles.size()]); + } catch (Exception e) { + throw new ArgeoUserAdminException("Cannot get members", e); + } + } + + @Override + public Role[] getRequiredMembers() { + throw new UnsupportedOperationException(); + } + + @Override + public int getType() { + return GROUP; + } + +} diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifParser.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifParser.java index 38c37312f..56bdb54e3 100644 --- a/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifParser.java +++ b/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifParser.java @@ -72,8 +72,8 @@ class LdifParser { if (currentDn != null) { Attributes previous = res.put(currentDn, currentAttributes); - if (log.isDebugEnabled()) - log.debug("Added " + currentDn); + if (log.isTraceEnabled()) + log.trace("Added " + currentDn); if (previous != null) { log.warn("There was already an entry with DN " + currentDn diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifUser.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifUser.java new file mode 100644 index 000000000..1de18c5b4 --- /dev/null +++ b/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifUser.java @@ -0,0 +1,59 @@ +package org.argeo.osgi.useradmin; + +import java.util.Dictionary; +import java.util.Hashtable; + +import javax.naming.directory.Attributes; +import javax.naming.ldap.LdapName; + +import org.osgi.service.useradmin.User; +import org.osgi.service.useradmin.UserAdmin; + +class LdifUser implements User { + private final LdapName dn; + private final Attributes attributes; + + LdifUser(LdapName dn, Attributes attributes) { + this.dn = dn; + this.attributes = attributes; + } + + @Override + public String getName() { + return dn.toString(); + } + + @Override + public int getType() { + return USER; + } + + @Override + public Dictionary getProperties() { + if (attributes == null) + throw new ArgeoUserAdminException( + "Must be loaded from user admin service"); + return new AttributeDictionary(attributes); + } + + @Override + public Dictionary getCredentials() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean hasCredential(String key, Object value) { + // TODO Auto-generated method stub + return false; + } + + protected LdapName getDn() { + return dn; + } + + protected Attributes getAttributes() { + return attributes; + } + +} 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 new file mode 100644 index 000000000..5796b46c4 --- /dev/null +++ b/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifUserAdmin.java @@ -0,0 +1,88 @@ +package org.argeo.osgi.useradmin; + +import java.io.InputStream; +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 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 LdifUserAdmin implements UserAdmin { + private SortedMap roles = new TreeMap(); + + public LdifUserAdmin(InputStream in) { + try { + 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(); + objectClasses: while (objectClasses.hasMore()) { + String objectClass = objectClasses.next().toString(); + if (objectClass.equals("inetOrgPerson")) { + roles.put(key, new LdifUser(key, attributes)); + break objectClasses; + } else if (objectClass.equals("groupOfNames")) { + roles.put(key, new LdifGroup(key, attributes)); + break objectClasses; + } + } + } + } catch (Exception e) { + throw new ArgeoUserAdminException( + "Cannot initialise 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); + } + + @Override + public Authorization getAuthorization(User user) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Role createRole(String name, int type) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeRole(String name) { + throw new UnsupportedOperationException(); + } + + @Override + public Role[] getRoles(String filter) throws InvalidSyntaxException { + throw new UnsupportedOperationException(); + } + + @Override + public User getUser(String key, String value) { + throw new UnsupportedOperationException(); + } + +} -- 2.30.2