Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use keycloak-client libraries instead of keycloak-common, keycloak-core and keycloak-adapter-spi #43260

Merged
merged 2 commits into from
Dec 23, 2024
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
32 changes: 8 additions & 24 deletions bom/application/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@
<mockito.version>5.14.2</mockito.version>
<jna.version>5.8.0</jna.version><!-- should satisfy both testcontainers and mongodb -->
<quarkus-security.version>2.2.0</quarkus-security.version>
<keycloak.version>25.0.6</keycloak.version>
<keycloak-client.version>26.0.3</keycloak-client.version>
<logstash-gelf.version>1.15.1</logstash-gelf.version>
<checker-qual.version>3.48.3</checker-qual.version>
<error-prone-annotations.version>2.36.0</error-prone-annotations.version>
Expand Down Expand Up @@ -6110,41 +6110,25 @@
<version>${quarkus-spring-boot-api.version}</version>
</dependency>

<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<version>${keycloak.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-common</artifactId>
<version>${keycloak.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-admin-client</artifactId>
<version>${keycloak.version}</version>
<exclusions>
<exclusion>
<groupId>org.checkerframework</groupId>
<artifactId>checker-qual</artifactId>
</exclusion>
</exclusions>
<version>${keycloak-client.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-spi</artifactId>
<version>${keycloak.version}</version>
<artifactId>keycloak-authz-client</artifactId>
<version>${keycloak-client.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-client</artifactId>
<version>${keycloak.version}</version>
<artifactId>keycloak-policy-enforcer</artifactId>
<version>${keycloak-client.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-policy-enforcer</artifactId>
<version>${keycloak.version}</version>
<artifactId>keycloak-client-common-synced</artifactId>
<version>${keycloak-client.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
Expand Down
5 changes: 2 additions & 3 deletions build-parent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,9 @@
<junit4.version>4.13.2</junit4.version>

<!-- The image to use for tests that run Keycloak -->
<!-- IMPORTANT: If this is changed you must also update bom/application/pom.xml and KeycloakBuildTimeConfig/DevServicesConfig in quarkus-oidc/deployment to match the version -->
<keycloak.version>25.0.6</keycloak.version>
<keycloak.server.version>25.0.6</keycloak.server.version>
<keycloak.wildfly.version>19.0.3</keycloak.wildfly.version>
<keycloak.docker.image>quay.io/keycloak/keycloak:${keycloak.version}</keycloak.docker.image>
<keycloak.docker.image>quay.io/keycloak/keycloak:${keycloak.server.version}</keycloak.docker.image>
<keycloak.docker.legacy.image>quay.io/keycloak/keycloak:${keycloak.wildfly.version}-legacy</keycloak.docker.legacy.image>

<unboundid-ldap.version>7.0.2</unboundid-ldap.version>
Expand Down
8 changes: 1 addition & 7 deletions extensions/devservices/keycloak/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,7 @@
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<exclusions>
<exclusion>
<groupId>com.sun.activation</groupId>
<artifactId>jakarta.activation</artifactId>
</exclusion>
</exclusions>
<artifactId>keycloak-client-common-synced</artifactId>
pskopek marked this conversation as resolved.
Show resolved Hide resolved
</dependency>
</dependencies>
<build>
Expand Down
10 changes: 0 additions & 10 deletions extensions/keycloak-admin-rest-client/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,6 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-tls-registry</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<exclusions>
<exclusion>
<groupId>com.sun.activation</groupId>
<artifactId>jakarta.activation</artifactId>
</exclusion>
</exclusions>
</dependency>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here actually. We now have a dependency with the Apache HTTP Client and I don't think we want (except if I'm mistaken) that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gsmet This is a mistake at keycloak-client-common-synced side. I will fix it there and update this PR with new version of keycloak-client.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks I will have another look next week.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pskopek I think I misunderstood you. The issue is not fixed, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I released new version of keycloak-client (26.0.3) and updated the PR. It is fixed now.

<dependency>
<groupId>org.eclipse.angus</groupId>
<artifactId>angus-activation</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,25 @@

import javax.net.ssl.SSLContext;

import jakarta.enterprise.inject.Instance;
import jakarta.ws.rs.Priorities;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.MediaType;

import org.eclipse.microprofile.config.ConfigProvider;
import org.jboss.resteasy.reactive.client.TlsConfig;
import org.jboss.resteasy.reactive.client.api.ClientLogger;
import org.jboss.resteasy.reactive.client.impl.ClientBuilderImpl;
import org.jboss.resteasy.reactive.client.impl.WebTargetImpl;
import org.jboss.resteasy.reactive.server.jackson.JacksonBasicMessageBodyReader;
import org.keycloak.admin.client.spi.ResteasyClientProvider;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

import io.quarkus.arc.Arc;
import io.quarkus.arc.ArcContainer;
import io.quarkus.arc.InstanceHandle;
import io.quarkus.jackson.ObjectMapperCustomizer;
import io.quarkus.rest.client.reactive.jackson.runtime.serialisers.ClientJacksonMessageBodyWriter;
import io.quarkus.tls.TlsConfiguration;
import io.vertx.core.net.KeyCertOptions;
Expand Down Expand Up @@ -69,38 +68,13 @@ private ClientBuilderImpl registerJacksonProviders(ClientBuilderImpl clientBuild
if (arcContainer == null) {
throw new IllegalStateException(this.getClass().getName() + " should only be used in a Quarkus application");
} else {
InstanceHandle<ObjectMapper> objectMapperInstance = arcContainer.instance(ObjectMapper.class);
boolean canReuseObjectMapper = canReuseObjectMapper(objectMapperInstance, arcContainer);
if (canReuseObjectMapper) {

ObjectMapper objectMapper = null;

InstanceHandle<JacksonBasicMessageBodyReader> readerInstance = arcContainer
.instance(JacksonBasicMessageBodyReader.class);
if (readerInstance.isAvailable()) {
clientBuilder = clientBuilder.register(readerInstance.get());
} else {
objectMapper = getObjectMapper(objectMapper, objectMapperInstance);
clientBuilder = clientBuilder.register(new JacksonBasicMessageBodyReader(objectMapper));
}

InstanceHandle<ClientJacksonMessageBodyWriter> writerInstance = arcContainer
.instance(ClientJacksonMessageBodyWriter.class);
if (writerInstance.isAvailable()) {
clientBuilder = clientBuilder.register(writerInstance.get());
} else {
objectMapper = getObjectMapper(objectMapper, objectMapperInstance);
clientBuilder = clientBuilder.register(new ClientJacksonMessageBodyWriter(objectMapper));
}
} else {
ObjectMapper newObjectMapper = new ObjectMapper();
clientBuilder = clientBuilder
.registerMessageBodyReader(new JacksonBasicMessageBodyReader(newObjectMapper), Object.class,
HANDLED_MEDIA_TYPES, true,
READER_PROVIDER_PRIORITY)
.registerMessageBodyWriter(new ClientJacksonMessageBodyWriter(newObjectMapper), Object.class,
HANDLED_MEDIA_TYPES, true, WRITER_PROVIDER_PRIORITY);
}
ObjectMapper newObjectMapper = newKeycloakAdminClientObjectMapper();
clientBuilder = clientBuilder
.registerMessageBodyReader(new JacksonBasicMessageBodyReader(newObjectMapper), Object.class,
HANDLED_MEDIA_TYPES, true,
READER_PROVIDER_PRIORITY)
.registerMessageBodyWriter(new ClientJacksonMessageBodyWriter(newObjectMapper), Object.class,
HANDLED_MEDIA_TYPES, true, WRITER_PROVIDER_PRIORITY);
InstanceHandle<ClientLogger> clientLogger = arcContainer.instance(ClientLogger.class);
if (clientLogger.isAvailable()) {
clientBuilder.clientLogger(clientLogger.get());
Expand All @@ -109,36 +83,14 @@ private ClientBuilderImpl registerJacksonProviders(ClientBuilderImpl clientBuild
return clientBuilder;
}

// the idea is to only reuse the ObjectMapper if no known customizations would break Keycloak
// TODO: in the future we could also look into checking the ObjectMapper bean itself to see how it has been configured
private boolean canReuseObjectMapper(InstanceHandle<ObjectMapper> objectMapperInstance, ArcContainer arcContainer) {
if (objectMapperInstance.isAvailable() && !objectMapperInstance.getBean().isDefaultBean()) {
// in this case a user provided a completely custom ObjectMapper, so we can't use it
return false;
}

Instance<ObjectMapperCustomizer> customizers = arcContainer.beanManager().createInstance()
.select(ObjectMapperCustomizer.class);
if (!customizers.isUnsatisfied()) {
// ObjectMapperCustomizer can make arbitrary changes, so in order to be safe we won't allow reuse
return false;
}
// if any Jackson properties were configured, disallow reuse - this is done in order to provide forward compatibility with new Jackson configuration options
for (String propertyName : ConfigProvider.getConfig().getPropertyNames()) {
if (propertyName.startsWith("quarkus.jackson")) {
return false;
}
}
return true;
}

// the whole idea here is to reuse the ObjectMapper instance
private ObjectMapper getObjectMapper(ObjectMapper value,
InstanceHandle<ObjectMapper> objectMapperInstance) {
if (value == null) {
return objectMapperInstance.isAvailable() ? objectMapperInstance.get() : new ObjectMapper();
}
return value;
// creates new ObjectMapper compatible with Keycloak Admin Client
private ObjectMapper newKeycloakAdminClientObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
// Same like JSONSerialization class. Makes it possible to use admin-client against older versions of Keycloak server where the properties on representations might be different
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// The client must work with the newer versions of Keycloak server, which might contain the JSON fields not yet known by the client. So unknown fields will be ignored.
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return objectMapper;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@

import io.quarkus.arc.BeanDestroyer;
import io.quarkus.arc.deployment.SyntheticBeanBuildItem;
import io.quarkus.deployment.Capabilities;
import io.quarkus.deployment.Capability;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.ExecutionTime;
Expand Down Expand Up @@ -58,11 +56,8 @@ void avoidRuntimeInitIssueInClientBuilderWrapper(ResteasyKeycloakAdminClientReco
@Record(ExecutionTime.RUNTIME_INIT)
@Produce(ServiceStartBuildItem.class)
@BuildStep
public void integrate(ResteasyKeycloakAdminClientRecorder recorder, Capabilities capabilities,
TlsRegistryBuildItem tlsRegistryBuildItem) {
boolean areJSONBProvidersPresent = capabilities.isPresent(Capability.RESTEASY_JSON_JSONB)
|| capabilities.isPresent(Capability.RESTEASY_JSON_JSONB_CLIENT);
recorder.setClientProvider(areJSONBProvidersPresent, tlsRegistryBuildItem.registry());
public void integrate(ResteasyKeycloakAdminClientRecorder recorder, TlsRegistryBuildItem tlsRegistryBuildItem) {
recorder.setClientProvider(tlsRegistryBuildItem.registry());
}

@Record(ExecutionTime.RUNTIME_INIT)
Expand Down
10 changes: 0 additions & 10 deletions extensions/keycloak-admin-resteasy-client/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,6 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-client-jaxb</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<exclusions>
<exclusion>
<groupId>com.sun.activation</groupId>
<artifactId>jakarta.activation</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.eclipse.angus</groupId>
<artifactId>angus-activation</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
import org.keycloak.admin.client.KeycloakBuilder;
import org.keycloak.admin.client.spi.ResteasyClientProvider;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

import io.quarkus.keycloak.admin.client.common.KeycloakAdminClientConfig;
import io.quarkus.resteasy.common.runtime.jackson.QuarkusJacksonSerializer;
import io.quarkus.runtime.RuntimeValue;
Expand Down Expand Up @@ -66,7 +70,7 @@ public Keycloak get() {
};
}

public void setClientProvider(boolean areJSONBProvidersPresent, Supplier<TlsConfigurationRegistry> registrySupplier) {
public void setClientProvider(Supplier<TlsConfigurationRegistry> registrySupplier) {
var registry = registrySupplier.get();
var namedTlsConfig = TlsConfiguration.from(registry,
keycloakAdminClientConfigRuntimeValue.getValue().tlsConfigurationName()).orElse(null);
Expand Down Expand Up @@ -100,12 +104,10 @@ public Client newRestEasyClient(Object customJacksonProvider, SSLContext sslCont
}
}

// point here is to use default Quarkus providers rather than org.keycloak.admin.client.JacksonProvider
// as it doesn't work properly in native mode
if (areJSONBProvidersPresent) {
// when both Jackson and JSONB providers are present, we need to ensure Jackson is used
builder.register(new AppJsonQuarkusJacksonSerializer(), 100);
}
// this ensures we don't customize managed (shared) ObjectMapper available in the CDI container
// and that we use QuarkusJacksonSerializer that works in native mode
builder.register(new AppJsonQuarkusJacksonSerializer(), 100);

return builder.build();
}

Expand All @@ -126,6 +128,24 @@ public void avoidRuntimeInitIssueInClientBuilderWrapper() {
// makes media type more specific which ensures that it will be used first
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
static class AppJsonQuarkusJacksonSerializer extends QuarkusJacksonSerializer {
static final class AppJsonQuarkusJacksonSerializer extends QuarkusJacksonSerializer {

private final ObjectMapper objectMapper;

private AppJsonQuarkusJacksonSerializer() {
this.objectMapper = new ObjectMapper();
// Same like JSONSerialization class. Makes it possible to use admin-client against older
// versions of Keycloak server where the properties on representations might be different
this.objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// The client must work with the newer versions of Keycloak server, which might contain the JSON fields
// not yet known by the client. So unknown fields will be ignored.
this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Comment on lines +136 to +142
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm surprised to this both here and in ResteasyReactiveClientProvider.java. ObjectMapper is a really heavy object and reusing them should be done if possible.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@geoand I'll need bit more information. I'll try to answer your comment and please provide more context:

I'm surprised to this both here and in ResteasyReactiveClientProvider.java. ObjectMapper is a really heavy object and reusing them should be done if possible.

  1. They are 2 different extensions, considering they are just 3 lines, I repeated it instead of putting this method to some util in Keycloak Admin client common
  2. These 2 extensions are not going to be used together, so they can't share same ObjectMapper instance
  3. AFAICT this object mapper is stored on the provider level (at least in the RESTEasy Classic where I debugged it), so the method you are commenting on is called once per provider instance. If you think I should create it on startup and keep it in static variable, np, I'll do it
  4. we need different object mapper than is managed by Quarkus (instance in CDI) because these to options set here (include non-null, fail on unknown false) shouldn't be set for other REST clients or wherever is the ObjectMapper used
  5. I checked jacksonprovider that is part of the Keycloak here https://github.com/keycloak/keycloak/blob/main/integration/admin-client/src/main/java/org/keycloak/admin/client/JacksonProvider.java and it's basically c&p so I trust Keycloak folk know what they are doing with setting these 2 configuration properties

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These 2 extensions are not going to be used together, so they can't share same ObjectMapper instance

Okay, that settles it, thanks!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are not reusing an ObjectMapper we already have, shouldn't we let the Keycloak libraries instantiate and configure the ObjectMapper as they see fit?

Or do we absolutely need to pass one?

Copy link
Member

@michalvavrik michalvavrik Dec 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Experience is that Keycloaks provider wasn't native compatible in the past. What I did now was necessary in past (you can lookup issues, JSONB was one of them), but I don't know if it is still true, I think we have limited native test coverage for RESTEasy one. Does it matter?

Copy link
Member

@gsmet gsmet Dec 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it somehow matters given we had to tweak things to have a compatible client. And we're not entirely sure we enabled all the right options. It seems to work for now but what if they change the serialization options in the future?

Now maybe I'm being too cautious but that's something we could miss in the future. And if for instance, we don't serialize something correctly, it might end up having security consequences.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that if you're on PTO, this can wait early Janiuary :). I'm not on PTO so that's why you see me popping :).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it somehow matters given we had to tweak things to have a compatible client. And we're not entirely sure we enabled all the right options. It seems to work for now but what if they change the serialization options in the future?

note that this code came from @pskopek in the REST client version and I repeatedly asked him if it is fine to do that (not that I got satisfactory answer, this was only one - #43260 (comment)).

It seems to work for now but what if they change the serialization options in the future?
Now maybe I'm being too cautious but that's something we could miss in the future. And if for instance, we don't serialize something correctly, it might end up having security consequences.

  1. Absolutely, but we can't know and I asked repeatedly if it is fine. I agree with you. We have Keycloak folk integrating Keycloak admin client here, it can't get any better. Only thing we could do is to switch to the KC JacksonProvider in the RESTEasy one, but I am pretty sure we don't have test coverage for all the past native issues because there wasn't a good place to put them. I believe that Keycloak Admin REST Client is both tested in native and preferred.
  2. Even if we do that, we still have manually managed ObjectMapper in the REST admin client, so if we need to get it right there, why can't we use same code here?

Copy link
Member

@michalvavrik michalvavrik Dec 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now maybe I'm being too cautious but that's something we could miss in the future. And if for instance, we don't serialize something correctly, it might end up having security consequences.

I agree, but the situation in the reactive client is same, so I don't believe it would make a difference here. What would make a difference is Keycloak providing ObjectMapper factory we could re-use in both extensions. @pskopek WDYT? This way, Keycloak would be owner of the logic.

The idea that Keycloak client is compatible with both previous and future versions of Keycloak makes me nervous as I can't forsee if any incompatibility could result in a vulnerability, but I have already mentioned it before.

}

@Override
public ObjectMapper locateMapper(Class<?> type, MediaType mediaType) {
return objectMapper;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import org.keycloak.adapters.authorization.cip.spi.ClaimInformationPointProviderFactory;
import org.keycloak.authorization.client.representation.ServerConfiguration;
import org.keycloak.authorization.client.representation.TokenIntrospectionResponse;
import org.keycloak.authorization.client.util.crypto.AuthzClientCryptoProvider;
import org.keycloak.common.crypto.CryptoProvider;
import org.keycloak.jose.jwk.JSONWebKeySet;
import org.keycloak.jose.jwk.JWK;
import org.keycloak.jose.jws.JWSHeader;
Expand Down Expand Up @@ -78,6 +80,8 @@ public void registerServiceProviders(BuildProducer<ServiceProviderBuildItem> ser
serviceProvider.produce(new ServiceProviderBuildItem(ClaimInformationPointProviderFactory.class.getName(),
HttpClaimInformationPointProviderFactory.class.getName(),
ClaimsInformationPointProviderFactory.class.getName()));
serviceProvider.produce(new ServiceProviderBuildItem(CryptoProvider.class.getName(),
AuthzClientCryptoProvider.class.getName()));
}

@BuildStep
Expand Down
15 changes: 0 additions & 15 deletions extensions/keycloak-authorization/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,29 +22,14 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-tls-registry</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<exclusions>
<exclusion>
<groupId>com.sun.activation</groupId>
<artifactId>jakarta.activation</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-policy-enforcer</artifactId>
<version>${keycloak.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.angus</groupId>
<artifactId>angus-activation</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-spi</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-client</artifactId>
Expand Down
4 changes: 4 additions & 0 deletions extensions/oidc-client-reactive-filter/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
<exclusion>
<groupId>org.jboss.resteasy</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
Expand Down
Loading
Loading