From 6724a1df5c2243dc90fd26b3ce45fc43f93c6164 Mon Sep 17 00:00:00 2001 From: Pablo Arteaga Date: Thu, 19 Sep 2024 19:42:06 +0100 Subject: [PATCH] Add configurable in-memory caching to the HTTP Credentials Provider --- pom.xml | 13 ++ trino-aws-proxy/pom.xml | 5 + .../http/HttpCredentialsProvider.java | 44 ++++- .../http/HttpCredentialsProviderConfig.java | 45 ++++- .../http/TestHttpCredentialsProvider.java | 158 +++++++++++++----- .../TestHttpCredentialsProviderConfig.java | 38 ++++- 6 files changed, 250 insertions(+), 53 deletions(-) diff --git a/pom.xml b/pom.xml index c8760b79..3c96ad0d 100644 --- a/pom.xml +++ b/pom.xml @@ -58,6 +58,7 @@ 8.5.9 3.3.6 4.1.1 + 3.1.8 @@ -108,6 +109,18 @@ ${project.version} + + com.github.ben-manes.caffeine + caffeine + ${dep.caffeine.version} + + + org.checkerframework + checker-qual + + + + com.github.docker-java docker-java-api diff --git a/trino-aws-proxy/pom.xml b/trino-aws-proxy/pom.xml index cde77304..50b579ea 100644 --- a/trino-aws-proxy/pom.xml +++ b/trino-aws-proxy/pom.xml @@ -44,6 +44,11 @@ jackson-dataformat-xml + + com.github.ben-manes.caffeine + caffeine + + com.google.guava guava diff --git a/trino-aws-proxy/src/main/java/io/trino/aws/proxy/server/credentials/http/HttpCredentialsProvider.java b/trino-aws-proxy/src/main/java/io/trino/aws/proxy/server/credentials/http/HttpCredentialsProvider.java index aa73a1fb..cf3a7c19 100644 --- a/trino-aws-proxy/src/main/java/io/trino/aws/proxy/server/credentials/http/HttpCredentialsProvider.java +++ b/trino-aws-proxy/src/main/java/io/trino/aws/proxy/server/credentials/http/HttpCredentialsProvider.java @@ -13,6 +13,9 @@ */ package io.trino.aws.proxy.server.credentials.http; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Multimaps; import com.google.inject.Inject; @@ -28,6 +31,7 @@ import java.net.URI; import java.util.Map; import java.util.Optional; +import java.util.function.Function; import static io.airlift.http.client.FullJsonResponseHandler.createFullJsonResponseHandler; import static io.airlift.http.client.Request.Builder.prepareGet; @@ -36,10 +40,20 @@ public class HttpCredentialsProvider implements CredentialsProvider { + private record CredentialsKey(String emulatedAccessKey, Optional session) + { + private CredentialsKey { + requireNonNull(emulatedAccessKey, "emulatedAccessKey is null"); + requireNonNull(session, "session is null"); + } + } + private final HttpClient httpClient; private final JsonCodec jsonCodec; private final URI httpCredentialsProviderEndpoint; private final Map httpHeaders; + private final Optional>> credentialsCache; + private final Function> credentialsFetcher; @Inject public HttpCredentialsProvider(@ForHttpCredentialsProvider HttpClient httpClient, HttpCredentialsProviderConfig config, JsonCodec jsonCodec) @@ -48,13 +62,39 @@ public HttpCredentialsProvider(@ForHttpCredentialsProvider HttpClient httpClient this.jsonCodec = requireNonNull(jsonCodec, "jsonCodec is null"); this.httpCredentialsProviderEndpoint = config.getEndpoint(); this.httpHeaders = ImmutableMap.copyOf(config.getHttpHeaders()); + if (config.getCacheSize() > 0 && config.getCacheTtl().toMillis() > 0) { + LoadingCache> cache = Caffeine.newBuilder() + .maximumSize(config.getCacheSize()) + .expireAfterWrite(config.getCacheTtl().toJavaTime()) + .build(this::fetchCredentials); + this.credentialsCache = Optional.of(cache); + this.credentialsFetcher = cache::get; + } + else { + this.credentialsCache = Optional.empty(); + this.credentialsFetcher = this::fetchCredentials; + } } @Override public Optional credentials(String emulatedAccessKey, Optional session) { - UriBuilder uriBuilder = UriBuilder.fromUri(httpCredentialsProviderEndpoint).path(emulatedAccessKey); - session.ifPresent(sessionToken -> uriBuilder.queryParam("sessionToken", sessionToken)); + return credentialsFetcher.apply(new CredentialsKey(emulatedAccessKey, session)); + } + + @VisibleForTesting + void resetCache() + { + credentialsCache.ifPresent(instantiatedCache -> { + instantiatedCache.invalidateAll(); + instantiatedCache.cleanUp(); + }); + } + + private Optional fetchCredentials(CredentialsKey credentialsKey) + { + UriBuilder uriBuilder = UriBuilder.fromUri(httpCredentialsProviderEndpoint).path(credentialsKey.emulatedAccessKey()); + credentialsKey.session().ifPresent(sessionToken -> uriBuilder.queryParam("sessionToken", sessionToken)); Request.Builder requestBuilder = prepareGet() .addHeaders(Multimaps.forMap(httpHeaders)) .setUri(uriBuilder.build()); diff --git a/trino-aws-proxy/src/main/java/io/trino/aws/proxy/server/credentials/http/HttpCredentialsProviderConfig.java b/trino-aws-proxy/src/main/java/io/trino/aws/proxy/server/credentials/http/HttpCredentialsProviderConfig.java index c563534f..ce9f4f3a 100644 --- a/trino-aws-proxy/src/main/java/io/trino/aws/proxy/server/credentials/http/HttpCredentialsProviderConfig.java +++ b/trino-aws-proxy/src/main/java/io/trino/aws/proxy/server/credentials/http/HttpCredentialsProviderConfig.java @@ -14,7 +14,12 @@ package io.trino.aws.proxy.server.credentials.http; import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableMap; import io.airlift.configuration.Config; +import io.airlift.configuration.ConfigDescription; +import io.airlift.units.Duration; +import io.airlift.units.MinDuration; +import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; import java.net.URI; @@ -25,7 +30,9 @@ public class HttpCredentialsProviderConfig { private URI endpoint; - private Map httpHeaders = Map.of(); + private Map httpHeaders = ImmutableMap.of(); + private long cacheSize; + private Duration cacheTtl = Duration.ZERO; @NotNull public URI getEndpoint() @@ -34,9 +41,10 @@ public URI getEndpoint() } @Config("credentials-provider.http.endpoint") - public HttpCredentialsProviderConfig setEndpoint(String endpoint) + @ConfigDescription("URL to retrieve credentials from, the username will be passed as a path under this URL") + public HttpCredentialsProviderConfig setEndpoint(URI endpoint) { - this.endpoint = URI.create(endpoint); + this.endpoint = endpoint; return this; } @@ -46,6 +54,9 @@ public Map getHttpHeaders() } @Config("credentials-provider.http.headers") + @ConfigDescription( + "Additional headers to include in requests, in the format header-1-name:header-1-value,header-2-name:header-2-value. " + + "If a header value needs to include a comma, it should be doubled") public HttpCredentialsProviderConfig setHttpHeaders(String httpHeadersList) { try { @@ -62,4 +73,32 @@ public HttpCredentialsProviderConfig setHttpHeaders(String httpHeadersList) } return this; } + + @Config("credentials-provider.http.cache-size") + @ConfigDescription("In-memory cache size for the credentials provider, defaults to 0 (no caching)") + public HttpCredentialsProviderConfig setCacheSize(long cacheSize) + { + this.cacheSize = cacheSize; + return this; + } + + @Min(0) + public long getCacheSize() + { + return cacheSize; + } + + @Config("credentials-provider.http.cache-ttl") + @ConfigDescription("In-memory cache TTL for the credentials provider, defaults to 0 seconds (no caching)") + public HttpCredentialsProviderConfig setCacheTtl(Duration cacheTtl) + { + this.cacheTtl = cacheTtl; + return this; + } + + @MinDuration("0s") + public Duration getCacheTtl() + { + return cacheTtl; + } } diff --git a/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/credentials/http/TestHttpCredentialsProvider.java b/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/credentials/http/TestHttpCredentialsProvider.java index 343bd685..330164fa 100644 --- a/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/credentials/http/TestHttpCredentialsProvider.java +++ b/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/credentials/http/TestHttpCredentialsProvider.java @@ -13,7 +13,6 @@ */ package io.trino.aws.proxy.server.credentials.http; -import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.inject.Inject; @@ -32,10 +31,13 @@ import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.io.IOException; +import java.util.Map; import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; import static io.trino.aws.proxy.server.credentials.http.HttpCredentialsModule.HTTP_CREDENTIALS_PROVIDER_IDENTIFIER; import static io.trino.aws.proxy.spi.plugin.TrinoAwsProxyServerBinding.bindIdentityType; @@ -46,7 +48,14 @@ @TrinoAwsProxyTest(filters = TestHttpCredentialsProvider.Filter.class) public class TestHttpCredentialsProvider { + private static final String DUMMY_EMULATED_ACCESS_KEY = "test-emulated-access-key"; + private static final String DUMMY_EMULATED_SECRET_KEY = "test-emulated-secret-key"; + private static final String DUMMY_REMOTE_ACCESS_KEY = "test-remote-access-key"; + private static final String DUMMY_REMOTE_SECRET_KEY = "test-remote-secret-key"; + private final CredentialsProvider credentialsProvider; + private final HttpCredentialsServlet httpCredentialsServlet; + private final HttpCredentialsProvider httpCredentialsProvider; public static class Filter implements BuilderFilter @@ -57,8 +66,16 @@ public static class Filter public TestingTrinoAwsProxyServer.Builder filter(TestingTrinoAwsProxyServer.Builder builder) { TestingHttpServer httpCredentialsServer; + Map expectedHeaders = ImmutableMap.builder() + .put("Authorization", "some-auth") + .put("Content-Type", "application/json") + .put("Some-Dummy-Header", "test,value") + .buildOrThrow(); + String headerConfigAsString = "Authorization: some-auth, Content-Type: application/json, Some-Dummy-Header:test,,value"; + + HttpCredentialsServlet httpCredentialsServlet = new HttpCredentialsServlet(expectedHeaders); try { - httpCredentialsServer = createTestingHttpCredentialsServer(); + httpCredentialsServer = createTestingHttpCredentialsServer(httpCredentialsServlet); httpCredentialsServer.start(); httpEndpointUri = httpCredentialsServer.getBaseUrl().toString(); } @@ -70,100 +87,153 @@ public TestingTrinoAwsProxyServer.Builder filter(TestingTrinoAwsProxyServer.Buil .addModule(binder -> bindIdentityType(binder, TestingIdentity.class)) .withProperty("credentials-provider.type", HTTP_CREDENTIALS_PROVIDER_IDENTIFIER) .withProperty("credentials-provider.http.endpoint", httpEndpointUri) - .withProperty("credentials-provider.http.headers", "Authorization: auth, Content-Type: application/json"); + .withProperty("credentials-provider.http.headers", headerConfigAsString) + .withProperty("credentials-provider.http.cache-size", "2") + .withProperty("credentials-provider.http.cache-ttl", "10m") + .addModule(binder -> binder.bind(HttpCredentialsServlet.class).toInstance(httpCredentialsServlet)); } } @Inject - public TestHttpCredentialsProvider(CredentialsProvider credentialsProvider) + public TestHttpCredentialsProvider(CredentialsProvider credentialsProvider, HttpCredentialsServlet httpCredentialsServlet, CredentialsProvider httpCredentialsProvider) { this.credentialsProvider = requireNonNull(credentialsProvider, "credentialsProvider is null"); + this.httpCredentialsServlet = requireNonNull(httpCredentialsServlet, "httpCredentialsServlet is null"); + this.httpCredentialsProvider = (HttpCredentialsProvider) requireNonNull(httpCredentialsProvider, "httpCredentialsProvider is null"); + } + + @BeforeEach + public void resetRequestCounter() + { + httpCredentialsProvider.resetCache(); + httpCredentialsServlet.resetRequestCount(); } @Test public void testValidCredentialsWithEmptySession() { - Credential emulated = new Credential("test-emulated-access-key", "test-emulated-secret"); - Credential remote = new Credential("test-remote-access-key", "test-remote-secret"); - Credentials expected = new Credentials(emulated, Optional.of(remote), Optional.empty(), Optional.of(new TestingIdentity("test-username", ImmutableList.of(), "xyzpdq"))); - Optional actual = credentialsProvider.credentials("test-emulated-access-key", Optional.empty()); - assertThat(actual).contains(expected); + testValidCredentials(Optional.empty()); } @Test public void testValidCredentialsWithValidSession() { - Credential emulated = new Credential("test-emulated-access-key", "test-emulated-secret"); - Credential remote = new Credential("test-remote-access-key", "test-remote-secret"); - Credentials expected = new Credentials(emulated, Optional.of(remote), Optional.empty(), Optional.of(new TestingIdentity("test-username", ImmutableList.of(), "xyzpdq"))); - Optional actual = credentialsProvider.credentials("test-emulated-access-key", Optional.of("test-emulated-access-key")); + testValidCredentials(Optional.of("%s-token".formatted(DUMMY_EMULATED_ACCESS_KEY))); + } + + @Test + public void testCredentialsCached() + { + String validToken = "%s-token".formatted(DUMMY_EMULATED_ACCESS_KEY); + // First credential is retrieved + testValidCredentials(Optional.of(validToken), 1); + + // Second credential is retrieved - the access key is identical, but the session token is not + testValidCredentials(Optional.empty(), 2); + + // Requesting these same two credentials again should not result in new HTTP calls + testValidCredentials(Optional.of(validToken), 2); + testValidCredentials(Optional.empty(), 2); + + // But if we request something else, it should still go to the HTTP endpoint + assertThat(credentialsProvider.credentials("something-else", Optional.empty())).isEmpty(); + assertThat(httpCredentialsServlet.getRequestCount()).isEqualTo(3); + } + + private void testValidCredentials(Optional emulatedAccessToken) + { + testValidCredentials(emulatedAccessToken, 1); + } + + private void testValidCredentials(Optional emulatedAccessToken, int expectedRequestCount) + { + Credential expectedEmulated = new Credential(DUMMY_EMULATED_ACCESS_KEY, DUMMY_EMULATED_SECRET_KEY, emulatedAccessToken); + Credential expectedRemote = new Credential(DUMMY_REMOTE_ACCESS_KEY, DUMMY_REMOTE_SECRET_KEY); + + Credentials expected = new Credentials(expectedEmulated, Optional.of(expectedRemote), Optional.empty(), Optional.of(new TestingIdentity("test-username", ImmutableList.of(), "xyzpdq"))); + Optional actual = credentialsProvider.credentials(DUMMY_EMULATED_ACCESS_KEY, emulatedAccessToken); assertThat(actual).contains(expected); + assertThat(httpCredentialsServlet.getRequestCount()).isEqualTo(expectedRequestCount); } @Test public void testInvalidCredentialsWithEmptySession() { - Optional actual = credentialsProvider.credentials("non-existent-key", Optional.empty()); - assertThat(actual).isEmpty(); + testNoCredentialsRetrieved("non-existent-key", Optional.empty()); } @Test public void testValidCredentialsWithInvalidSession() { - Optional actual = credentialsProvider.credentials("test-emulated-access-key", Optional.of("sessionToken-not-equals-accessKey")); - assertThat(actual).isEmpty(); + testNoCredentialsRetrieved(DUMMY_EMULATED_ACCESS_KEY, Optional.of("session-token-not-valid-for-access-key")); } @Test public void testInvalidCredentialsWithInvalidSession() { - Optional actual = credentialsProvider.credentials("non-existent-key", Optional.of("sessionToken-not-equals-accessKey")); - assertThat(actual).isEmpty(); + testNoCredentialsRetrieved("non-existent-key", Optional.of("session-token-not-valid-for-access-key")); } @Test public void testIncorrectResponseFromServer() { - Optional actual = credentialsProvider.credentials("incorrect-response", Optional.empty()); - assertThat(actual).isEmpty(); + testNoCredentialsRetrieved("incorrect-response", Optional.empty()); } - private static TestingHttpServer createTestingHttpCredentialsServer() + private void testNoCredentialsRetrieved(String emulatedAccessKey, Optional sessionToken) + { + assertThat(credentialsProvider.credentials(emulatedAccessKey, sessionToken)).isEmpty(); + assertThat(httpCredentialsServlet.getRequestCount()).isEqualTo(1); + } + + private static TestingHttpServer createTestingHttpCredentialsServer(HttpCredentialsServlet servlet) throws IOException { NodeInfo nodeInfo = new NodeInfo("test"); HttpServerConfig config = new HttpServerConfig().setHttpPort(0); HttpServerInfo httpServerInfo = new HttpServerInfo(config, nodeInfo); - return new TestingHttpServer(httpServerInfo, nodeInfo, config, new HttpCredentialsServlet(), ImmutableMap.of()); + return new TestingHttpServer(httpServerInfo, nodeInfo, config, servlet, ImmutableMap.of()); } private static class HttpCredentialsServlet extends HttpServlet { + private final Map expectedHeaders; + private final AtomicInteger requestCounter; + + private HttpCredentialsServlet(Map expectedHeaders) + { + this.expectedHeaders = ImmutableMap.copyOf(expectedHeaders); + this.requestCounter = new AtomicInteger(); + } + @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { - if (Strings.isNullOrEmpty(request.getHeader("Authorization")) || Strings.isNullOrEmpty("Content-Type")) { - response.setStatus(HttpServletResponse.SC_BAD_REQUEST); - return; + requestCounter.addAndGet(1); + for (Map.Entry expectedHeader : expectedHeaders.entrySet()) { + if (!expectedHeader.getValue().equals(request.getHeader(expectedHeader.getKey()))) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return; + } } Optional sessionToken = Optional.ofNullable(request.getParameter("sessionToken")); String emulatedAccessKey = request.getPathInfo().substring(1); - String credentialsIdentifier = ""; - if (sessionToken.isPresent()) { - // Simulate valid session - When accessKey equals sessionToken - if (emulatedAccessKey.equals(sessionToken.get())) { - credentialsIdentifier = sessionToken.get(); - } - } - else { - credentialsIdentifier = emulatedAccessKey; + // The session token in the request is legal if it is either: + // - Not present + // - Matching our test logic: it should be equal to the access-key + "-token" + boolean isLegalSessionToken = sessionToken + .map(presentSessionToken -> "%s-token".formatted(emulatedAccessKey).equals(presentSessionToken)) + .orElse(true); + if (!isLegalSessionToken) { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + return; } - switch (credentialsIdentifier) { - case "test-emulated-access-key" -> { - Credential emulated = new Credential("test-emulated-access-key", "test-emulated-secret"); - Credential remote = new Credential("test-remote-access-key", "test-remote-secret"); + switch (emulatedAccessKey) { + case DUMMY_EMULATED_ACCESS_KEY -> { + Credential emulated = new Credential(DUMMY_EMULATED_ACCESS_KEY, DUMMY_EMULATED_SECRET_KEY, sessionToken); + Credential remote = new Credential(DUMMY_REMOTE_ACCESS_KEY, DUMMY_REMOTE_SECRET_KEY); Credentials credentials = new Credentials(emulated, Optional.of(remote), Optional.empty(), Optional.of(new TestingIdentity("test-username", ImmutableList.of(), "xyzpdq"))); String jsonCredentials = new ObjectMapperProvider().get().writeValueAsString(credentials); response.setContentType(APPLICATION_JSON); @@ -175,5 +245,15 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) default -> response.setStatus(HttpServletResponse.SC_NOT_FOUND); } } + + private int getRequestCount() + { + return requestCounter.get(); + } + + private void resetRequestCount() + { + requestCounter.set(0); + } } } diff --git a/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/credentials/http/TestHttpCredentialsProviderConfig.java b/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/credentials/http/TestHttpCredentialsProviderConfig.java index 6b1f2022..b52fbb62 100644 --- a/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/credentials/http/TestHttpCredentialsProviderConfig.java +++ b/trino-aws-proxy/src/test/java/io/trino/aws/proxy/server/credentials/http/TestHttpCredentialsProviderConfig.java @@ -14,11 +14,16 @@ package io.trino.aws.proxy.server.credentials.http; import com.google.common.collect.ImmutableMap; +import io.airlift.units.Duration; import org.junit.jupiter.api.Test; +import java.net.URI; import java.util.Map; +import java.util.concurrent.TimeUnit; import static io.airlift.configuration.testing.ConfigAssertions.assertFullMapping; +import static io.airlift.configuration.testing.ConfigAssertions.assertRecordedDefaults; +import static io.airlift.configuration.testing.ConfigAssertions.recordDefaults; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -27,20 +32,35 @@ public class TestHttpCredentialsProviderConfig @Test public void testExplicitPropertyMappings() { - Map properties = ImmutableMap.of( - "credentials-provider.http.endpoint", "http://usersvc:9000/api/v1/users", - "credentials-provider.http.headers", "x-api-key: xyz123, Content-Type: application/json"); + Map properties = ImmutableMap.builder() + .put("credentials-provider.http.endpoint", "http://usersvc:9000/api/v1/users") + .put("credentials-provider.http.headers", "x-api-key: xyz123, Content-Type: application/json") + .put("credentials-provider.http.cache-size", "123") + .put("credentials-provider.http.cache-ttl", "2m") + .buildOrThrow(); HttpCredentialsProviderConfig expected = new HttpCredentialsProviderConfig() - .setEndpoint("http://usersvc:9000/api/v1/users") - .setHttpHeaders("x-api-key: xyz123, Content-Type: application/json"); + .setEndpoint(URI.create("http://usersvc:9000/api/v1/users")) + .setHttpHeaders("x-api-key: xyz123, Content-Type: application/json") + .setCacheSize(123) + .setCacheTtl(new Duration(2, TimeUnit.MINUTES)); assertFullMapping(properties, expected); } + @Test + public void testConfigDefaults() + { + assertRecordedDefaults(recordDefaults(HttpCredentialsProviderConfig.class) + .setEndpoint(null) + .setHttpHeaders("") + .setCacheSize(0) + .setCacheTtl(Duration.ZERO)); + } + @Test public void testValidHttpHeaderVariation1() { HttpCredentialsProviderConfig config = new HttpCredentialsProviderConfig() - .setEndpoint("http://usersvc:9000/api/v1/users") + .setEndpoint(URI.create("http://usersvc:9000/api/v1/users")) .setHttpHeaders("x-api-key: Authorization: xyz123"); Map httpHeaders = config.getHttpHeaders(); assertThat(httpHeaders.get("x-api-key")).isEqualTo("Authorization: xyz123"); @@ -50,7 +70,7 @@ public void testValidHttpHeaderVariation1() public void testValidHttpHeaderVariation2() { HttpCredentialsProviderConfig config = new HttpCredentialsProviderConfig() - .setEndpoint("http://usersvc:9000/api/v1/users") + .setEndpoint(URI.create("http://usersvc:9000/api/v1/users")) .setHttpHeaders("x-api-key: xyz,,123, Authorization: key,,,,123"); Map httpHeaders = config.getHttpHeaders(); assertThat(httpHeaders.get("x-api-key")).isEqualTo("xyz,123"); @@ -61,7 +81,7 @@ public void testValidHttpHeaderVariation2() public void testIncorrectHttpHeader1() { assertThrows(IllegalArgumentException.class, () -> new HttpCredentialsProviderConfig() - .setEndpoint("http://usersvc:9000/api/v1/users") + .setEndpoint(URI.create("http://usersvc:9000/api/v1/users")) .setHttpHeaders("malformed-header")); } @@ -69,7 +89,7 @@ public void testIncorrectHttpHeader1() public void testIncorrectHttpHeader2() { assertThrows(IllegalArgumentException.class, () -> new HttpCredentialsProviderConfig() - .setEndpoint("http://usersvc:9000/api/v1/users") + .setEndpoint(URI.create("http://usersvc:9000/api/v1/users")) .setHttpHeaders("x-api-key: xyz,,,123, Authorization: key123")); } }