This change adds validation when running the users tool so that if Elasticsearch is expected to run in a JVM that is configured to be in FIPS 140 mode and the password hashing algorithm is not compliant, we would throw an error. Users tool uses the configuration from the node and this validation would also happen upon node startup but users might be added in the file realm before the node is started and we would have the opportunity to notify the user of this misconfiguration. The changes in #55544 make this much less probable to happen in 8 since the default algorithm will be compliant but this change can act as a fallback in anycase and makes for a better user experience.
This commit is contained in:
parent
38b55f06ba
commit
d56f25acb4
|
@ -439,6 +439,10 @@ public class UsersTool extends LoggingAwareMultiCommand {
|
|||
|
||||
private static char[] getPasswordHash(Terminal terminal, Environment env, String cliPasswordValue) throws UserException {
|
||||
final Hasher hasher = Hasher.resolve(XPackSettings.PASSWORD_HASHING_ALGORITHM.get(env.settings()));
|
||||
if (XPackSettings.FIPS_MODE_ENABLED.get(env.settings()) && hasher.name().toLowerCase(Locale.ROOT).startsWith("pbkdf2") == false) {
|
||||
throw new UserException(ExitCodes.CONFIG, "Only PBKDF2 is allowed for password hashing in a FIPS 140 JVM. Please set the " +
|
||||
"appropriate value for [ " + XPackSettings.PASSWORD_HASHING_ALGORITHM.getKey() + " ] setting.");
|
||||
}
|
||||
final char[] passwordHash;
|
||||
try (SecureString password = parsePassword(terminal, cliPasswordValue)) {
|
||||
passwordHash = hasher.hash(password);
|
||||
|
|
|
@ -70,7 +70,8 @@ public class UsersToolTests extends CommandTestCase {
|
|||
IOUtils.rm(homeDir);
|
||||
confDir = homeDir.resolve("config");
|
||||
Files.createDirectories(confDir);
|
||||
hasher = Hasher.resolve(randomFrom("bcrypt", "pbkdf2"));
|
||||
hasher = inFipsJvm() ? randomFrom(Hasher.PBKDF2, Hasher.PBKDF2_1000)
|
||||
: randomFrom(Hasher.PBKDF2_1000, Hasher.PBKDF2, Hasher.BCRYPT, Hasher.BCRYPT9);
|
||||
String defaultPassword = SecuritySettingsSourceField.TEST_PASSWORD;
|
||||
Files.write(confDir.resolve("users"), Arrays.asList(
|
||||
"existing_user:" + new String(hasher.hash(SecuritySettingsSourceField.TEST_PASSWORD_SECURE_STRING)),
|
||||
|
@ -90,10 +91,11 @@ public class UsersToolTests extends CommandTestCase {
|
|||
" cluster: all"
|
||||
), StandardCharsets.UTF_8);
|
||||
settings =
|
||||
Settings.builder()
|
||||
.put("path.home", homeDir)
|
||||
.put("xpack.security.authc.realms.file.file.order", 0)
|
||||
.build();
|
||||
Settings.builder()
|
||||
.put("path.home", homeDir)
|
||||
.put("xpack.security.authc.realms.file.file.order", 0)
|
||||
.put("xpack.security.authc.password_hashing.algorithm", hasher.name())
|
||||
.build();
|
||||
pathHomeParameter = "-Epath.home=" + homeDir;
|
||||
fileOrderParameter = "-Expack.security.authc.realms.file.file.order=0";
|
||||
}
|
||||
|
@ -174,9 +176,7 @@ public class UsersToolTests extends CommandTestCase {
|
|||
}
|
||||
String gotHash = usernameHash[1];
|
||||
SecureString expectedHash = new SecureString(password.toCharArray());
|
||||
// CommandTestCase#execute runs passwd with default settings, so bcrypt with cost of 10
|
||||
Hasher bcryptHasher = Hasher.resolve("bcrypt");
|
||||
assertTrue("Could not validate password for user", bcryptHasher.verify(expectedHash, gotHash.toCharArray()));
|
||||
assertTrue("Could not validate password for user", hasher.verify(expectedHash, gotHash.toCharArray()));
|
||||
return;
|
||||
}
|
||||
fail("Could not find username " + username + " in users file:\n" + lines.toString());
|
||||
|
@ -363,6 +363,23 @@ public class UsersToolTests extends CommandTestCase {
|
|||
assertTrue(lines.toString(), lines.isEmpty());
|
||||
}
|
||||
|
||||
public void testAddUserWithInvalidHashingAlgorithmInFips() throws Exception {
|
||||
settings =
|
||||
Settings.builder()
|
||||
.put(settings)
|
||||
.put("xpack.security.authc.password_hashing.algorithm", "bcrypt")
|
||||
.put("xpack.security.fips_mode.enabled", true)
|
||||
.build();
|
||||
|
||||
UserException e = expectThrows(UserException.class, () -> {
|
||||
execute("useradd", pathHomeParameter, fileOrderParameter, randomAlphaOfLength(12), "-p",
|
||||
SecuritySettingsSourceField.TEST_PASSWORD);
|
||||
});
|
||||
assertEquals(ExitCodes.CONFIG, e.exitCode);
|
||||
assertEquals("Only PBKDF2 is allowed for password hashing in a FIPS 140 JVM. " +
|
||||
"Please set the appropriate value for [ xpack.security.authc.password_hashing.algorithm ] setting.", e.getMessage());
|
||||
}
|
||||
|
||||
public void testUserdelUnknownUser() throws Exception {
|
||||
UserException e = expectThrows(UserException.class, () -> {
|
||||
execute("userdel", pathHomeParameter, fileOrderParameter, "unknown");
|
||||
|
@ -398,6 +415,21 @@ public class UsersToolTests extends CommandTestCase {
|
|||
assertRole("test_admin", "existing_user"); // roles unchanged
|
||||
}
|
||||
|
||||
public void testPasswdWithInvalidHashingAlgorithmInFips() throws Exception {
|
||||
settings =
|
||||
Settings.builder()
|
||||
.put(settings)
|
||||
.put("xpack.security.authc.password_hashing.algorithm", "bcrypt")
|
||||
.put("xpack.security.fips_mode.enabled", true)
|
||||
.build();
|
||||
UserException e = expectThrows(UserException.class, () -> {
|
||||
execute("passwd", pathHomeParameter, fileOrderParameter, "existing_user", "-p", "newpassword");
|
||||
});
|
||||
assertEquals(ExitCodes.CONFIG, e.exitCode);
|
||||
assertEquals("Only PBKDF2 is allowed for password hashing in a FIPS 140 JVM. " +
|
||||
"Please set the appropriate value for [ xpack.security.authc.password_hashing.algorithm ] setting.", e.getMessage());
|
||||
}
|
||||
|
||||
public void testRolesUnknownUser() throws Exception {
|
||||
UserException e = expectThrows(UserException.class, () -> {
|
||||
execute("roles", pathHomeParameter, fileOrderParameter, "unknown");
|
||||
|
|
Loading…
Reference in New Issue