How do I add new dependencies to the keycloak codebase?

I am modifying the Keycloak codebase (https://github.com/keycloak/keycloak) to include a use case that I need (decrypt JWE when during Identity Brokering).

To decrypt a JWE, I added a dependency for com.nimbusds.nimbus-jose-jwt:
In the keycloak-parent/pom.xml, I added the dependency and the version

<properties>
...
  <nimbus-jose-jwt.version>5.7</nimbus-jose-jwt.version>
...
</properties>
...
<dependencyManagement>
  <dependencies>
  ...
    <dependency>
       <groupId>com.nimbusds</groupId>
       <artifactId>nimbus-jose-jwt</artifactId>
       <version>${nimbus-jose-jwt.version}</version>
    </dependency>
  ...
  </dependencies>
</dependencyManagement>

In the keycloak-services/pom.xml, I added the dependency

<dependency>
  <groupId>com.nimbusds</groupId>
  <artifactId>nimbus-jose-jwt</artifactId>
</dependency>

I also added a new function called “getDecryptedToken” to keycloak-services/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java

I then ran this command to build

mvn -Pdistribution -pl distribution/server-dist -am -Dmaven.test.skip clean install

With this build, I get the following exception when I clicked on the external provider link when clicking on the link to an external identity provider. I am very puzzled as to why this is happening as I have already added the dependency in the keycloak-services/pom.xml.

8:32:42,663 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (default task-7) Uncaught server error: java.lang.NoClassDefFoundError: com/nimbusds/jose/JOSEException
	at org.keycloak.keycloak-services@10.0.2//org.keycloak.broker.oidc.OIDCIdentityProviderFactory.create(OIDCIdentityProviderFactory.java:43)
	at org.keycloak.keycloak-services@10.0.2//org.keycloak.broker.oidc.OIDCIdentityProviderFactory.create(OIDCIdentityProviderFactory.java:32)
	at org.keycloak.keycloak-services@10.0.2//org.keycloak.services.resources.IdentityBrokerService.performLogin(IdentityBrokerService.java:390)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:567)
	at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final//org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:138)
	at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final//org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:535)
	at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final//org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:424)
	at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final//org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$0(ResourceMethodInvoker.java:385)
	at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final//org.jboss.resteasy.core.interception.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:356)
	at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final//org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:387)
	at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final//org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:356)
	at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final//org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:150)
	at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final//org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:104)
	at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final//org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:440)
	at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final//org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:229)
	at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final//org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:135)
	at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final//org.jboss.resteasy.core.interception.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:356)
	at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final//org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:138)
	at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final//org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:215)
	at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final//org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:227)
	at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final//org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56)
	at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final//org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51)
	at javax.servlet.api@2.0.0.Final//javax.servlet.http.HttpServlet.service(HttpServlet.java:590)
	at io.undertow.servlet@2.1.0.Final//io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
	at io.undertow.servlet@2.1.0.Final//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
	at org.keycloak.keycloak-services@10.0.2//org.keycloak.services.filters.KeycloakSessionServletFilter.doFilter(KeycloakSessionServletFilter.java:91)
	at io.undertow.servlet@2.1.0.Final//io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
	at io.undertow.servlet@2.1.0.Final//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
	at io.undertow.servlet@2.1.0.Final//io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
	at io.undertow.servlet@2.1.0.Final//io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
	at io.undertow.servlet@2.1.0.Final//io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
	at io.undertow.servlet@2.1.0.Final//io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
	at org.wildfly.extension.undertow@19.1.0.Final//org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
	at io.undertow.core@2.1.0.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at io.undertow.servlet@2.1.0.Final//io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
	at io.undertow.servlet@2.1.0.Final//io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:132)
	at io.undertow.servlet@2.1.0.Final//io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
	at io.undertow.core@2.1.0.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at io.undertow.core@2.1.0.Final//io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
	at io.undertow.servlet@2.1.0.Final//io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
	at io.undertow.core@2.1.0.Final//io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
	at io.undertow.servlet@2.1.0.Final//io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
	at io.undertow.core@2.1.0.Final//io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
	at io.undertow.core@2.1.0.Final//io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
	at io.undertow.core@2.1.0.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at org.wildfly.extension.undertow@19.1.0.Final//org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
	at io.undertow.core@2.1.0.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at org.wildfly.extension.undertow@19.1.0.Final//org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:68)
	at io.undertow.core@2.1.0.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at io.undertow.servlet@2.1.0.Final//io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:269)
	at io.undertow.servlet@2.1.0.Final//io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:78)
	at io.undertow.servlet@2.1.0.Final//io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:133)
	at io.undertow.servlet@2.1.0.Final//io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:130)
	at io.undertow.servlet@2.1.0.Final//io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
	at io.undertow.servlet@2.1.0.Final//io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
	at org.wildfly.extension.undertow@19.1.0.Final//org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction.lambda$create$0(SecurityContextThreadSetupAction.java:105)
	at org.wildfly.extension.undertow@19.1.0.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1541)
	at org.wildfly.extension.undertow@19.1.0.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1541)
	at org.wildfly.extension.undertow@19.1.0.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1541)
	at org.wildfly.extension.undertow@19.1.0.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1541)
	at io.undertow.servlet@2.1.0.Final//io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:249)
	at io.undertow.servlet@2.1.0.Final//io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:78)
	at io.undertow.servlet@2.1.0.Final//io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:99)
	at io.undertow.core@2.1.0.Final//io.undertow.server.Connectors.executeRootHandler(Connectors.java:370)
	at io.undertow.core@2.1.0.Final//io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
	at org.jboss.threads@2.3.3.Final//org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
	at org.jboss.threads@2.3.3.Final//org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1982)
	at org.jboss.threads@2.3.3.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1486)
	at org.jboss.threads@2.3.3.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1377)
	at java.base/java.lang.Thread.run(Thread.java:835)
Caused by: java.lang.ClassNotFoundException: com.nimbusds.jose.JOSEException from [Module "org.keycloak.keycloak-services" version 10.0.2 from local module loader @38aa816f (finder: local module finder @53f6fd09 (roots: /Users/dev/Documents/Github/keycloak/keycloak-10.0.2/modules,/Users/dev/Documents/Github/keycloak/keycloak-10.0.2/modules/system/layers/keycloak,/Users/dev/Documents/Github/keycloak/keycloak-10.0.2/modules/system/layers/base))]
	at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:255)
	at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:410)
	at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:398)
	at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:116)
	... 73 more
1 Like

If you look in the pom.xml there is an artifact with groupId : com.github.ua-parser
Do a search in the codebase for that groupId and you can see an example on how to add another dependency

2 Likes

I did a search for com.github.ua-parser and found 2 files that I was able to refer to as an example.

distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-spi-private/main/module.xml
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/com/github/ua-parser/main/module.xml

For module.xml in keycloak-server-spi-private, the step is to add " <module name= “com.github.ua-parser” export= “true” />"
But I don’t quite get what was done for “dependencies” in module.xml of com/github/ua-parser. How is the dependency “org.yaml.snakeyaml” derived?

<module xmlns="urn:jboss:module:1.3" name="com.github.ua-parser">
    <resources>
        <artifact name="${com.github.ua-parser:uap-java}"/>
    </resources>
    <dependencies>
        <module name="org.yaml.snakeyaml"/>
    </dependencies>
</module>

I went on to locate distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml and added com.nimbusds

<module name="sun.jdk"/>
<module name="com.webauthn4j.webauthn4j-core"/>
<module name="com.webauthn4j.webauthn4j-util"/>
<module name="javax.persistence.api"/>
<module name="com.nimbusds" export="true"/>

I have also created distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/com/nimbusds/main/module.xml, but I am not too sure what I should be adding to the dependencies.

<module xmlns="urn:jboss:module:1.3" name="com.nimbusds">
    <resources>
        <artifact name="${com.nimbusds:nimbus-jose-jwt}"/>
    </resources>
    <dependencies>
    </dependencies>
</module>

The pom for com.github.ua-parser seems to have a dependency on snakeyaml https://github.com/ua-parser/uap-java/blob/master/pom.xml
The other dependency org.apache.commons is already available as module sso that’s why it’s probably not included in the dependencies

So I assume that you need to declare all the dependencies that the nimbus pom has

2 Likes

I see. I have a much better idea of what needs to be done now. Thank you for explaining this to me!

Did you have any success with that approach? I’m trying to do something similar here with Gson:

   <module xmlns="urn:jboss:module:1.3" name="com.google.code.gson">
        <resources>
            <artifact name="${com.google.code.gson:gson}"/>
        </resources>
        <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
                <scope>test</scope>
              </dependency>
        </dependencies>
    </module>

at (…)com/google/gson/main/module.xml

and at (…)keycloak-services/main/module.xml
<module name="com.google.code.gson" export="true"/>

But it still doesn’t work…

Since Jackson is already available on Keycloak I just used it instead.

1 Like

Hello guys. When you connect your SPI with external lib, keycloak catch exception NoClassDefFoundError
You need to import that external lib jar file to keycloak like this:
./opt/jboss/keycloak/bin/jboss-cli.sh --command=“module add --name=org.slf4j.slf4j-api --resources=/home/app/dependencies/slf4j-api-1.7.30.jar”
And after that you need to create file jboss-deployment-structure.xml in \src\main\resources\META-INF
Inside of it:

Blockquote
<jboss-deployment-structure
<deployment
<dependencies
<module name=“org.slf4j.slf4j-api” /
</dependencies
</deployment
</jboss-deployment-structure

Set < in the end :smiley:
And of cource you need to import this lib to pom.xml

4 Likes

Thanks for the tip ArmanGhost! It’s a lot more manageable than what I’ve been doing.

1 Like