X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;f=org.argeo.security.core%2Fsrc%2Forg%2Fargeo%2Fosgi%2Fuseradmin%2FLdifUser.java;h=4f0a56a6075ac7e3b6dbfb120984bc49c61b1e22;hb=563ee18b53fa90f14dc3f443f29f6d020ffdee2b;hp=cd5401a55794273ffd350c9e341d025d4bd6425c;hpb=25071ab6bcb2df1fa4057c2c04137f2d606772e7;p=lgpl%2Fargeo-commons.git 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 index cd5401a55..4f0a56a60 100644 --- a/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifUser.java +++ b/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifUser.java @@ -1,5 +1,8 @@ package org.argeo.osgi.useradmin; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -15,6 +18,11 @@ import javax.naming.directory.Attributes; import javax.naming.directory.BasicAttribute; import javax.naming.ldap.LdapName; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.codec.digest.DigestUtils; +import org.argeo.osgi.useradmin.AbstractUserDirectory.WorkingCopy; + +/** Directory user implementation */ class LdifUser implements DirectoryUser { private final AbstractUserDirectory userAdmin; @@ -22,7 +30,6 @@ class LdifUser implements DirectoryUser { private final boolean frozen; private Attributes publishedAttributes; - private Attributes modifiedAttributes = null; private final AttributeDictionary properties; private final AttributeDictionary credentials; @@ -63,6 +70,13 @@ class LdifUser implements DirectoryUser { @Override public boolean hasCredential(String key, Object value) { + if (key == null) { + // TODO check other sources (like PKCS12) + char[] password = toChars(value); + byte[] hashedPassword = hash(password); + return hasCredential(LdifName.userpassword.name(), hashedPassword); + } + Object storedValue = getCredentials().get(key); if (storedValue == null || value == null) return false; @@ -75,6 +89,41 @@ class LdifUser implements DirectoryUser { return false; } + /** Hash and clear the password */ + private byte[] hash(char[] password) { + byte[] hashedPassword = ("{SHA}" + Base64 + .encodeBase64String(DigestUtils.sha1(toBytes(password)))) + .getBytes(); + Arrays.fill(password, '\u0000'); + return hashedPassword; + } + + private byte[] toBytes(char[] chars) { + CharBuffer charBuffer = CharBuffer.wrap(chars); + ByteBuffer byteBuffer = Charset.forName("UTF-8").encode(charBuffer); + byte[] bytes = Arrays.copyOfRange(byteBuffer.array(), + byteBuffer.position(), byteBuffer.limit()); + Arrays.fill(charBuffer.array(), '\u0000'); // clear sensitive data + Arrays.fill(byteBuffer.array(), (byte) 0); // clear sensitive data + return bytes; + } + + private char[] toChars(Object obj) { + if (obj instanceof char[]) + return (char[]) obj; + if (!(obj instanceof byte[])) + throw new IllegalArgumentException(obj.getClass() + + " is not a byte array"); + ByteBuffer fromBuffer = ByteBuffer.wrap((byte[]) obj); + CharBuffer toBuffer = Charset.forName("UTF-8").decode(fromBuffer); + char[] res = Arrays.copyOfRange(toBuffer.array(), toBuffer.position(), + toBuffer.limit()); + Arrays.fill(fromBuffer.array(), (byte) 0); // clear sensitive data + Arrays.fill((byte[]) obj, (byte) 0); // clear sensitive data + Arrays.fill(toBuffer.array(), '\u0000'); // clear sensitive data + return res; + } + @Override public LdapName getDn() { return dn; @@ -82,11 +131,21 @@ class LdifUser implements DirectoryUser { @Override public synchronized Attributes getAttributes() { - return isEditing() ? modifiedAttributes : publishedAttributes; + return isEditing() ? getModifiedAttributes() : publishedAttributes; + } + + /** Should only be called from working copy thread. */ + private synchronized Attributes getModifiedAttributes() { + assert getWc() != null; + return getWc().getAttributes(getDn()); } protected synchronized boolean isEditing() { - return userAdmin.isEditing() && modifiedAttributes != null; + return getWc() != null && getModifiedAttributes() != null; + } + + private synchronized WorkingCopy getWc() { + return userAdmin.getWorkingCopy(); } protected synchronized void startEditing() { @@ -94,17 +153,22 @@ class LdifUser implements DirectoryUser { throw new UserDirectoryException("Cannot edit frozen view"); if (getUserAdmin().isReadOnly()) throw new UserDirectoryException("User directory is read-only"); - assert modifiedAttributes == null; - modifiedAttributes = (Attributes) publishedAttributes.clone(); + assert getModifiedAttributes() == null; + getWc().startEditing(this); + // modifiedAttributes = (Attributes) publishedAttributes.clone(); } - protected synchronized void stopEditing(boolean apply) { - assert modifiedAttributes != null; - if (apply) - publishedAttributes = modifiedAttributes; - modifiedAttributes = null; + public synchronized void publishAttributes(Attributes modifiedAttributes) { + publishedAttributes = modifiedAttributes; } + // protected synchronized void stopEditing(boolean apply) { + // assert getModifiedAttributes() != null; + // if (apply) + // publishedAttributes = getModifiedAttributes(); + // // modifiedAttributes = null; + // } + public DirectoryUser getPublished() { return new LdifUser(userAdmin, dn, publishedAttributes, true); } @@ -211,6 +275,13 @@ class LdifUser implements DirectoryUser { @Override public Object put(String key, Object value) { + if (key == null) { + // TODO persist to other sources (like PKCS12) + char[] password = toChars(value); + byte[] hashedPassword = hash(password); + return put(LdifName.userpassword.name(), hashedPassword); + } + userAdmin.checkEdit(); if (!isEditing()) startEditing(); @@ -226,10 +297,12 @@ class LdifUser implements DirectoryUser { throw new IllegalArgumentException("Key " + key + " excluded"); try { - Attribute attribute = modifiedAttributes.get(key.toString()); + Attribute attribute = getModifiedAttributes().get( + key.toString()); attribute = new BasicAttribute(key.toString()); attribute.add(value); - Attribute previousAttribute = modifiedAttributes.put(attribute); + Attribute previousAttribute = getModifiedAttributes().put( + attribute); if (previousAttribute != null) return previousAttribute.get(); else @@ -253,7 +326,7 @@ class LdifUser implements DirectoryUser { throw new IllegalArgumentException("Key " + key + " excluded"); try { - Attribute attr = modifiedAttributes.remove(key.toString()); + Attribute attr = getModifiedAttributes().remove(key.toString()); if (attr != null) return attr.get(); else