--- /dev/null
+package org.argeo.osgi.useradmin;
+
+import java.util.SortedMap;
+
+import javax.naming.directory.Attributes;
+import javax.naming.ldap.LdapName;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.digest.DigestUtils;
+
+import junit.framework.TestCase;
+
+public class LdifParserTest extends TestCase {
+ public void testSimpleLdif() throws Exception {
+ LdifParser ldifParser = new LdifParser();
+ SortedMap<LdapName, Attributes> res = ldifParser.read(getClass()
+ .getResourceAsStream("test.ldif"));
+ LdapName rootDn = new LdapName(
+ "uid=root,ou=People,dc=demo,dc=example,dc=org");
+ Attributes rootAttributes = res.get(rootDn);
+ assertNotNull(rootAttributes);
+ assertEquals("Superuser", rootAttributes.get("description").get());
+ byte[] rawPwEntry = (byte[]) rootAttributes.get("userpassword").get();
+ assertEquals("{SHA}ieSV55Qc+eQOaYDRSha/AjzNTJE=",
+ new String(rawPwEntry));
+ byte[] hashedPassword = DigestUtils.sha1("demo".getBytes());
+ assertEquals("{SHA}" + Base64.encodeBase64String(hashedPassword),
+ new String(rawPwEntry));
+
+ }
+}
--- /dev/null
+dn: dc=demo,dc=example,dc=org
+objectClass: domain
+objectClass: extensibleObject
+objectClass: top
+dc: demo
+
+dn: ou=Roles,dc=demo,dc=example,dc=org
+objectClass: organizationalUnit
+objectClass: top
+ou: Roles
+
+dn: ou=People,dc=demo,dc=example,dc=org
+objectClass: organizationalUnit
+objectClass: top
+ou: People
+
+dn: uid=demo,ou=People,dc=demo,dc=example,dc=org
+objectClass: organizationalPerson
+objectClass: person
+objectClass: inetOrgPerson
+objectClass: top
+cn: demo User
+description: Demo user
+givenname: Demo
+mail: demo@localhost
+sn: User
+uid: demo
+userpassword:: e1NIQX1pZVNWNTVRYytlUU9hWURSU2hhL0Fqek5USkU9
+
+dn: uid=root,ou=People,dc=demo,dc=example,dc=org
+objectClass: person
+objectClass: inetOrgPerson
+objectClass: organizationalPerson
+objectClass: top
+cn: demo User
+description: Superuser
+givenname: Root
+mail: root@localhost
+sn: Root
+uid: root
+userpassword:: e1NIQX1pZVNWNTVRYytlUU9hWURSU2hhL0Fqek5USkU9
+
+dn: cn=admin,ou=Roles,dc=demo,dc=example,dc=org
+objectClass: groupOfNames
+objectClass: top
+cn: admin
+member: uid=root,ou=People,dc=demo,dc=example,dc=org
--- /dev/null
+package org.argeo.osgi.useradmin;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import javax.naming.InvalidNameException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.ldap.LdapName;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/** Basic LDIF parser. */
+class LdifParser {
+ private final static Log log = LogFactory.getLog(LdifParser.class);
+
+ SortedMap<LdapName, Attributes> read(InputStream in) throws IOException {
+ SortedMap<LdapName, Attributes> res = new TreeMap<LdapName, Attributes>();
+ try {
+ List<String> lines = IOUtils.readLines(in);
+
+ LdapName currentDn = null;
+ Attributes currentAttributes = null;
+ StringBuilder currentEntry = new StringBuilder();
+
+ readLines: for (String line : lines) {
+ if (line.startsWith(" ")) {
+ currentEntry.append(line.substring(1));
+ continue readLines;
+ } else {
+ if (currentEntry.length() != 0) {
+ // read previous attribute
+ StringBuilder attrId = new StringBuilder(8);
+ boolean isBase64 = false;
+ readAttrId: for (int i = 0; i < currentEntry.length(); i++) {
+ char c = currentEntry.charAt(i);
+ if (c == ':') {
+ if (i + 1 < currentEntry.length()
+ && currentEntry.charAt(i + 1) == ':')
+ isBase64 = true;
+ currentEntry.delete(0, i + (isBase64 ? 2 : 1));
+ break readAttrId;
+ } else {
+ attrId.append(c);
+ }
+ }
+
+ String attributeId = attrId.toString();
+ String cleanValueStr = currentEntry.toString().trim();
+ Object attributeValue = isBase64 ? Base64
+ .decodeBase64(cleanValueStr) : cleanValueStr;
+
+ // manage DN attributes
+ if (attributeId.equals("dn")) {
+ if (currentDn != null) {
+ Attributes previous = res.put(currentDn,
+ currentAttributes);
+ if (previous != null) {
+ log.warn("There was already an entry with DN "
+ + currentDn
+ + ", which has been discarded by a subsequent one.");
+ }
+ }
+
+ try {
+ currentDn = new LdapName(
+ attributeValue.toString());
+ currentAttributes = new BasicAttributes();
+ } catch (InvalidNameException e) {
+ log.error(attributeValue
+ + " not a valid DN, skipping the entry.");
+ currentDn = null;
+ currentAttributes = null;
+ }
+ }
+
+ // store attribute
+ if (currentAttributes != null) {
+ Attribute attribute = currentAttributes
+ .get(attributeId);
+ if (attribute == null) {
+ attribute = new BasicAttribute(attributeId);
+ currentAttributes.put(attribute);
+ }
+ attribute.add(attributeValue);
+ }
+ currentEntry = new StringBuilder();
+ }
+ currentEntry.append(line);
+ }
+ }
+ } finally {
+ IOUtils.closeQuietly(in);
+ }
+ return res;
+ }
+}
\ No newline at end of file