Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Response;

import org.eclipse.microprofile.rest.client.inject.RestClient;

Expand All @@ -25,36 +26,31 @@ public class TokenPropagationResource {

@POST
@Path("service1")
public String service1() {
defaultApi1.executeQuery1();
return "hello";
public Response service1() {
return defaultApi1.executeQuery1();
}

@POST
@Path("service2")
public String service2() {
defaultApi2.executeQuery2();
return "hello";
public Response service2() {
return defaultApi2.executeQuery2();
}

@POST
@Path("service3")
public String service3() {
defaultApi3.executeQuery3();
return "hello";
public Response service3() {
return defaultApi3.executeQuery3();
}

@POST
@Path("service4")
public String service4() {
defaultApi4.executeQuery4();
return "hello";
public Response service4() {
return defaultApi4.executeQuery4();
}

@POST
@Path("service5")
public String service5() {
defaultApi5.executeQuery5();
return "hello";
public Response service5() {
return defaultApi5.executeQuery5();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@

public class TokenPropagationExternalServicesMock implements QuarkusTestResourceLifecycleManager {

public static final String AUTHORIZATION_TOKEN = "AUTHORIZATION_TOKEN";
public static final String SERVICE1_AUTHORIZATION_TOKEN = "SERVICE1_AUTHORIZATION_TOKEN";
public static final String SERVICE2_AUTHORIZATION_TOKEN = "SERVICE2_AUTHORIZATION_TOKEN";
public static final String SERVICE3_HEADER_TO_PROPAGATE = "SERVICE3_HEADER_TO_PROPAGATE";
public static final String SERVICE3_AUTHORIZATION_TOKEN = "SERVICE3_AUTHORIZATION_TOKEN";
public static final String SERVICE4_HEADER_TO_PROPAGATE = "SERVICE4_HEADER_TO_PROPAGATE";
Expand All @@ -49,10 +50,10 @@ public Map<String, String> start() {
LOGGER.info("Mocked Server started at {}", wireMockServer.baseUrl());

// stub the token-propagation-external-service1 invocation with the expected token
stubForExternalService("/token-propagation-external-service1/executeQuery1", AUTHORIZATION_TOKEN);
stubForExternalService("/token-propagation-external-service1/executeQuery1", SERVICE1_AUTHORIZATION_TOKEN);

// stub the token-propagation-external-service2 invocation with the expected token
stubForExternalService("/token-propagation-external-service2/executeQuery2", AUTHORIZATION_TOKEN);
stubForExternalService("/token-propagation-external-service2/executeQuery2", SERVICE2_AUTHORIZATION_TOKEN);

// stub the token-propagation-external-service3 invocation with the expected token
stubForExternalService("/token-propagation-external-service3/executeQuery3", SERVICE3_AUTHORIZATION_TOKEN);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
package io.quarkiverse.openapi.generator.it.security;

import static io.quarkiverse.openapi.generator.it.security.TokenPropagationExternalServicesMock.AUTHORIZATION_TOKEN;
import static io.quarkiverse.openapi.generator.it.security.TokenPropagationExternalServicesMock.SERVICE1_AUTHORIZATION_TOKEN;
import static io.quarkiverse.openapi.generator.it.security.TokenPropagationExternalServicesMock.SERVICE2_AUTHORIZATION_TOKEN;
import static io.quarkiverse.openapi.generator.it.security.TokenPropagationExternalServicesMock.SERVICE3_AUTHORIZATION_TOKEN;
import static io.quarkiverse.openapi.generator.it.security.TokenPropagationExternalServicesMock.SERVICE3_HEADER_TO_PROPAGATE;
import static io.quarkiverse.openapi.generator.it.security.TokenPropagationExternalServicesMock.SERVICE4_AUTHORIZATION_TOKEN;
import static io.quarkiverse.openapi.generator.it.security.TokenPropagationExternalServicesMock.SERVICE4_HEADER_TO_PROPAGATE;
import static io.restassured.RestAssured.given;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

import jakarta.ws.rs.core.HttpHeaders;

import org.junit.jupiter.api.Tag;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.QuarkusTest;
Expand All @@ -26,21 +31,40 @@
@Tag("resteasy-classic")
class TokenPropagationTest {

@ParameterizedTest
@ValueSource(strings = { "service1", "service2", "service3", "service4", "service5" })
void service1(String service) {
Map<String, String> headers = new HashMap<>();
// service token-propagation-external-service1 and token-propagation-external-service2 will receive the AUTHORIZATION_TOKEN
headers.put(HttpHeaders.AUTHORIZATION, AUTHORIZATION_TOKEN);
// service token-propagation-external-service3 will receive the SERVICE3_AUTHORIZATION_TOKEN
headers.put(SERVICE3_HEADER_TO_PROPAGATE, SERVICE3_AUTHORIZATION_TOKEN);
// service token-propagation-external-service4 will receive the SERVICE4_AUTHORIZATION_TOKEN
headers.put(SERVICE4_HEADER_TO_PROPAGATE, SERVICE4_AUTHORIZATION_TOKEN);
private static class HeaderArgument {
String headerName;
String headerValue;

HeaderArgument(String headerName, String headerValue) {
this.headerName = headerName;
this.headerValue = headerValue;
}

}

@ParameterizedTest
@MethodSource("serviceInvocationParams")
void invokeService(String service, HeaderArgument headerArgument) {
Map<String, List<String>> headers = new HashMap<>();
headers.put(headerArgument.headerName, Collections.singletonList(headerArgument.headerValue));
given()
.headers(headers)
.post("/token_propagation/" + service)
.then()
.statusCode(200);
}

private static Stream<Arguments> serviceInvocationParams() {
return Stream.of(
// service token-propagation-external-service1 will receive the SERVICE1_AUTHORIZATION_TOKEN
Arguments.of("service1", new HeaderArgument(HttpHeaders.AUTHORIZATION, SERVICE1_AUTHORIZATION_TOKEN)),
// service token-propagation-external-service2 will receive the SERVICE2_AUTHORIZATION_TOKEN
Arguments.of("service2", new HeaderArgument(HttpHeaders.AUTHORIZATION, SERVICE2_AUTHORIZATION_TOKEN)),
// service token-propagation-external-service3 will receive the SERVICE3_AUTHORIZATION_TOKEN
Arguments.of("service3", new HeaderArgument(SERVICE3_HEADER_TO_PROPAGATE, SERVICE3_AUTHORIZATION_TOKEN)),
// service token-propagation-external-service4 will receive the SERVICE4_AUTHORIZATION_TOKEN
Arguments.of("service4", new HeaderArgument(SERVICE4_HEADER_TO_PROPAGATE, SERVICE4_AUTHORIZATION_TOKEN))

);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import java.util.List;

import jakarta.ws.rs.client.ClientRequestContext;
import jakarta.ws.rs.core.HttpHeaders;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -32,9 +31,13 @@ public OAuth2AuthenticationProvider(String name,
@Override
public void filter(ClientRequestContext requestContext) throws IOException {
if (isTokenPropagation()) {
String bearerToken = getTokenForPropagation(requestContext.getHeaders());
bearerToken = sanitizeBearerToken(bearerToken);
requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, OidcConstants.BEARER_SCHEME + " " + bearerToken);
String bearerToken = sanitizeBearerToken(getTokenForPropagation(requestContext.getHeaders()));
if (!isEmptyOrBlank(bearerToken)) {
addAuthorizationHeader(requestContext.getHeaders(), OidcConstants.BEARER_SCHEME + " " + bearerToken);
} else {
LOGGER.debug("No oauth2 bearer token was found to propagate for the security scheme: {}." +
" You must verify that the request header: {} is set.", getName(), getHeaderForPropagation());
}
} else {
delegate.filter(requestContext);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static io.quarkiverse.openapi.generator.providers.AbstractAuthenticationPropagationHeadersFactory.propagationHeaderName;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

Expand Down Expand Up @@ -66,9 +67,12 @@ public boolean isTokenPropagation() {
}

public String getTokenForPropagation(MultivaluedMap<String, Object> httpHeaders) {
String headerName = getHeaderName() != null ? getHeaderName() : HttpHeaders.AUTHORIZATION;
String propagatedHeaderName = propagationHeaderName(getOpenApiSpecId(), getName(), headerName);
return Objects.toString(httpHeaders.getFirst(propagatedHeaderName));
String propagatedHeaderName = propagationHeaderName(getOpenApiSpecId(), getName(), getHeaderForPropagation());
return Objects.toString(httpHeaders.getFirst(propagatedHeaderName), null);
}

public String getHeaderForPropagation() {
return getHeaderName() != null ? getHeaderName() : HttpHeaders.AUTHORIZATION;
}

public String getHeaderName() {
Expand All @@ -88,4 +92,12 @@ public final String getCanonicalAuthConfigPropertyName(String authPropertyName)
public static String getCanonicalAuthConfigPropertyName(String authPropertyName, String openApiSpecId, String authName) {
return String.format(CANONICAL_AUTH_CONFIG_PROPERTY_NAME, openApiSpecId, authName, authPropertyName);
}

protected void addAuthorizationHeader(MultivaluedMap<String, Object> headers, String value) {
headers.put(HttpHeaders.AUTHORIZATION, Collections.singletonList(value));
}

protected static boolean isEmptyOrBlank(String value) {
return value == null || value.isBlank();
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package io.quarkiverse.openapi.generator.providers;

import static io.quarkiverse.openapi.generator.providers.ConfigCredentialsProvider.PASSWORD;
import static io.quarkiverse.openapi.generator.providers.ConfigCredentialsProvider.USER_NAME;

import java.io.IOException;
import java.util.List;

import jakarta.ws.rs.client.ClientRequestContext;
import jakarta.ws.rs.core.HttpHeaders;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -44,10 +46,14 @@ public void filter(ClientRequestContext requestContext) throws IOException {
basicToken = sanitizeBasicToken(getTokenForPropagation(requestContext.getHeaders()));
}

if (!basicToken.isBlank()) {
requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION,
AuthUtils.basicAuthAccessToken(basicToken));
if (!isEmptyOrBlank(basicToken)) {
addAuthorizationHeader(requestContext.getHeaders(), AuthUtils.basicAuthAccessToken(basicToken));
} else {
LOGGER.debug("No basic authentication token was found for the security scheme: {}." +
" You must verify that the properties: {} and {} are properly configured, or the request header: {} is set when the token propagation is enabled.",
getName(), getCanonicalAuthConfigPropertyName(USER_NAME, getOpenApiSpecId(), getName()),
getCanonicalAuthConfigPropertyName(PASSWORD, getOpenApiSpecId(), getName()),
getHeaderForPropagation());
}

}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package io.quarkiverse.openapi.generator.providers;

import static io.quarkiverse.openapi.generator.providers.ConfigCredentialsProvider.BEARER_TOKEN;

import java.io.IOException;
import java.util.List;

import jakarta.ws.rs.client.ClientRequestContext;
import jakarta.ws.rs.core.HttpHeaders;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Provides bearer token authentication or any other valid scheme.
Expand All @@ -13,6 +17,8 @@
*/
public class BearerAuthenticationProvider extends AbstractAuthProvider {

private static final Logger LOGGER = LoggerFactory.getLogger(BearerAuthenticationProvider.class);

private final String scheme;

public BearerAuthenticationProvider(final String openApiSpecId, final String name, final String scheme,
Expand All @@ -34,8 +40,13 @@ public void filter(ClientRequestContext requestContext) throws IOException {
bearerToken = sanitizeBearerToken(getTokenForPropagation(requestContext.getHeaders()));
}

if (!bearerToken.isBlank()) {
requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, AuthUtils.authTokenOrBearer(this.scheme, bearerToken));
if (!isEmptyOrBlank(bearerToken)) {
addAuthorizationHeader(requestContext.getHeaders(), AuthUtils.authTokenOrBearer(this.scheme, bearerToken));
} else {
LOGGER.debug("No bearer token was found for the security scheme: {}." +
" You must verify that the property: {} is properly configured, or the request header: {} is set when the token propagation is enabled.",
getName(), getCanonicalAuthConfigPropertyName(BEARER_TOKEN, getOpenApiSpecId(), getName()),
getHeaderForPropagation());
}
}

Expand Down