diff --git a/common/build.gradle b/common/build.gradle index d27e213db1..942ce75df4 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -41,6 +41,7 @@ dependencies { implementation 'com.github.babbel:okhttp-aws-signer:1.0.2' api group: 'com.amazonaws', name: 'aws-java-sdk-core', version: '1.12.1' api group: 'com.amazonaws', name: 'aws-java-sdk-sts', version: '1.12.1' + implementation "com.github.seancfoley:ipaddress:5.3.3" testImplementation group: 'junit', name: 'junit', version: '4.13.2' testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.9.1' diff --git a/common/src/main/java/org/opensearch/sql/common/authinterceptors/AwsSigningInterceptor.java b/common/src/main/java/org/opensearch/sql/common/interceptors/AwsSigningInterceptor.java similarity index 97% rename from common/src/main/java/org/opensearch/sql/common/authinterceptors/AwsSigningInterceptor.java rename to common/src/main/java/org/opensearch/sql/common/interceptors/AwsSigningInterceptor.java index e2d33dca8b..16196544b5 100644 --- a/common/src/main/java/org/opensearch/sql/common/authinterceptors/AwsSigningInterceptor.java +++ b/common/src/main/java/org/opensearch/sql/common/interceptors/AwsSigningInterceptor.java @@ -5,7 +5,7 @@ * */ -package org.opensearch.sql.common.authinterceptors; +package org.opensearch.sql.common.interceptors; import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.AWSCredentialsProvider; diff --git a/common/src/main/java/org/opensearch/sql/common/authinterceptors/BasicAuthenticationInterceptor.java b/common/src/main/java/org/opensearch/sql/common/interceptors/BasicAuthenticationInterceptor.java similarity index 93% rename from common/src/main/java/org/opensearch/sql/common/authinterceptors/BasicAuthenticationInterceptor.java rename to common/src/main/java/org/opensearch/sql/common/interceptors/BasicAuthenticationInterceptor.java index 2275482e30..15e9a0fc12 100644 --- a/common/src/main/java/org/opensearch/sql/common/authinterceptors/BasicAuthenticationInterceptor.java +++ b/common/src/main/java/org/opensearch/sql/common/interceptors/BasicAuthenticationInterceptor.java @@ -5,7 +5,7 @@ * */ -package org.opensearch.sql.common.authinterceptors; +package org.opensearch.sql.common.interceptors; import java.io.IOException; import lombok.NonNull; diff --git a/common/src/main/java/org/opensearch/sql/common/interceptors/URIValidatorInterceptor.java b/common/src/main/java/org/opensearch/sql/common/interceptors/URIValidatorInterceptor.java new file mode 100644 index 0000000000..68e7339beb --- /dev/null +++ b/common/src/main/java/org/opensearch/sql/common/interceptors/URIValidatorInterceptor.java @@ -0,0 +1,43 @@ +/* + * + * * Copyright OpenSearch Contributors + * * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.opensearch.sql.common.interceptors; + +import java.io.IOException; +import java.util.List; +import lombok.NonNull; +import okhttp3.Interceptor; +import okhttp3.Request; +import okhttp3.Response; +import org.jetbrains.annotations.NotNull; +import org.opensearch.sql.common.setting.Settings; +import org.opensearch.sql.common.utils.URIValidationUtils; + +public class URIValidatorInterceptor implements Interceptor { + + private final List denyHostList; + + public URIValidatorInterceptor(@NonNull List denyHostList) { + this.denyHostList = denyHostList; + } + + @NotNull + @Override + public Response intercept(Interceptor.Chain chain) throws IOException { + Request request = chain.request(); + String host = request.url().host(); + boolean isValidHost = URIValidationUtils.validateURIHost(host, denyHostList); + if (isValidHost) { + return chain.proceed(request); + } else { + throw new IllegalArgumentException( + String.format( + "Disallowed hostname in the uri. Validate with %s config", + Settings.Key.DATASOURCES_URI_HOSTS_DENY_LIST.getKeyValue())); + } + } +} diff --git a/common/src/main/java/org/opensearch/sql/common/setting/Settings.java b/common/src/main/java/org/opensearch/sql/common/setting/Settings.java index 1e5243f91f..be780e8d80 100644 --- a/common/src/main/java/org/opensearch/sql/common/setting/Settings.java +++ b/common/src/main/java/org/opensearch/sql/common/setting/Settings.java @@ -31,7 +31,7 @@ public enum Key { QUERY_MEMORY_LIMIT("plugins.query.memory_limit"), QUERY_SIZE_LIMIT("plugins.query.size_limit"), ENCYRPTION_MASTER_KEY("plugins.query.datasources.encryption.masterkey"), - DATASOURCES_URI_ALLOWHOSTS("plugins.query.datasources.uri.allowhosts"), + DATASOURCES_URI_HOSTS_DENY_LIST("plugins.query.datasources.uri.hosts.denylist"), METRICS_ROLLING_WINDOW("plugins.query.metrics.rolling_window"), METRICS_ROLLING_INTERVAL("plugins.query.metrics.rolling_interval"), diff --git a/common/src/main/java/org/opensearch/sql/common/utils/URIValidationUtils.java b/common/src/main/java/org/opensearch/sql/common/utils/URIValidationUtils.java new file mode 100644 index 0000000000..c7893fc053 --- /dev/null +++ b/common/src/main/java/org/opensearch/sql/common/utils/URIValidationUtils.java @@ -0,0 +1,22 @@ +package org.opensearch.sql.common.utils; + +import inet.ipaddr.IPAddressString; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.List; + +/** Utility Class for URI host validation. */ +public class URIValidationUtils { + + public static boolean validateURIHost(String host, List denyHostList) + throws UnknownHostException { + IPAddressString ipStr = new IPAddressString(InetAddress.getByName(host).getHostAddress()); + for (String denyHost : denyHostList) { + IPAddressString denyHostStr = new IPAddressString(denyHost); + if (denyHostStr.contains(ipStr)) { + return false; + } + } + return true; + } +} diff --git a/common/src/test/java/org/opensearch/sql/common/authinterceptors/AwsSigningInterceptorTest.java b/common/src/test/java/org/opensearch/sql/common/interceptors/AwsSigningInterceptorTest.java similarity index 98% rename from common/src/test/java/org/opensearch/sql/common/authinterceptors/AwsSigningInterceptorTest.java rename to common/src/test/java/org/opensearch/sql/common/interceptors/AwsSigningInterceptorTest.java index 435ac9dc93..6c5d1bac89 100644 --- a/common/src/test/java/org/opensearch/sql/common/authinterceptors/AwsSigningInterceptorTest.java +++ b/common/src/test/java/org/opensearch/sql/common/interceptors/AwsSigningInterceptorTest.java @@ -5,7 +5,7 @@ * */ -package org.opensearch.sql.common.authinterceptors; +package org.opensearch.sql.common.interceptors; import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.auth.AWSSessionCredentials; diff --git a/common/src/test/java/org/opensearch/sql/common/authinterceptors/BasicAuthenticationInterceptorTest.java b/common/src/test/java/org/opensearch/sql/common/interceptors/BasicAuthenticationInterceptorTest.java similarity index 96% rename from common/src/test/java/org/opensearch/sql/common/authinterceptors/BasicAuthenticationInterceptorTest.java rename to common/src/test/java/org/opensearch/sql/common/interceptors/BasicAuthenticationInterceptorTest.java index d59928d2ef..af93060fab 100644 --- a/common/src/test/java/org/opensearch/sql/common/authinterceptors/BasicAuthenticationInterceptorTest.java +++ b/common/src/test/java/org/opensearch/sql/common/interceptors/BasicAuthenticationInterceptorTest.java @@ -5,7 +5,7 @@ * */ -package org.opensearch.sql.common.authinterceptors; +package org.opensearch.sql.common.interceptors; import java.util.Collections; import lombok.SneakyThrows; diff --git a/docs/user/ppl/admin/datasources.rst b/docs/user/ppl/admin/datasources.rst index 0f026f72cf..37d2fdfcee 100644 --- a/docs/user/ppl/admin/datasources.rst +++ b/docs/user/ppl/admin/datasources.rst @@ -140,15 +140,11 @@ Master Key config for encrypting credential information # Print the master key print("Generated master key:", master_key) -Datasource Allow Hosts Config +Datasource URI Hosts Deny Lists Config ======================================================== -* In the OpenSearch configuration file (opensearch.yml), the parameter "plugins.query.datasources.uri.allowhosts" can be utilized to control the permitted hosts within the datasource URI configuration. -* By default, the value is set to `.*`, which allows any domain to be accepted. -* For instance, if you set the value to `dummy.*.com`, the following URIs are some examples that would be allowed in the datasource configuration: - - https://dummy.prometheus.com:9080 - - http://dummy.prometheus.com - -Note: The mentioned URIs are just examples to illustrate the concept. +* In the OpenSearch configuration file (opensearch.yml), the parameter "plugins.query.datasources.uri.hosts.denylist" can be utilized to control the permitted host ips within the datasource URI configuration. +* By default, the value is set to empty list, which allows any domain to be accepted. +* For instance, if you set the value to `127.0.0.0/8`, ppl plugins will deny all the query requests where the datasource URI resolves to the ip range from `127.0.0.0` to `127.255.255.255` Using a datasource in PPL command diff --git a/opensearch/src/main/java/org/opensearch/sql/opensearch/setting/OpenSearchSettings.java b/opensearch/src/main/java/org/opensearch/sql/opensearch/setting/OpenSearchSettings.java index 133903dabe..48ceacaf10 100644 --- a/opensearch/src/main/java/org/opensearch/sql/opensearch/setting/OpenSearchSettings.java +++ b/opensearch/src/main/java/org/opensearch/sql/opensearch/setting/OpenSearchSettings.java @@ -12,10 +12,12 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import java.io.InputStream; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; +import java.util.function.Function; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import org.opensearch.cluster.ClusterName; @@ -119,10 +121,11 @@ public class OpenSearchSettings extends Settings { Setting.Property.Final, Setting.Property.Filtered); - public static final Setting DATASOURCE_URI_ALLOW_HOSTS = - Setting.simpleString( - Key.DATASOURCES_URI_ALLOWHOSTS.getKeyValue(), - ".*", + public static final Setting> DATASOURCE_URI_HOSTS_DENY_LIST = + Setting.listSetting( + Key.DATASOURCES_URI_HOSTS_DENY_LIST.getKeyValue(), + Collections.emptyList(), + Function.identity(), Setting.Property.NodeScope, Setting.Property.Dynamic); @@ -187,9 +190,9 @@ public OpenSearchSettings(ClusterSettings clusterSettings) { register( settingBuilder, clusterSettings, - Key.DATASOURCES_URI_ALLOWHOSTS, - DATASOURCE_URI_ALLOW_HOSTS, - new Updater(Key.DATASOURCES_URI_ALLOWHOSTS)); + Key.DATASOURCES_URI_HOSTS_DENY_LIST, + DATASOURCE_URI_HOSTS_DENY_LIST, + new Updater(Key.DATASOURCES_URI_HOSTS_DENY_LIST)); registerNonDynamicSettings( settingBuilder, clusterSettings, Key.CLUSTER_NAME, ClusterName.CLUSTER_NAME_SETTING); defaultSettings = settingBuilder.build(); @@ -253,7 +256,7 @@ public static List> pluginSettings() { .add(QUERY_SIZE_LIMIT_SETTING) .add(METRICS_ROLLING_WINDOW_SETTING) .add(METRICS_ROLLING_INTERVAL_SETTING) - .add(DATASOURCE_URI_ALLOW_HOSTS) + .add(DATASOURCE_URI_HOSTS_DENY_LIST) .build(); } diff --git a/prometheus/src/main/java/org/opensearch/sql/prometheus/client/PrometheusClientImpl.java b/prometheus/src/main/java/org/opensearch/sql/prometheus/client/PrometheusClientImpl.java index 46525fd58c..48154964eb 100644 --- a/prometheus/src/main/java/org/opensearch/sql/prometheus/client/PrometheusClientImpl.java +++ b/prometheus/src/main/java/org/opensearch/sql/prometheus/client/PrometheusClientImpl.java @@ -128,9 +128,7 @@ private JSONObject readResponse(Response response) throws IOException { } } else { throw new PrometheusClientException( - String.format( - "Request to Prometheus is Unsuccessful with : %s", - Objects.requireNonNull(response.body(), "Response body can't be null").string())); + String.format("Request to Prometheus is Unsuccessful with code : %s", response.code())); } } } diff --git a/prometheus/src/main/java/org/opensearch/sql/prometheus/storage/PrometheusStorageFactory.java b/prometheus/src/main/java/org/opensearch/sql/prometheus/storage/PrometheusStorageFactory.java index 76d89aad47..4ed3bbd735 100644 --- a/prometheus/src/main/java/org/opensearch/sql/prometheus/storage/PrometheusStorageFactory.java +++ b/prometheus/src/main/java/org/opensearch/sql/prometheus/storage/PrometheusStorageFactory.java @@ -11,20 +11,21 @@ import com.amazonaws.auth.BasicAWSCredentials; import java.net.URI; import java.net.URISyntaxException; +import java.net.UnknownHostException; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import lombok.RequiredArgsConstructor; import okhttp3.OkHttpClient; import org.apache.commons.validator.routines.DomainValidator; -import org.opensearch.sql.common.authinterceptors.AwsSigningInterceptor; -import org.opensearch.sql.common.authinterceptors.BasicAuthenticationInterceptor; +import org.opensearch.sql.common.interceptors.AwsSigningInterceptor; +import org.opensearch.sql.common.interceptors.BasicAuthenticationInterceptor; +import org.opensearch.sql.common.interceptors.URIValidatorInterceptor; import org.opensearch.sql.common.setting.Settings; +import org.opensearch.sql.common.utils.URIValidationUtils; import org.opensearch.sql.datasource.model.DataSource; import org.opensearch.sql.datasource.model.DataSourceMetadata; import org.opensearch.sql.datasource.model.DataSourceType; @@ -61,7 +62,7 @@ public DataSource createDataSource(DataSourceMetadata metadata) { // Need to refactor to a separate Validator class. private void validateDataSourceConfigProperties(Map dataSourceMetadataConfig) - throws URISyntaxException { + throws URISyntaxException, UnknownHostException { if (dataSourceMetadataConfig.get(AUTH_TYPE) != null) { AuthenticationType authenticationType = AuthenticationType.get(dataSourceMetadataConfig.get(AUTH_TYPE)); @@ -87,7 +88,7 @@ StorageEngine getStorageEngine(Map requiredConfig) { validateDataSourceConfigProperties(requiredConfig); return new PrometheusClientImpl( getHttpClient(requiredConfig), new URI(requiredConfig.get(URI))); - } catch (URISyntaxException e) { + } catch (URISyntaxException | UnknownHostException e) { throw new IllegalArgumentException( String.format("Invalid URI in prometheus properties: %s", e.getMessage())); } @@ -100,6 +101,9 @@ private OkHttpClient getHttpClient(Map config) { okHttpClient.callTimeout(1, TimeUnit.MINUTES); okHttpClient.connectTimeout(30, TimeUnit.SECONDS); okHttpClient.followRedirects(false); + okHttpClient.addInterceptor( + new URIValidatorInterceptor( + settings.getSettingValue(Settings.Key.DATASOURCES_URI_HOSTS_DENY_LIST))); if (config.get(AUTH_TYPE) != null) { AuthenticationType authenticationType = AuthenticationType.get(config.get(AUTH_TYPE)); if (AuthenticationType.BASICAUTH.equals(authenticationType)) { @@ -148,7 +152,8 @@ private void validateMissingFields(Map config, Set field } } - private void validateURI(Map config) throws URISyntaxException { + private void validateURI(Map config) + throws URISyntaxException, UnknownHostException { URI uri = new URI(config.get(URI)); String host = uri.getHost(); if (host == null @@ -157,14 +162,14 @@ private void validateURI(Map config) throws URISyntaxException { throw new IllegalArgumentException( String.format("Invalid hostname in the uri: %s", config.get(URI))); } else { - Pattern allowHostsPattern = - Pattern.compile(settings.getSettingValue(Settings.Key.DATASOURCES_URI_ALLOWHOSTS)); - Matcher matcher = allowHostsPattern.matcher(host); - if (!matcher.matches()) { + boolean isAllowedHost = + URIValidationUtils.validateURIHost( + host, settings.getSettingValue(Settings.Key.DATASOURCES_URI_HOSTS_DENY_LIST)); + if (!isAllowedHost) { throw new IllegalArgumentException( String.format( "Disallowed hostname in the uri. Validate with %s config", - Settings.Key.DATASOURCES_URI_ALLOWHOSTS.getKeyValue())); + Settings.Key.DATASOURCES_URI_HOSTS_DENY_LIST.getKeyValue())); } } } diff --git a/prometheus/src/test/java/org/opensearch/sql/prometheus/client/PrometheusClientImplTest.java b/prometheus/src/test/java/org/opensearch/sql/prometheus/client/PrometheusClientImplTest.java index 81cd2e3860..d6ca25b206 100644 --- a/prometheus/src/test/java/org/opensearch/sql/prometheus/client/PrometheusClientImplTest.java +++ b/prometheus/src/test/java/org/opensearch/sql/prometheus/client/PrometheusClientImplTest.java @@ -114,10 +114,9 @@ void testQueryRangeWithNon2xxError() { assertThrows( PrometheusClientException.class, () -> prometheusClient.queryRange(QUERY, STARTTIME, ENDTIME, STEP)); - assertTrue( - prometheusClientException - .getMessage() - .contains("Request to Prometheus is Unsuccessful with :")); + assertEquals( + "Request to Prometheus is Unsuccessful with code : 400", + prometheusClientException.getMessage()); RecordedRequest recordedRequest = mockWebServer.takeRequest(); verifyQueryRangeCall(recordedRequest); } diff --git a/prometheus/src/test/java/org/opensearch/sql/prometheus/storage/PrometheusStorageFactoryTest.java b/prometheus/src/test/java/org/opensearch/sql/prometheus/storage/PrometheusStorageFactoryTest.java index 49cdc42f4e..46658699ca 100644 --- a/prometheus/src/test/java/org/opensearch/sql/prometheus/storage/PrometheusStorageFactoryTest.java +++ b/prometheus/src/test/java/org/opensearch/sql/prometheus/storage/PrometheusStorageFactoryTest.java @@ -9,6 +9,7 @@ import static org.mockito.Mockito.when; +import java.util.Collections; import java.util.HashMap; import lombok.SneakyThrows; import org.apache.commons.lang3.RandomStringUtils; @@ -38,10 +39,11 @@ void testGetConnectorType() { @Test @SneakyThrows void testGetStorageEngineWithBasicAuth() { - when(settings.getSettingValue(Settings.Key.DATASOURCES_URI_ALLOWHOSTS)).thenReturn(".*"); + when(settings.getSettingValue(Settings.Key.DATASOURCES_URI_HOSTS_DENY_LIST)) + .thenReturn(Collections.emptyList()); PrometheusStorageFactory prometheusStorageFactory = new PrometheusStorageFactory(settings); HashMap properties = new HashMap<>(); - properties.put("prometheus.uri", "http://dummyprometheus.com:9090"); + properties.put("prometheus.uri", "http://localhost:9090"); properties.put("prometheus.auth.type", "basicauth"); properties.put("prometheus.auth.username", "admin"); properties.put("prometheus.auth.password", "admin"); @@ -52,10 +54,11 @@ void testGetStorageEngineWithBasicAuth() { @Test @SneakyThrows void testGetStorageEngineWithAWSSigV4Auth() { - when(settings.getSettingValue(Settings.Key.DATASOURCES_URI_ALLOWHOSTS)).thenReturn(".*"); + when(settings.getSettingValue(Settings.Key.DATASOURCES_URI_HOSTS_DENY_LIST)) + .thenReturn(Collections.emptyList()); PrometheusStorageFactory prometheusStorageFactory = new PrometheusStorageFactory(settings); HashMap properties = new HashMap<>(); - properties.put("prometheus.uri", "http://dummyprometheus.com:9090"); + properties.put("prometheus.uri", "http://localhost:9090"); properties.put("prometheus.auth.type", "awssigv4"); properties.put("prometheus.auth.region", "us-east-1"); properties.put("prometheus.auth.secret_key", "accessKey"); @@ -123,7 +126,8 @@ void testGetStorageEngineWithLongConfigProperties() { @Test @SneakyThrows void testGetStorageEngineWithWrongAuthType() { - when(settings.getSettingValue(Settings.Key.DATASOURCES_URI_ALLOWHOSTS)).thenReturn(".*"); + when(settings.getSettingValue(Settings.Key.DATASOURCES_URI_HOSTS_DENY_LIST)) + .thenReturn(Collections.emptyList()); PrometheusStorageFactory prometheusStorageFactory = new PrometheusStorageFactory(settings); HashMap properties = new HashMap<>(); properties.put("prometheus.uri", "https://test.com"); @@ -142,7 +146,8 @@ void testGetStorageEngineWithWrongAuthType() { @Test @SneakyThrows void testGetStorageEngineWithNONEAuthType() { - when(settings.getSettingValue(Settings.Key.DATASOURCES_URI_ALLOWHOSTS)).thenReturn(".*"); + when(settings.getSettingValue(Settings.Key.DATASOURCES_URI_HOSTS_DENY_LIST)) + .thenReturn(Collections.emptyList()); PrometheusStorageFactory prometheusStorageFactory = new PrometheusStorageFactory(settings); HashMap properties = new HashMap<>(); properties.put("prometheus.uri", "https://test.com"); @@ -168,9 +173,10 @@ void testGetStorageEngineWithInvalidURISyntax() { @Test void createDataSourceSuccess() { - when(settings.getSettingValue(Settings.Key.DATASOURCES_URI_ALLOWHOSTS)).thenReturn(".*"); + when(settings.getSettingValue(Settings.Key.DATASOURCES_URI_HOSTS_DENY_LIST)) + .thenReturn(Collections.emptyList()); HashMap properties = new HashMap<>(); - properties.put("prometheus.uri", "http://dummyprometheus.com:9090"); + properties.put("prometheus.uri", "http://localhost:9090"); properties.put("prometheus.auth.type", "basicauth"); properties.put("prometheus.auth.username", "admin"); properties.put("prometheus.auth.password", "admin"); @@ -186,7 +192,8 @@ void createDataSourceSuccess() { @Test void createDataSourceSuccessWithLocalhost() { - when(settings.getSettingValue(Settings.Key.DATASOURCES_URI_ALLOWHOSTS)).thenReturn(".*"); + when(settings.getSettingValue(Settings.Key.DATASOURCES_URI_HOSTS_DENY_LIST)) + .thenReturn(Collections.emptyList()); HashMap properties = new HashMap<>(); properties.put("prometheus.uri", "http://localhost:9090"); properties.put("prometheus.auth.type", "basicauth"); @@ -248,10 +255,10 @@ void createDataSourceWithInvalidIp() { @Test void createDataSourceWithHostnameNotMatchingWithAllowHostsConfig() { - when(settings.getSettingValue(Settings.Key.DATASOURCES_URI_ALLOWHOSTS)) - .thenReturn("^dummy.*.com$"); + when(settings.getSettingValue(Settings.Key.DATASOURCES_URI_HOSTS_DENY_LIST)) + .thenReturn(Collections.singletonList("127.0.0.0/8")); HashMap properties = new HashMap<>(); - properties.put("prometheus.uri", "http://localhost.com:9090"); + properties.put("prometheus.uri", "http://localhost:9090"); properties.put("prometheus.auth.type", "basicauth"); properties.put("prometheus.auth.username", "admin"); properties.put("prometheus.auth.password", "admin"); @@ -265,29 +272,9 @@ void createDataSourceWithHostnameNotMatchingWithAllowHostsConfig() { RuntimeException exception = Assertions.assertThrows( RuntimeException.class, () -> prometheusStorageFactory.createDataSource(metadata)); - Assertions.assertTrue( - exception - .getMessage() - .contains( - "Disallowed hostname in the uri. " - + "Validate with plugins.query.datasources.uri.allowhosts config")); - } - - @Test - void createDataSourceSuccessWithHostnameRestrictions() { - when(settings.getSettingValue(Settings.Key.DATASOURCES_URI_ALLOWHOSTS)) - .thenReturn("^dummy.*.com$"); - HashMap properties = new HashMap<>(); - properties.put("prometheus.uri", "http://dummy.prometheus.com:9090"); - properties.put("prometheus.auth.type", "basicauth"); - properties.put("prometheus.auth.username", "admin"); - properties.put("prometheus.auth.password", "admin"); - - DataSourceMetadata metadata = new DataSourceMetadata(); - metadata.setName("prometheus"); - metadata.setConnector(DataSourceType.PROMETHEUS); - metadata.setProperties(properties); - DataSource dataSource = new PrometheusStorageFactory(settings).createDataSource(metadata); - Assertions.assertTrue(dataSource.getStorageEngine() instanceof PrometheusStorageEngine); + Assertions.assertEquals( + "Disallowed hostname in the uri. " + + "Validate with plugins.query.datasources.uri.hosts.denylist config", + exception.getMessage()); } }