Skip to content
Closed
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 @@ -24,6 +24,12 @@ public class TokenPropagationResource {
@RestClient
org.acme.externalservice5.api.DefaultApi defaultApi5;

@RestClient
org.acme.externalservice6.api.DefaultApi defaultApi6;

@RestClient
org.acme.externalservice7.api.DefaultApi defaultApi7;

@POST
@Path("service1")
public Response service1() {
Expand Down Expand Up @@ -53,4 +59,16 @@ public Response service4() {
public Response service5() {
return defaultApi5.executeQuery5();
}

@POST
@Path("service6")
public Response service6() {
return defaultApi6.executeQuery6();
}

@POST
@Path("service7")
public Response service7() {
return defaultApi7.executeQuery7();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
openapi: 3.0.3
info:
title: token-propagation-external-service6-with-base-url API
version: 3.0.0-lts-SNAPSHOT
paths:
/token-propagation-external-service6-with-base-url/executeQuery6:
post:
operationId: executeQuery6
responses:
"200":
description: OK
security:
- service6-http-bearer: []
components:
securitySchemes:
service6-http-bearer:
type: http
scheme: bearer
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
openapi: 3.0.3
info:
title: token-propagation-external-service7-with-base-url API
version: 3.0.0-lts-SNAPSHOT
paths:
/token-propagation-external-service7-with-base-url/executeQuery7:
post:
operationId: executeQuery7
responses:
"200":
description: OK
security:
- service7-http-bearer: []
components:
securitySchemes:
service7-http-bearer:
type: http
scheme: bearer
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,17 @@ quarkus.openapi-generator.codegen.spec.token_propagation_external_service2_yaml.
quarkus.openapi-generator.codegen.spec.token_propagation_external_service3_yaml.base-package=org.acme.externalservice3
quarkus.openapi-generator.codegen.spec.token_propagation_external_service4_yaml.base-package=org.acme.externalservice4
quarkus.openapi-generator.codegen.spec.token_propagation_external_service5_yaml.base-package=org.acme.externalservice5
quarkus.openapi-generator.codegen.spec.token_propagation_external_service6_with_base_url_yaml.base-package=org.acme.externalservice6
quarkus.openapi-generator.codegen.spec.token_propagation_external_service7_with_base_url_yaml.base-package=org.acme.externalservice7

quarkus.rest-client.token_propagation_external_service1_yaml.url=${propagation-external-service-mock.url}
quarkus.rest-client.token_propagation_external_service2_yaml.url=${propagation-external-service-mock.url}
quarkus.rest-client.token_propagation_external_service3_yaml.url=${propagation-external-service-mock.url}
quarkus.rest-client.token_propagation_external_service4_yaml.url=${propagation-external-service-mock.url}
quarkus.rest-client.token_propagation_external_service5_yaml.url=${propagation-external-service-mock.url}
# service6 and service7 endpoints has the base url /external/api/v1
quarkus.rest-client.token_propagation_external_service6_with_base_url_yaml.url=${propagation-external-service-mock.url}/external/api/v1
quarkus.rest-client.token_propagation_external_service7_with_base_url_yaml.url=${propagation-external-service-mock.url}/external/api/v1

# default propagation for token_propagation_external_service1 invocation
quarkus.openapi-generator.token_propagation_external_service1_yaml.auth.service1_http_bearer.token-propagation=true
Expand All @@ -50,6 +55,13 @@ quarkus.openapi-generator.token_propagation_external_service3_yaml.auth.service3
quarkus.openapi-generator.token_propagation_external_service4_yaml.auth.service4_oauth2.token-propagation=true
quarkus.openapi-generator.token_propagation_external_service4_yaml.auth.service4_oauth2.header-name=SERVICE4_HEADER_TO_PROPAGATE

# default propagation for token_propagation_external_service6_with_base_url invocation
quarkus.openapi-generator.token_propagation_external_service6_with_base_url_yaml.auth.service6_http_bearer.token-propagation=true

# propagate the token coming in the header SERVICE7_HEADER_TO_PROPAGATE for token_propagation_external_service7_with_base_url invocation
quarkus.openapi-generator.token_propagation_external_service7_with_base_url_yaml.auth.service7_http_bearer.token-propagation=true
quarkus.openapi-generator.token_propagation_external_service7_with_base_url_yaml.auth.service7_http_bearer.header-name=SERVICE7_HEADER_TO_PROPAGATE

# Oidc clients for the services that has oauth2 security.
# Oidc client used by the token_propagation_external_service2
quarkus.oidc-client.service2_oauth2.auth-server-url=${keycloak.mock.service.url}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ public class TokenPropagationExternalServicesMock implements QuarkusTestResource
public static final String SERVICE3_AUTHORIZATION_TOKEN = "SERVICE3_AUTHORIZATION_TOKEN";
public static final String SERVICE4_HEADER_TO_PROPAGATE = "SERVICE4_HEADER_TO_PROPAGATE";
public static final String SERVICE4_AUTHORIZATION_TOKEN = "SERVICE4_AUTHORIZATION_TOKEN";
public static final String SERVICE6_AUTHORIZATION_TOKEN = "SERVICE6_AUTHORIZATION_TOKEN";
public static final String SERVICE7_HEADER_TO_PROPAGATE = "SERVICE7_HEADER_TO_PROPAGATE";
public static final String SERVICE7_AUTHORIZATION_TOKEN = "SERVICE7_AUTHORIZATION_TOKEN";
public static final String TOKEN_PROPAGATION_EXTERNAL_SERVICE_MOCK_URL = "propagation-external-service-mock.url";
private static final String BEARER = "Bearer ";
private static final Logger LOGGER = LoggerFactory.getLogger(TokenPropagationExternalServicesMock.class);
Expand Down Expand Up @@ -66,6 +69,14 @@ public Map<String, String> start() {
// configured.
stubForExternalService("/token-propagation-external-service5/executeQuery5", KEYCLOAK_ACCESS_TOKEN);

// stub the token-propagation-external-service6-with-base-url invocation with the expected token, emulate also the endpoint base url /external/api/v1
stubForExternalService("/external/api/v1/token-propagation-external-service6-with-base-url/executeQuery6",
SERVICE6_AUTHORIZATION_TOKEN);

// stub the token-propagation-external-service7-with-base-url invocation with the expected token, emulate also the endpoint base url /external/api/v1
stubForExternalService("/external/api/v1/token-propagation-external-service7-with-base-url/executeQuery7",
SERVICE7_AUTHORIZATION_TOKEN);

return Map.of(TOKEN_PROPAGATION_EXTERNAL_SERVICE_MOCK_URL, wireMockServer.baseUrl());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
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.quarkiverse.openapi.generator.it.security.TokenPropagationExternalServicesMock.SERVICE6_AUTHORIZATION_TOKEN;
import static io.quarkiverse.openapi.generator.it.security.TokenPropagationExternalServicesMock.SERVICE7_AUTHORIZATION_TOKEN;
import static io.quarkiverse.openapi.generator.it.security.TokenPropagationExternalServicesMock.SERVICE7_HEADER_TO_PROPAGATE;
import static io.restassured.RestAssured.given;

import java.util.Collections;
Expand Down Expand Up @@ -63,8 +66,10 @@ private static Stream<Arguments> serviceInvocationParams() {
// 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))

);
Arguments.of("service4", new HeaderArgument(SERVICE4_HEADER_TO_PROPAGATE, SERVICE4_AUTHORIZATION_TOKEN)),
// service token-propagation-external-service6-with-base-url will receive the SERVICE6_AUTHORIZATION_TOKEN
Arguments.of("service6", new HeaderArgument(HttpHeaders.AUTHORIZATION, SERVICE6_AUTHORIZATION_TOKEN)),
// service token-propagation-external-service7-with-base-url will receive the SERVICE7_AUTHORIZATION_TOKEN
Arguments.of("service7", new HeaderArgument(SERVICE7_HEADER_TO_PROPAGATE, SERVICE7_AUTHORIZATION_TOKEN)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
import static io.quarkiverse.openapi.generator.providers.AbstractAuthenticationPropagationHeadersFactory.propagationHeaderNamePrefix;

import java.io.IOException;
import java.net.URI;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import jakarta.ws.rs.client.ClientRequestContext;
import jakarta.ws.rs.client.ClientRequestFilter;

import org.eclipse.microprofile.config.ConfigProvider;

import io.quarkiverse.openapi.generator.OpenApiGeneratorConfig;

/**
Expand Down Expand Up @@ -47,9 +50,53 @@ public void filter(ClientRequestContext requestContext) throws IOException {
* It can perform the authentication filter only if this operation requires it (has a security reference)
*/
private boolean canFilter(final AuthProvider authProvider, final ClientRequestContext requestContext) {
String sanitizedPath = sanitizePath(authProvider, requestContext.getUri());
return authProvider.operationsToFilter().stream()
.anyMatch(o -> o.getHttpMethod().equals(requestContext.getMethod()) &&
o.matchPath(requestContext.getUri().getPath()));
o.matchPath(sanitizedPath));
}

/**
* Calculates the path to realize the matching with the OpenAPI operations, considering that the Quarkus client is
* configured with a URI that refers to the OpenAPI service endpoint. e.g.:
*
* In the OpenAPI document below the service endpoint is: http://https://development.gigantic-server.com/v1,
*
* openapi: 3.0.3
* servers:
* - url: https://development.gigantic-server.com/v1
* description: Development server
* ...
* paths:
* /some-operation:
* post:
* operationId: SomeOperation
* ...
*
* And thus, the Quarkus client must be configured like this:
* quarkus.rest-client.example-auth_yaml.url=https://development.gigantic-server.com/v1
*
* @param authProvider authentication provider to realize the matching with.
* @param requestUri the request url to invoke, e.g. https://development.gigantic-server.com/v1/some-operation
* @return The sanitized path to realize the matching with the OpenApi operations path, following the example above
* must be: /some-operation
*/
protected String sanitizePath(AuthProvider authProvider, URI requestUri) {
String basePath = getRestClientURLConfig(authProvider).getPath();
basePath = basePath.endsWith("/") ? basePath.substring(0, basePath.length() - 1) : basePath;
String requestPath = requestUri.getPath();
if (!basePath.isEmpty() && requestPath.startsWith(basePath)) {
return requestPath.substring(basePath.length());
}
return requestPath;
}

protected URI getRestClientURLConfig(AuthProvider authProvider) {
String openApiSpecId = ((AbstractAuthProvider) authProvider).getOpenApiSpecId();
String restClientProperty = String.format("quarkus.rest-client.%s.url", openApiSpecId);
return ConfigProvider.getConfig().getOptionalValue(restClientProperty, URI.class)
.orElseThrow(() -> new IllegalArgumentException(
"Required rest client property is not configured: " + restClientProperty));
}

protected static String sanitizeAuthName(String schemeName) {
Expand Down
Loading