From b8597a6182d6047d50b44fb7cfc746869b374d14 Mon Sep 17 00:00:00 2001 From: Dan Hermann Date: Tue, 29 Oct 2019 06:44:28 -0500 Subject: [PATCH] Validate monitoring username at parse time (#47821) --- .../exporter/http/HttpExporter.java | 42 ++++++++++++++++++- .../exporter/http/HttpExporterTests.java | 22 ++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/exporter/http/HttpExporter.java b/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/exporter/http/HttpExporter.java index 68a12aeed7849..69ad6b9141598 100644 --- a/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/exporter/http/HttpExporter.java +++ b/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/exporter/http/HttpExporter.java @@ -176,7 +176,47 @@ public Iterator> settings() { */ public static final Setting.AffixSetting AUTH_USERNAME_SETTING = Setting.affixKeySetting("xpack.monitoring.exporters.","auth.username", - (key) -> Setting.simpleString(key, Property.Dynamic, Property.NodeScope, Property.Filtered)); + (key) -> Setting.simpleString( + key, + new Setting.Validator() { + @Override + public void validate(String password) { + // no username validation that is independent of other settings + } + + @Override + public void validate(String username, Map, Object> settings) { + final String namespace = + HttpExporter.AUTH_USERNAME_SETTING.getNamespace( + HttpExporter.AUTH_USERNAME_SETTING.getConcreteSetting(key)); + final String password = + (String) settings.get(AUTH_PASSWORD_SETTING.getConcreteSettingForNamespace(namespace)); + + // password must be specified along with username for any auth + if (Strings.isNullOrEmpty(username) == false) { + if (Strings.isNullOrEmpty(password)) { + throw new SettingsException( + "[" + AUTH_USERNAME_SETTING.getConcreteSettingForNamespace(namespace).getKey() + "] is set " + + "but [" + AUTH_PASSWORD_SETTING.getConcreteSettingForNamespace(namespace).getKey() + "] is " + + "missing"); + } + } + } + + @Override + public Iterator> settings() { + final String namespace = + HttpExporter.AUTH_USERNAME_SETTING.getNamespace( + HttpExporter.AUTH_USERNAME_SETTING.getConcreteSetting(key)); + final List> settings = List.of( + HttpExporter.AUTH_PASSWORD_SETTING.getConcreteSettingForNamespace(namespace)); + return settings.iterator(); + } + + }, + Property.Dynamic, + Property.NodeScope, + Property.Filtered)); /** * Password for basic auth. */ diff --git a/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/exporter/http/HttpExporterTests.java b/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/exporter/http/HttpExporterTests.java index cd1a8ee16a479..24d2fc0d47e7a 100644 --- a/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/exporter/http/HttpExporterTests.java +++ b/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/exporter/http/HttpExporterTests.java @@ -239,6 +239,28 @@ public void testExporterWithPasswordButNoUsername() { assertThat(exception.getMessage(), equalTo(expected)); } + public void testExporterWithUsernameButNoPassword() { + final String expected = + "[xpack.monitoring.exporters._http.auth.username] is set but [xpack.monitoring.exporters._http.auth.password] is missing"; + final String prefix = "xpack.monitoring.exporters._http"; + final Settings settings = Settings.builder() + .put(prefix + ".type", HttpExporter.TYPE) + .put(prefix + ".host", "localhost:9200") + .put(prefix + ".auth.username", "_user") + .build(); + + final IllegalArgumentException e = expectThrows( + IllegalArgumentException.class, + () -> HttpExporter.AUTH_USERNAME_SETTING.getConcreteSetting(prefix + ".auth.username").get(settings)); + assertThat( + e, + hasToString( + containsString("Failed to parse value for setting [xpack.monitoring.exporters._http.auth.username]"))); + + assertThat(e.getCause(), instanceOf(SettingsException.class)); + assertThat(e.getCause(), hasToString(containsString(expected))); + } + public void testExporterWithUnknownBlacklistedClusterAlerts() { final SSLIOSessionStrategy sslStrategy = mock(SSLIOSessionStrategy.class); when(sslService.sslIOSessionStrategy(any(Settings.class))).thenReturn(sslStrategy);