Skip to content

Commit

Permalink
Fix #824 - Introduce a separated OIDC module to hold security depende…
Browse files Browse the repository at this point in the history
…ncies (#872)

* Fix #824 - Introduce a separated OIDC module to hold security dependencies

Signed-off-by: Ricardo Zanini <[email protected]>

* Fix  parent module

Signed-off-by: Ricardo Zanini <[email protected]>

---------

Signed-off-by: Ricardo Zanini <[email protected]>
  • Loading branch information
ricardozanini authored Nov 27, 2024
1 parent e230b96 commit e5993bf
Show file tree
Hide file tree
Showing 21 changed files with 249 additions and 230 deletions.
5 changes: 5 additions & 0 deletions client/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@
<artifactId>quarkus-openapi-generator</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkiverse.openapi.generator</groupId>
<artifactId>quarkus-openapi-generator-oidc</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Forces swagger-parser version to avoid conflict with Quarkus.
This is needed while org.openapitools:openapi-generator doesn't use swagger-parser 2.1.13 or greater -->
<dependency>
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@
import io.quarkiverse.openapi.generator.markers.ApiKeyAuthenticationMarker;
import io.quarkiverse.openapi.generator.markers.BasicAuthenticationMarker;
import io.quarkiverse.openapi.generator.markers.OauthAuthenticationMarker;
import io.quarkiverse.openapi.generator.oidc.providers.OAuth2AuthenticationProvider;
import io.quarkiverse.openapi.generator.providers.ApiKeyAuthenticationProvider;
import io.quarkiverse.openapi.generator.providers.AuthProvider;
import io.quarkiverse.openapi.generator.providers.BasicAuthenticationProvider;
import io.quarkiverse.openapi.generator.providers.CompositeAuthenticationProvider;
import io.quarkiverse.openapi.generator.providers.OAuth2AuthenticationProvider;
import io.quarkus.test.QuarkusUnitTest;

public class OpenApiSpecProviderTest {
Expand Down
2 changes: 1 addition & 1 deletion client/integration-tests/enum-unexpected/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<modelVersion>4.0.0</modelVersion>

<artifactId>quarkus-openapi-generator-it-enum-unexpected</artifactId>
<name>Quarkus - Openapi Generator - Integration Tests - Enum Unexpected</name>
<name>Quarkus - Openapi Generator - Integration Tests - Client - Enum Unexpected</name>
<description>Example project for OpenAPI with enum unexpected value</description>

<dependencies>
Expand Down
2 changes: 1 addition & 1 deletion client/integration-tests/polymorphism/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<modelVersion>4.0.0</modelVersion>

<artifactId>quarkus-openapi-generator-it-polymorphism</artifactId>
<name>Quarkus - Openapi Generator - Integration Tests - Polymorphism</name>
<name>Quarkus - Openapi Generator - Integration Tests - Client - Polymorphism</name>

<dependencies>
<dependency>
Expand Down
17 changes: 5 additions & 12 deletions client/integration-tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@
<artifactId>quarkus-openapi-generator-it-generation-input</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkiverse.openapi.generator</groupId>
<artifactId>quarkus-openapi-generator-oidc</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<profiles>
Expand All @@ -68,14 +73,6 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-client-jackson</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-client-oidc-filter</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-multipart</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
Expand Down Expand Up @@ -103,10 +100,6 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-client-jackson</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-client-oidc-filter</artifactId>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
Expand Down
29 changes: 29 additions & 0 deletions client/integration-tests/security/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
<groupId>io.quarkiverse.openapi.generator</groupId>
<artifactId>quarkus-openapi-generator</artifactId>
</dependency>
<dependency>
<groupId>io.quarkiverse.openapi.generator</groupId>
<artifactId>quarkus-openapi-generator-oidc</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
Expand Down Expand Up @@ -91,5 +95,30 @@
<quarkus.package.type>native</quarkus.package.type>
</properties>
</profile>
<profile>
<id>resteasy-reactive</id>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-client-oidc-filter</artifactId>
</dependency>
</dependencies>
</profile>
<profile>
<id>resteasy-classic</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-client-oidc-filter</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-multipart</artifactId>
</dependency>
</dependencies>
</profile>
</profiles>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@

import jakarta.ws.rs.core.HttpHeaders;

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

import com.github.tomakehurst.wiremock.WireMockServer;

import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
Expand All @@ -25,18 +28,25 @@ 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";

private static final String BEARER = "Bearer ";

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);
private WireMockServer wireMockServer;

private static void stubForExternalService(String tokenPropagationExternalServiceUrl, String authorizationToken) {
stubFor(post(tokenPropagationExternalServiceUrl)
.withHeader(HttpHeaders.AUTHORIZATION, equalTo(BEARER + authorizationToken))
.willReturn(aResponse()
.withHeader(CONTENT_TYPE, APPLICATION_JSON)
.withBody("{}")));
}

@Override
public Map<String, String> start() {
wireMockServer = new WireMockServer(options().dynamicPort());
wireMockServer.start();
configureFor(wireMockServer.port());
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);
Expand All @@ -58,14 +68,6 @@ public Map<String, String> start() {
return Map.of(TOKEN_PROPAGATION_EXTERNAL_SERVICE_MOCK_URL, wireMockServer.baseUrl());
}

private static void stubForExternalService(String tokenPropagationExternalServiceUrl, String authorizationToken) {
stubFor(post(tokenPropagationExternalServiceUrl)
.withHeader(HttpHeaders.AUTHORIZATION, equalTo(BEARER + authorizationToken))
.willReturn(aResponse()
.withHeader(CONTENT_TYPE, APPLICATION_JSON)
.withBody("{}")));
}

@Override
public void stop() {
if (wireMockServer != null) {
Expand Down
5 changes: 2 additions & 3 deletions client/integration-tests/without-oidc/pom.xml
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>quarkus-openapi-generator-parent</artifactId>
<artifactId>quarkus-openapi-generator-integration-tests</artifactId>
<groupId>io.quarkiverse.openapi.generator</groupId>
<version>3.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand All @@ -19,7 +18,7 @@
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-client-jackson</artifactId>
<artifactId>quarkus-hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
quarkus.rest-client.quarkus_simple_openapi_yaml.url=http://localhost:8080

quarkus.keycloak.devservices.enabled=false
34 changes: 34 additions & 0 deletions client/oidc/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.quarkiverse.openapi.generator</groupId>
<artifactId>quarkus-openapi-generator-client-parent</artifactId>
<version>3.0.0-SNAPSHOT</version>
</parent>

<artifactId>quarkus-openapi-generator-oidc</artifactId>
<name>Quarkus - Openapi Generator - Client - OIDC</name>
<description>OIDC Capabilities for Runtime</description>

<dependencies>
<dependency>
<groupId>io.quarkiverse.openapi.generator</groupId>
<artifactId>quarkus-openapi-generator</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-client-oidc-filter</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-client-oidc-filter</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.quarkiverse.openapi.generator;
package io.quarkiverse.openapi.generator.oidc;

import java.io.IOException;

Expand All @@ -10,7 +10,9 @@

import org.jboss.logging.Logger;

import io.quarkiverse.openapi.generator.providers.OAuth2AuthenticationProvider;
import io.quarkiverse.openapi.generator.OidcClient;
import io.quarkiverse.openapi.generator.OpenApiGeneratorConfig;
import io.quarkiverse.openapi.generator.oidc.providers.OAuth2AuthenticationProvider;
import io.quarkus.oidc.client.runtime.AbstractTokensProducer;
import io.quarkus.oidc.client.runtime.DisabledOidcClientException;

Expand All @@ -19,15 +21,13 @@
public class ClassicOidcClientRequestFilterDelegate extends AbstractTokensProducer
implements ClientRequestFilter, OAuth2AuthenticationProvider.OidcClientRequestFilterDelegate {

private static final Logger LOG = Logger
.getLogger(ClassicOidcClientRequestFilterDelegate.class);
private static final Logger LOG = Logger.getLogger(ClassicOidcClientRequestFilterDelegate.class);

final String clientId;

ClassicOidcClientRequestFilterDelegate(InjectionPoint injectionPoint) {
OidcClient annotation = (OidcClient) injectionPoint.getQualifiers().stream()
.filter(x -> x.annotationType().equals(OidcClient.class))
.findFirst().orElseThrow();
.filter(x -> x.annotationType().equals(OidcClient.class)).findFirst().orElseThrow();

this.clientId = OpenApiGeneratorConfig.getSanitizedSecuritySchemeName(annotation.name());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package io.quarkiverse.openapi.generator.oidc;

import java.util.List;
import java.util.function.Function;

import io.quarkiverse.openapi.generator.AuthenticationRecorder;
import io.quarkiverse.openapi.generator.OidcClient;
import io.quarkiverse.openapi.generator.OpenApiGeneratorConfig;
import io.quarkiverse.openapi.generator.oidc.providers.OAuth2AuthenticationProvider;
import io.quarkiverse.openapi.generator.providers.AuthProvider;
import io.quarkiverse.openapi.generator.providers.OperationAuthInfo;
import io.quarkus.arc.SyntheticCreationalContext;
import io.quarkus.runtime.annotations.Recorder;

@Recorder
public class OidcAuthenticationRecorder {
private final OpenApiGeneratorConfig generatorConfig;

public OidcAuthenticationRecorder(OpenApiGeneratorConfig generatorConfig) {
this.generatorConfig = generatorConfig;
}

public Function<SyntheticCreationalContext<AuthProvider>, AuthProvider> recordOauthAuthProvider(
String name,
String openApiSpecId,
List<OperationAuthInfo> operations) {
return context -> new OAuth2AuthenticationProvider(
AuthenticationRecorder.getAuthConfig(generatorConfig, openApiSpecId, name), name, openApiSpecId,
context.getInjectedReference(OAuth2AuthenticationProvider.OidcClientRequestFilterDelegate.class,
new OidcClient.Literal(name)),
operations);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.quarkiverse.openapi.generator;
package io.quarkiverse.openapi.generator.oidc;

import java.io.IOException;
import java.util.function.Consumer;

import jakarta.annotation.Priority;
import jakarta.enterprise.inject.spi.InjectionPoint;
Expand All @@ -13,8 +12,9 @@
import org.jboss.resteasy.reactive.client.spi.ResteasyReactiveClientRequestContext;
import org.jboss.resteasy.reactive.client.spi.ResteasyReactiveClientRequestFilter;

import io.quarkiverse.openapi.generator.providers.OAuth2AuthenticationProvider;
import io.quarkus.oidc.client.Tokens;
import io.quarkiverse.openapi.generator.OidcClient;
import io.quarkiverse.openapi.generator.OpenApiGeneratorConfig;
import io.quarkiverse.openapi.generator.oidc.providers.OAuth2AuthenticationProvider;
import io.quarkus.oidc.client.runtime.AbstractTokensProducer;
import io.quarkus.oidc.client.runtime.DisabledOidcClientException;
import io.quarkus.oidc.common.runtime.OidcConstants;
Expand All @@ -24,16 +24,14 @@
public class ReactiveOidcClientRequestFilterDelegate extends AbstractTokensProducer
implements ResteasyReactiveClientRequestFilter, OAuth2AuthenticationProvider.OidcClientRequestFilterDelegate {

private static final Logger LOG = Logger
.getLogger(ReactiveOidcClientRequestFilterDelegate.class);
private static final Logger LOG = Logger.getLogger(ReactiveOidcClientRequestFilterDelegate.class);
private static final String BEARER_SCHEME_WITH_SPACE = OidcConstants.BEARER_SCHEME + " ";

final String clientId;

ReactiveOidcClientRequestFilterDelegate(InjectionPoint injectionPoint) {
OidcClient annotation = (OidcClient) injectionPoint.getQualifiers().stream()
.filter(x -> x.annotationType().equals(OidcClient.class))
.findFirst().orElseThrow();
.filter(x -> x.annotationType().equals(OidcClient.class)).findFirst().orElseThrow();
this.clientId = OpenApiGeneratorConfig.getSanitizedSecuritySchemeName(annotation.name());
}

Expand All @@ -58,23 +56,17 @@ public void filter(ClientRequestContext requestContext) throws IOException {
public void filter(ResteasyReactiveClientRequestContext requestContext) {
requestContext.suspend();

super.getTokens().subscribe().with(new Consumer<>() {
@Override
public void accept(Tokens tokens) {
requestContext.getHeaders().putSingle(HttpHeaders.AUTHORIZATION,
BEARER_SCHEME_WITH_SPACE + tokens.getAccessToken());
super.getTokens().subscribe().with(tokens -> {
requestContext.getHeaders().putSingle(HttpHeaders.AUTHORIZATION,
BEARER_SCHEME_WITH_SPACE + tokens.getAccessToken());
requestContext.resume();
}, t -> {
if (t instanceof DisabledOidcClientException) {
LOG.debug("Client is disabled, acquiring and propagating the token is not necessary");
requestContext.resume();
}
}, new Consumer<>() {
@Override
public void accept(Throwable t) {
if (t instanceof DisabledOidcClientException) {
LOG.debug("Client is disabled, acquiring and propagating the token is not necessary");
requestContext.resume();
} else {
LOG.debugf("Access token is not available, cause: %s, aborting the request", t.getMessage());
requestContext.resume((t instanceof RuntimeException) ? t : new RuntimeException(t));
}
} else {
LOG.debugf("Access token is not available, cause: %s, aborting the request", t.getMessage());
requestContext.resume((t instanceof RuntimeException) ? t : new RuntimeException(t));
}
});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.quarkiverse.openapi.generator.providers;
package io.quarkiverse.openapi.generator.oidc.providers;

import static io.quarkiverse.openapi.generator.AuthConfig.TOKEN_PROPAGATION;

Expand All @@ -12,6 +12,8 @@
import org.slf4j.LoggerFactory;

import io.quarkiverse.openapi.generator.AuthConfig;
import io.quarkiverse.openapi.generator.providers.AbstractAuthProvider;
import io.quarkiverse.openapi.generator.providers.OperationAuthInfo;
import io.quarkus.oidc.common.runtime.OidcConstants;

public class OAuth2AuthenticationProvider extends AbstractAuthProvider {
Expand Down
Loading

0 comments on commit e5993bf

Please sign in to comment.