Skip to content

Commit

Permalink
make composite authentication provider synthetic
Browse files Browse the repository at this point in the history
  • Loading branch information
rmanibus committed Sep 13, 2024
1 parent 3809339 commit 74a5b9b
Show file tree
Hide file tree
Showing 11 changed files with 157 additions and 160 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.quarkiverse.openapi.generator.deployment;

import io.quarkiverse.openapi.generator.providers.AuthProvider;
import io.quarkus.builder.item.MultiBuildItem;
import io.quarkus.runtime.RuntimeValue;

public final class AuthProviderBuildItem extends MultiBuildItem {

AuthProviderBuildItem(String openApiSpecId, RuntimeValue<AuthProvider> authProvider) {
this.openApiSpecId = openApiSpecId;
this.authProvider = authProvider;
}

final String openApiSpecId;
final RuntimeValue<AuthProvider> authProvider;

public RuntimeValue<AuthProvider> getAuthProvider() {
return authProvider;
}

public String getOpenApiSpecId() {
return openApiSpecId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import io.quarkus.deployment.annotations.Record;
import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
import io.quarkus.deployment.builditem.FeatureBuildItem;
import io.quarkus.runtime.RuntimeValue;

public class GeneratorProcessor {

Expand All @@ -38,11 +39,32 @@ FeatureBuildItem feature() {
return new FeatureBuildItem(FEATURE);
}

@BuildStep
@Record(ExecutionTime.STATIC_INIT)
void produceCompositeProviders(AuthenticationRecorder recorder,
List<AuthProviderBuildItem> authProviders,
BuildProducer<SyntheticBeanBuildItem> producer) {
Map<String, List<AuthProviderBuildItem>> providersBySpec = authProviders.stream()
.collect(Collectors.groupingBy(AuthProviderBuildItem::getOpenApiSpecId));
providersBySpec.forEach((openApiSpecId, providers) -> {
producer.produce(SyntheticBeanBuildItem.configure(CompositeAuthenticationProvider.class)
.scope(Dependent.class)
.addQualifier()
.annotation(Authentication.class)
.addValue("openApiSpecId", openApiSpecId)
.done()
.runtimeValue(recorder
.recordCompositeProvider(providers.stream().map(AuthProviderBuildItem::getAuthProvider).toList()))
.done());

});
}

@BuildStep
@Record(ExecutionTime.STATIC_INIT)
void produceOauthAuthentication(CombinedIndexBuildItem beanArchiveBuildItem,
Capabilities capabilities,
BuildProducer<SyntheticBeanBuildItem> producer,
BuildProducer<AuthProviderBuildItem> authenticationProviders,
AuthenticationRecorder recorder) {
Collection<AnnotationInstance> authenticationMarkers = beanArchiveBuildItem.getIndex()
.getAnnotations(OAUTH_AUTHENTICATION_MARKER);
Expand All @@ -56,29 +78,22 @@ void produceOauthAuthentication(CombinedIndexBuildItem beanArchiveBuildItem,

List<OperationAuthInfo> operations = getOperations(operationsBySpec, openApiSpecId, name);

producer.produce(SyntheticBeanBuildItem.configure(OAuth2AuthenticationProvider.class)
.scope(Dependent.class)
.addQualifier()
.annotation(Authentication.class)
.addValue("name", name)
.addValue("openApiSpecId", openApiSpecId)
.done()
.runtimeValue(recorder.recordOauthAuthProvider(
sanitizeAuthName(name),
openApiSpecId,
capabilities.isPresent(Capability.REST_CLIENT_REACTIVE)
? recorder.recordReactiveDelegate(sanitizeAuthName(name))
: recorder.recordClassicDelegate(sanitizeAuthName(name)),
operations))
.done());
}
RuntimeValue<AuthProvider> authProvider = recorder.recordOauthAuthProvider(
sanitizeAuthName(name),
openApiSpecId,
capabilities.isPresent(Capability.REST_CLIENT_REACTIVE)
? recorder.recordReactiveDelegate(sanitizeAuthName(name))
: recorder.recordClassicDelegate(sanitizeAuthName(name)),
operations);

authenticationProviders.produce(new AuthProviderBuildItem(openApiSpecId, authProvider));
}
}

@BuildStep
@Record(ExecutionTime.STATIC_INIT)
void produceBasicAuthentication(CombinedIndexBuildItem beanArchiveBuildItem,
BuildProducer<SyntheticBeanBuildItem> producer,
BuildProducer<AuthProviderBuildItem> authenticationProviders,
AuthenticationRecorder recorder) {

Collection<AnnotationInstance> authenticationMarkers = beanArchiveBuildItem.getIndex()
Expand All @@ -92,26 +107,19 @@ void produceBasicAuthentication(CombinedIndexBuildItem beanArchiveBuildItem,

List<OperationAuthInfo> operations = getOperations(operationsBySpec, openApiSpecId, name);

producer.produce(SyntheticBeanBuildItem.configure(BasicAuthenticationProvider.class)
.scope(Dependent.class)
.addQualifier()
.annotation(Authentication.class)
.addValue("name", name)
.addValue("openApiSpecId", openApiSpecId)
.done()
.createWith(recorder.recordBasicAuthProvider(
sanitizeAuthName(name),
openApiSpecId,
operations))
.done());
}
RuntimeValue<AuthProvider> authProvider = recorder.recordBasicAuthProvider(
sanitizeAuthName(name),
openApiSpecId,
operations);

authenticationProviders.produce(new AuthProviderBuildItem(openApiSpecId, authProvider));
}
}

@BuildStep
@Record(ExecutionTime.STATIC_INIT)
void produceBearerAuthentication(CombinedIndexBuildItem beanArchiveBuildItem,
BuildProducer<SyntheticBeanBuildItem> producer,
BuildProducer<AuthProviderBuildItem> authenticationProviders,
AuthenticationRecorder recorder) {

Collection<AnnotationInstance> authenticationMarkers = beanArchiveBuildItem.getIndex()
Expand All @@ -126,27 +134,20 @@ void produceBearerAuthentication(CombinedIndexBuildItem beanArchiveBuildItem,

List<OperationAuthInfo> operations = getOperations(operationsBySpec, openApiSpecId, name);

producer.produce(SyntheticBeanBuildItem.configure(BearerAuthenticationProvider.class)
.scope(Dependent.class)
.addQualifier()
.annotation(Authentication.class)
.addValue("name", name)
.addValue("openApiSpecId", openApiSpecId)
.done()
.createWith(recorder.recordBearerAuthProvider(
sanitizeAuthName(name),
scheme,
openApiSpecId,
operations))
.done());
}
RuntimeValue<AuthProvider> authProvider = recorder.recordBearerAuthProvider(
sanitizeAuthName(name),
scheme,
openApiSpecId,
operations);

authenticationProviders.produce(new AuthProviderBuildItem(openApiSpecId, authProvider));
}
}

@BuildStep
@Record(ExecutionTime.STATIC_INIT)
void produceApiKeyAuthentication(CombinedIndexBuildItem beanArchiveBuildItem,
BuildProducer<SyntheticBeanBuildItem> producer,
BuildProducer<AuthProviderBuildItem> authenticationProviders,
AuthenticationRecorder recorder) {

Collection<AnnotationInstance> authenticationMarkers = beanArchiveBuildItem.getIndex()
Expand All @@ -162,20 +163,14 @@ void produceApiKeyAuthentication(CombinedIndexBuildItem beanArchiveBuildItem,

List<OperationAuthInfo> operations = getOperations(operationsBySpec, openApiSpecId, name);

producer.produce(SyntheticBeanBuildItem.configure(ApiKeyAuthenticationProvider.class)
.scope(Dependent.class)
.addQualifier()
.annotation(Authentication.class)
.addValue("name", name)
.addValue("openApiSpecId", openApiSpecId)
.done()
.createWith(recorder.recordApiKeyAuthProvider(
sanitizeAuthName(name),
openApiSpecId,
apiKeyIn,
apiKeyName,
operations))
.done());
RuntimeValue<AuthProvider> authProvider = recorder.recordApiKeyAuthProvider(
sanitizeAuthName(name),
openApiSpecId,
apiKeyIn,
apiKeyName,
operations);

authenticationProviders.produce(new AuthProviderBuildItem(openApiSpecId, authProvider));
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,48 +19,14 @@ package {apiPackage}.auth;
@io.quarkiverse.openapi.generator.markers.ApiKeyAuthenticationMarker(name="{auth.name}", openApiSpecId="{quarkus-generator.openApiSpecId}", apiKeyIn=io.quarkiverse.openapi.generator.providers.ApiKeyIn.cookie, apiKeyName="{auth.keyParamName}")
{/if}
{/for}
public class CompositeAuthenticationProvider extends io.quarkiverse.openapi.generator.providers.AbstractCompositeAuthenticationProvider {
public class CompositeAuthenticationProvider implements jakarta.ws.rs.client.ClientRequestFilter {



@jakarta.inject.Inject
io.quarkiverse.openapi.generator.OpenApiGeneratorConfig generatorConfig;

{#for auth in oauthMethods.orEmpty}
@jakarta.inject.Inject
@io.quarkiverse.openapi.generator.Authentication(name="{auth.name}", openApiSpecId="{configKey}")
io.quarkiverse.openapi.generator.providers.OAuth2AuthenticationProvider oAuth2Provider{auth_index};
{/for}

{#for auth in httpBasicMethods.orEmpty}
@io.quarkiverse.openapi.generator.Authentication(name="{auth.name}", openApiSpecId="{quarkus-generator.openApiSpecId}")
io.quarkiverse.openapi.generator.providers.BasicAuthenticationProvider basicAuthProvider{auth_index};
{/for}

{#for auth in httpBearerMethods.orEmpty}
@io.quarkiverse.openapi.generator.Authentication(name="{auth.name}", openApiSpecId="{quarkus-generator.openApiSpecId}")
io.quarkiverse.openapi.generator.providers.BearerAuthenticationProvider bearerProvider{auth_index};
{/for}

{#for auth in apiKeyMethods.orEmpty}
@io.quarkiverse.openapi.generator.Authentication(name="{auth.name}", openApiSpecId="{quarkus-generator.openApiSpecId}")
io.quarkiverse.openapi.generator.providers.ApiKeyAuthenticationProvider apiKeyQueryProvider{auth_index};
{/for}

@io.quarkiverse.openapi.generator.Authentication(openApiSpecId="{configKey}")
io.quarkiverse.openapi.generator.providers.CompositeAuthenticationProvider compositeProvider;

@jakarta.annotation.PostConstruct
public void init() {
{#for auth in httpBasicMethods.orEmpty}
this.addAuthenticationProvider(basicAuthProvider{auth_index});
{/for}
{#for auth in oauthMethods.orEmpty}
this.addAuthenticationProvider(oAuth2Provider{auth_index});
{/for}
{#for auth in httpBearerMethods.orEmpty}
this.addAuthenticationProvider(bearerProvider{auth_index});
{/for}
{#for auth in apiKeyMethods.orEmpty}
this.addAuthenticationProvider(apiKeyQueryProvider{auth_index});
{/for}
}
@java.lang.Override
public void filter(jakarta.ws.rs.client.ClientRequestContext context) throws java.io.IOException {
compositeProvider.filter(context);
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package {apiPackage}.auth;
public class AuthenticationPropagationHeadersFactory extends io.quarkiverse.openapi.generator.providers.AbstractAuthenticationPropagationHeadersFactory {

@jakarta.inject.Inject
public AuthenticationPropagationHeadersFactory(CompositeAuthenticationProvider compositeProvider, io.quarkiverse.openapi.generator.OpenApiGeneratorConfig generatorConfig, io.quarkiverse.openapi.generator.providers.HeadersProvider headersProvider) {
public AuthenticationPropagationHeadersFactory(@io.quarkiverse.openapi.generator.Authentication(openApiSpecId="{configKey}") io.quarkiverse.openapi.generator.providers.CompositeAuthenticationProvider compositeProvider, io.quarkiverse.openapi.generator.OpenApiGeneratorConfig generatorConfig, io.quarkiverse.openapi.generator.providers.HeadersProvider headersProvider) {
super(compositeProvider, generatorConfig, headersProvider);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,46 +15,57 @@
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.providers.ApiKeyAuthenticationProvider;
import io.quarkiverse.openapi.generator.providers.BasicAuthenticationProvider;
import io.quarkiverse.openapi.generator.providers.OAuth2AuthenticationProvider;
import io.quarkiverse.openapi.generator.providers.*;
import io.quarkus.test.QuarkusUnitTest;

public class AuthenticationProviderTest {

@RegisterExtension
static final QuarkusUnitTest unitTest = new QuarkusUnitTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addClass(CompositeAuthenticationProvider.class)
.addClass(LocalAuthenticationProvider.class)
.addAsResource(
new StringAsset("\n"),
"application.properties"));

@Test
public void test() {
Assertions.assertEquals("petstore_auth", oAuth2Provider.getName());
Assertions.assertEquals("spec_1", oAuth2Provider.getOpenApiSpecId());
Assertions.assertEquals("basic_auth", basicAuthProvider.getName());
Assertions.assertEquals("spec_1", basicAuthProvider.getOpenApiSpecId());
Assertions.assertEquals("api_key", apiKeyQueryProvider.getName());
Assertions.assertEquals("spec_2", apiKeyQueryProvider.getOpenApiSpecId());
Assertions.assertEquals(1, spec1CompositeProvider.getAuthenticationProviders().size());
Assertions.assertEquals(1, spec2CompositeProvider.getAuthenticationProviders().size());
Assertions.assertEquals(1, spec3CompositeProvider.getAuthenticationProviders().size());

AuthProvider authProvider = spec1CompositeProvider.getAuthenticationProviders().get(0);
Assertions.assertInstanceOf(OAuth2AuthenticationProvider.class, authProvider);
Assertions.assertEquals("petstore_auth", authProvider.getName());
Assertions.assertEquals("spec_1", ((OAuth2AuthenticationProvider) authProvider).getOpenApiSpecId());

authProvider = spec2CompositeProvider.getAuthenticationProviders().get(0);
Assertions.assertInstanceOf(BasicAuthenticationProvider.class, authProvider);
Assertions.assertEquals("basic_auth", authProvider.getName());
Assertions.assertEquals("spec_2", ((BasicAuthenticationProvider) authProvider).getOpenApiSpecId());

authProvider = spec3CompositeProvider.getAuthenticationProviders().get(0);
Assertions.assertInstanceOf(ApiKeyAuthenticationProvider.class, authProvider);
Assertions.assertEquals("api_key", authProvider.getName());
Assertions.assertEquals("spec_3", ((ApiKeyAuthenticationProvider) authProvider).getOpenApiSpecId());

}

@Inject
@Authentication(name = "petstore_auth", openApiSpecId = "spec_1")
OAuth2AuthenticationProvider oAuth2Provider;
@Authentication(openApiSpecId = "spec_1")
CompositeAuthenticationProvider spec1CompositeProvider;

@Authentication(name = "basic_auth", openApiSpecId = "spec_1")
BasicAuthenticationProvider basicAuthProvider;
@Authentication(openApiSpecId = "spec_2")
CompositeAuthenticationProvider spec2CompositeProvider;

@Authentication(name = "api_key", openApiSpecId = "spec_2")
ApiKeyAuthenticationProvider apiKeyQueryProvider;
@Authentication(openApiSpecId = "spec_3")
CompositeAuthenticationProvider spec3CompositeProvider;

@jakarta.annotation.Priority(jakarta.ws.rs.Priorities.AUTHENTICATION)
@OauthAuthenticationMarker(name = "petstore_auth", openApiSpecId = "spec_1")
@BasicAuthenticationMarker(name = "basic_auth", openApiSpecId = "spec_1")
@ApiKeyAuthenticationMarker(name = "api_key", openApiSpecId = "spec_2", apiKeyIn = header, apiKeyName = "api_key")
public static class CompositeAuthenticationProvider {
@BasicAuthenticationMarker(name = "basic_auth", openApiSpecId = "spec_2")
@ApiKeyAuthenticationMarker(name = "api_key", openApiSpecId = "spec_3", apiKeyIn = header, apiKeyName = "api_key")
public static class LocalAuthenticationProvider {

}

Expand Down
Loading

0 comments on commit 74a5b9b

Please sign in to comment.