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=712ccdfde9eb4848b1ea5477b41542b938b75f0a;hpb=2968380c9c58aa858aa8f5dcb02b61a85c8ae149;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 712ccdfde..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,8 +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; @@ -64,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; @@ -76,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; @@ -227,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();