diff --git a/src/main/java/org/elasticsearch/shield/authc/support/Hasher.java b/src/main/java/org/elasticsearch/shield/authc/support/Hasher.java index 4090ad8cdc2..19b112cda18 100644 --- a/src/main/java/org/elasticsearch/shield/authc/support/Hasher.java +++ b/src/main/java/org/elasticsearch/shield/authc/support/Hasher.java @@ -9,6 +9,7 @@ import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.digest.Crypt; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.Md5Crypt; +import org.apache.commons.codec.digest.Sha2Crypt; import org.elasticsearch.ElasticsearchIllegalArgumentException; import org.elasticsearch.common.os.OsUtils; @@ -34,9 +35,6 @@ public enum Hasher { @Override public boolean verify(SecuredString text, char[] hash) { String hashStr = new String(hash); - if (hashStr.startsWith(BCRYPT_PREFIX_Y)) { - hashStr = BCRYPT_PREFIX + hashStr.substring(BCRYPT_PREFIX_Y.length()); - } if (hashStr.startsWith(BCRYPT_PREFIX)) { return BCrypt.checkpw(text, hashStr); } @@ -52,16 +50,94 @@ public enum Hasher { String passwd64 = Base64.encodeBase64String(DigestUtils.sha1(textBytes)); return hashStr.substring(SHA1_PREFIX.length()).compareTo(passwd64) == 0; } + if (hashStr.startsWith(SHA2_PREFIX_5) || hashStr.startsWith(SHA2_PREFIX_6)) { + return hashStr.compareTo(Sha2Crypt.sha256Crypt(textBytes, hashStr)) == 0; + } return CRYPT_SUPPORTED ? - hashStr.compareTo(Crypt.crypt(textBytes, hashStr)) == 0 : // crypt algo - text.equals(hashStr); // plain text + hashStr.compareTo(Crypt.crypt(textBytes, hashStr)) == 0 : // crypt algo + text.equals(hashStr); // plain text + } + }, + + + BCRYPT() { + @Override + public char[] hash(SecuredString text) { + String salt = org.elasticsearch.shield.authc.support.BCrypt.gensalt(); + return BCrypt.hashpw(text, salt).toCharArray(); + } + + @Override + public boolean verify(SecuredString text, char[] hash) { + String hashStr = new String(hash); + if (!hashStr.startsWith(BCRYPT_PREFIX)) { + return false; + } + return BCrypt.checkpw(text, hashStr); + } + }, + + MD5() { + @Override + public char[] hash(SecuredString text) { + byte[] textBytes = CharArrays.toUtf8Bytes(text.internalChars()); + return Md5Crypt.apr1Crypt(textBytes).toCharArray(); + } + + @Override + public boolean verify(SecuredString text, char[] hash) { + String hashStr = new String(hash); + if (!hashStr.startsWith(APR1_PREFIX)) { + return false; + } + byte[] textBytes = CharArrays.toUtf8Bytes(text.internalChars()); + return hashStr.compareTo(Md5Crypt.apr1Crypt(textBytes, hashStr)) == 0; + } + }, + + SHA1() { + @Override + public char[] hash(SecuredString text) { + byte[] textBytes = CharArrays.toUtf8Bytes(text.internalChars()); + String hash = Base64.encodeBase64String(DigestUtils.sha1(textBytes)); + return (SHA1_PREFIX + hash).toCharArray(); + } + + @Override + public boolean verify(SecuredString text, char[] hash) { + String hashStr = new String(hash); + if (!hashStr.startsWith(SHA1_PREFIX)) { + return false; + } + byte[] textBytes = CharArrays.toUtf8Bytes(text.internalChars()); + String passwd64 = Base64.encodeBase64String(DigestUtils.sha1(textBytes)); + return hashStr.substring(SHA1_PREFIX.length()).compareTo(passwd64) == 0; + } + }, + + SHA2() { + @Override + public char[] hash(SecuredString text) { + byte[] textBytes = CharArrays.toUtf8Bytes(text.internalChars()); + return Sha2Crypt.sha256Crypt(textBytes).toCharArray(); + } + + @Override + public boolean verify(SecuredString text, char[] hash) { + String hashStr = new String(hash); + if (hashStr.startsWith(SHA2_PREFIX_5) || hashStr.startsWith(SHA2_PREFIX_6)) { + byte[] textBytes = CharArrays.toUtf8Bytes(text.internalChars()); + return hashStr.compareTo(Sha2Crypt.sha256Crypt(textBytes, hashStr)) == 0; + } + return false; } }; private static final String APR1_PREFIX = "$apr1$"; private static final String BCRYPT_PREFIX = "$2a$"; - private static final String BCRYPT_PREFIX_Y = "$2y$"; private static final String SHA1_PREFIX = "{SHA}"; + private static final String SHA2_PREFIX_5 = "$5$"; + private static final String SHA2_PREFIX_6 = "$6$"; private static final String PLAIN_PREFIX = "{plain}"; static final boolean CRYPT_SUPPORTED = !OsUtils.WINDOWS; diff --git a/src/test/java/org/elasticsearch/shield/authc/esusers/FileUserPasswdStoreTests.java b/src/test/java/org/elasticsearch/shield/authc/esusers/FileUserPasswdStoreTests.java index 1545c5c9f2d..00fdd6abe01 100644 --- a/src/test/java/org/elasticsearch/shield/authc/esusers/FileUserPasswdStoreTests.java +++ b/src/test/java/org/elasticsearch/shield/authc/esusers/FileUserPasswdStoreTests.java @@ -48,7 +48,7 @@ public class FileUserPasswdStoreTests extends ElasticsearchTestCase { assertThat(users, notNullValue()); assertThat(users.size(), is(6)); assertThat(users.get("bcrypt"), notNullValue()); - assertThat(new String(users.get("bcrypt")), equalTo("$2y$05$zxnP0vdREMxnEpkLCDI2OuSaSk/QEKA2.A42iOpI6U2u.RLLOWm1e")); + assertThat(new String(users.get("bcrypt")), equalTo("$2a$05$zxnP0vdREMxnEpkLCDI2OuSaSk/QEKA2.A42iOpI6U2u.RLLOWm1e")); assertThat(users.get("bcrypt10"), notNullValue()); assertThat(new String(users.get("bcrypt10")), equalTo("$2y$10$FMhmFjwU5.qxQ/BsEciS9OqcJVkFMgXMo4uH5CelOR1j4N9zIv67e")); assertThat(users.get("md5"), notNullValue()); diff --git a/src/test/java/org/elasticsearch/shield/authc/support/HasherTests.java b/src/test/java/org/elasticsearch/shield/authc/support/HasherTests.java index 7a3f626047d..4365a514031 100644 --- a/src/test/java/org/elasticsearch/shield/authc/support/HasherTests.java +++ b/src/test/java/org/elasticsearch/shield/authc/support/HasherTests.java @@ -5,7 +5,6 @@ */ package org.elasticsearch.shield.authc.support; -import org.elasticsearch.common.os.OsUtils; import org.elasticsearch.test.ElasticsearchTestCase; import org.junit.Test; @@ -15,11 +14,11 @@ import org.junit.Test; public class HasherTests extends ElasticsearchTestCase { @Test - public void testHtpasswdToolGenerated() throws Exception { + public void testHtpasswd_ToolGenerated() throws Exception { Hasher hasher = Hasher.HTPASSWD; SecuredString passwd = SecuredStringTests.build("test123"); assertTrue(hasher.verify(passwd, "$2a$05$zxnP0vdREMxnEpkLCDI2OuSaSk/QEKA2.A42iOpI6U2u.RLLOWm1e".toCharArray())); - assertTrue(hasher.verify(passwd, "$2a$10$FMhmFjwU5.qxQ/BsEciS9OqcJVkFMgXMo4uH5CelOR1j4N9zIv67e".toCharArray())); + assertTrue(hasher.verify(passwd, "$2a$10$vNMk6GyVUU./7YSZB6BGPuozm921GVPw/Pdukzd09s.sL2rIWROU6".toCharArray())); assertTrue(hasher.verify(passwd, "$apr1$R3DdqiAZ$aljIkaIVPSarmDMlJUBBP.".toCharArray())); if (!Hasher.CRYPT_SUPPORTED) { assertTrue(hasher.verify(passwd, "test123".toCharArray())); @@ -28,12 +27,37 @@ public class HasherTests extends ElasticsearchTestCase { } assertTrue(hasher.verify(passwd, "{plain}test123".toCharArray())); assertTrue(hasher.verify(passwd, "{SHA}cojt0Pw//L6ToM8G41aOKFIWh7w=".toCharArray())); + assertTrue(hasher.verify(passwd, "$5$RsqcsPiF$51tIIXf6oZb3Awox6FWNhITVlM/aW3oa8uN2eptIf54".toCharArray())); } @Test - public void testHtpasswdSelfGenerated() throws Exception { - Hasher hasher = Hasher.HTPASSWD; + public void testHtpasswd_SelfGenerated() throws Exception { + testHasherSelfGenerated(Hasher.HTPASSWD); + } + + @Test + public void testBcrypt_SelfGenerated() throws Exception { + testHasherSelfGenerated(Hasher.BCRYPT); + } + + @Test + public void testMd5_SelfGenerated() throws Exception { + testHasherSelfGenerated(Hasher.MD5); + } + + @Test + public void testSha1_SelfGenerated() throws Exception { + testHasherSelfGenerated(Hasher.SHA1); + } + + @Test + public void testSha2_SelfGenerated() throws Exception { + testHasherSelfGenerated(Hasher.SHA2); + } + + public void testHasherSelfGenerated(Hasher hasher) throws Exception { SecuredString passwd = SecuredStringTests.build("test123"); assertTrue(hasher.verify(passwd, hasher.hash(passwd))); } + } diff --git a/src/test/resources/org/elasticsearch/shield/authc/esusers/users b/src/test/resources/org/elasticsearch/shield/authc/esusers/users index 51469265909..df132ed1344 100644 --- a/src/test/resources/org/elasticsearch/shield/authc/esusers/users +++ b/src/test/resources/org/elasticsearch/shield/authc/esusers/users @@ -1,4 +1,4 @@ -bcrypt: $2y$05$zxnP0vdREMxnEpkLCDI2OuSaSk/QEKA2.A42iOpI6U2u.RLLOWm1e +bcrypt: $2a$05$zxnP0vdREMxnEpkLCDI2OuSaSk/QEKA2.A42iOpI6U2u.RLLOWm1e md5: $apr1$R3DdqiAZ$aljIkaIVPSarmDMlJUBBP. crypt: hsP1PYSLsEEvs plain: {plain}test123