diff --git a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/headers/UriUserInfoTest.java b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/headers/UriUserInfoTest.java new file mode 100644 index 0000000000000..63a52d6e85207 --- /dev/null +++ b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/headers/UriUserInfoTest.java @@ -0,0 +1,84 @@ +package io.quarkus.rest.client.reactive.headers; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.net.URI; +import java.util.Base64; + +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.Path; +import javax.ws.rs.core.UriBuilder; + +import org.eclipse.microprofile.rest.client.RestClientBuilder; +import org.eclipse.microprofile.rest.client.annotation.ClientHeaderParam; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.quarkus.test.common.http.TestHTTPResource; + +public class UriUserInfoTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar.addClasses(TestResource.class)); + + @TestHTTPResource + URI baseUri; + + @Test + void noUserInfo() { + Client client = RestClientBuilder.newBuilder().baseUri(baseUri).build(Client.class); + assertThat(client.call()).isNullOrEmpty(); + } + + @Test + void withUserInfo() { + Client client = RestClientBuilder.newBuilder().baseUri(UriBuilder.fromUri(baseUri).userInfo("foo:bar").build()) + .build(Client.class); + assertThat(client.call()).isEqualTo("foo:bar"); + } + + @Test + void userInfoOverridesClientHeaderParamAnnotation() { + Client client = RestClientBuilder.newBuilder().baseUri(UriBuilder.fromUri(baseUri).userInfo("foo:bar").build()) + .build(Client.class); + assertThat(client.call2()).isEqualTo("foo:bar"); + } + + @Test + void userInfoDoesNotOverrideHeaderParamAnnotation() { + Client client = RestClientBuilder.newBuilder().baseUri(UriBuilder.fromUri(baseUri).userInfo("foo:bar").build()) + .build(Client.class); + assertThat(client.call3("Basic " + Base64.getEncoder().encodeToString(("user:pass").getBytes()))) + .isEqualTo("user:pass"); + } + + @Path("/test") + public static class TestResource { + + @GET + @Path("/credentials") + public String credentials(@HeaderParam("Authorization") String authorization) { + if ((authorization == null) || authorization.isEmpty()) { + return null; + } + return new String(Base64.getDecoder().decode(authorization.substring("Basic ".length()))); + } + } + + @Path("/test/credentials") + public interface Client { + + @GET + String call(); + + @ClientHeaderParam(name = "Authorization", value = "whatever") + @GET + String call2(); + + @GET + String call3(@HeaderParam("Authorization") String authorization); + } +} diff --git a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/AsyncInvokerImpl.java b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/AsyncInvokerImpl.java index 64a44c7c08c48..8708360ffce7a 100644 --- a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/AsyncInvokerImpl.java +++ b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/AsyncInvokerImpl.java @@ -2,6 +2,7 @@ import java.lang.reflect.Type; import java.net.URI; +import java.util.Base64; import java.util.HashMap; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -14,6 +15,7 @@ import javax.ws.rs.client.Entity; import javax.ws.rs.client.InvocationCallback; import javax.ws.rs.core.GenericType; +import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.Response; import org.jboss.resteasy.reactive.RestResponse; @@ -45,12 +47,30 @@ public AsyncInvokerImpl(ClientImpl restClient, HttpClient httpClient, URI uri, R this.httpClient = httpClient; this.uri = uri; this.requestSpec = new RequestSpec(requestSpec); + addUserInfoIfNecessary(this.uri, this.requestSpec); this.configuration = configuration; this.properties = new HashMap<>(properties); this.handlerChain = handlerChain; this.requestContext = requestContext; } + private void addUserInfoIfNecessary(URI uri, RequestSpec requestSpec) { + String userInfo = uri.getUserInfo(); + if (userInfo == null) { + return; + } + String[] parts = userInfo.split(":"); + if (parts.length != 2) { + return; + } + ClientRequestHeaders specHeaders = requestSpec.headers; + String authorizationHeader = specHeaders.getHeader(HttpHeaders.AUTHORIZATION); + if (authorizationHeader == null) { + specHeaders.header(HttpHeaders.AUTHORIZATION, + "Basic " + Base64.getEncoder().encodeToString((parts[0] + ":" + parts[1]).getBytes())); + } + } + public Map getProperties() { return properties; }