diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/RealmSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/RealmSettings.java index 0c35525f1de..6ab511df90e 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/RealmSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/RealmSettings.java @@ -10,6 +10,7 @@ import org.elasticsearch.common.settings.SecureSetting; import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.settings.SettingsException; import java.util.Arrays; import java.util.List; @@ -91,12 +92,31 @@ public class RealmSettings { return settingsByName.names().stream().map(name -> { final RealmConfig.RealmIdentifier id = new RealmConfig.RealmIdentifier(type, name); final Settings realmSettings = settingsByName.getAsSettings(name); + verifyRealmSettings(id, realmSettings); return new Tuple<>(id, realmSettings); }); }) .collect(Collectors.toMap(Tuple::v1, Tuple::v2)); } + /** + * Performs any necessary verifications on a realms settings that are not automatically applied by Settings validation infrastructure. + */ + private static void verifyRealmSettings(RealmConfig.RealmIdentifier identifier, Settings realmSettings) { + final Settings nonSecureSettings = Settings.builder().put(realmSettings, false).build(); + if (nonSecureSettings.isEmpty()) { + final String prefix = realmSettingPrefix(identifier); + throw new SettingsException( + "found settings for the realm [{}] (with type [{}]) in the secure settings (elasticsearch.keystore)," + + " but this realm does not have any settings in elasticsearch.yml." + + " Please remove these settings from the keystore, or update their names to match one of the realms that are" + + " defined in elasticsearch.yml - [{}]", + identifier.getName(), identifier.getType(), + realmSettings.keySet().stream().map(k -> prefix + k).collect(Collectors.joining(",")) + ); + } + } + public static String getFullSettingKey(String realmName, Setting.AffixSetting setting) { return setting.getConcreteSettingForNamespace(realmName).getKey(); } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/RealmSettingsTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/RealmSettingsTests.java index eb33408f338..6061469d700 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/RealmSettingsTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/RealmSettingsTests.java @@ -10,12 +10,16 @@ import org.elasticsearch.common.settings.MockSecureSettings; import org.elasticsearch.common.settings.SecureSettings; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.settings.SettingsException; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.SecuritySettingsSource; import org.elasticsearch.xpack.core.XPackSettings; import org.elasticsearch.xpack.core.security.authc.InternalRealmsSettings; +import org.elasticsearch.xpack.core.security.authc.RealmConfig; import org.elasticsearch.xpack.core.security.authc.RealmSettings; +import org.elasticsearch.xpack.core.security.authc.ldap.PoolingSessionFactorySettings; import org.elasticsearch.xpack.core.security.authc.support.Hasher; +import org.hamcrest.Matchers; import java.util.Collections; import java.util.HashSet; @@ -23,7 +27,6 @@ import java.util.List; import java.util.Set; import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.notNullValue; public class RealmSettingsTests extends ESTestCase { private static final List CACHE_HASHING_ALGOS = Hasher.getAvailableAlgoCacheHash(); @@ -87,6 +90,21 @@ public class RealmSettingsTests extends ESTestCase { assertSuccess(settings); } + public void testSettingsWithKeystoreOnlyRealmDoesNotValidate() throws Exception { + final String securePasswordKey = RealmSettings.getFullSettingKey( + new RealmConfig.RealmIdentifier("ldap", "ldap_1"), PoolingSessionFactorySettings.SECURE_BIND_PASSWORD); + final Settings.Builder builder = Settings.builder() + .put(ldapRealm("ldap-1", randomBoolean(), randomBoolean()).build()); + SecuritySettingsSource.addSecureSettings(builder, secureSettings -> { + secureSettings.setString(securePasswordKey, "secret-password"); + }); + final Settings settings = builder.build(); + final SettingsException exception = expectThrows(SettingsException.class, () -> RealmSettings.getRealmSettings(settings)); + assertThat(exception.getMessage(), containsString("elasticsearch.keystore")); + assertThat(exception.getMessage(), containsString("elasticsearch.yml")); + assertThat(exception.getMessage(), containsString(securePasswordKey)); + } + private Settings.Builder nativeRealm(String name) { return realm("native", name, nativeSettings()); } @@ -277,12 +295,7 @@ public class RealmSettingsTests extends ESTestCase { } catch (RuntimeException e) { fail("Settings do not validate: " + e); } - } - - private void assertErrorWithCause(String realmType, String realmName, String message, Settings settings) { - final IllegalArgumentException exception = assertError(realmType, realmName, settings); - assertThat(exception.getCause(), notNullValue()); - assertThat(exception.getCause().getMessage(), containsString(message)); + assertThat(RealmSettings.getRealmSettings(settings), Matchers.not(Matchers.anEmptyMap())); } private void assertErrorWithMessage(String realmType, String realmName, String message, Settings settings) {