I'm a couple of custom SPIs to Keycloak(6.0.1) and I need also to create a custom action token which will be sent to the user.
I've created a custom event listener, email sender, required action and deploy all these in a single jar.
When I'm trying to put the action token handler with proper manifest entries I get this
Caused by: java.lang.NoClassDefFoundError: Failed to link com/mycompany/providers/registration/actiontoken/Invitati
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1095)
at org.jboss.modules.ModuleClassLoader.doDefineOrLoadClass(ModuleClassLoader.java:424)
at org.jboss.modules.ModuleClassLoader.defineClass(ModuleClassLoader.java:555)
at org.jboss.modules.ModuleClassLoader.loadClassLocal(ModuleClassLoader.java:339)
at org.jboss.modules.ModuleClassLoader$1.loadClassLocal(ModuleClassLoader.java:126)
at org.jboss.modules.Module.loadModuleClass(Module.java:731)
at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:247)
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)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:398)
at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.nextProviderClass(ServiceLoader.java:1209)
at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNextService(ServiceLoader.java:1220)
at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNext(ServiceLoader.java:1264)
at java.base/java.util.ServiceLoader$2.hasNext(ServiceLoader.java:1299)
at java.base/java.util.ServiceLoader$3.hasNext(ServiceLoader.java:1384)
at [email protected]//org.keycloak.provider.DefaultProviderLoader.load(DefaultProviderLoader.java:60)
Definition of the handler
package com.mycompany.providers.registration.actiontoken;
import org.keycloak.TokenVerifier;
import
org.keycloak.authentication.actiontoken.AbstractActionTokenHander;
import org.keycloak.authentication.actiontoken.ActionTokenContext;
import org.keycloak.authentication.actiontoken.TokenUtils;
import org.keycloak.events.EventBuilder;
import org.keycloak.events.EventType;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.sessions.AuthenticationSessionModel;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
public class InvitationActionTokenHandler extends AbstractActionTokenHander<InvitationActionToken> {
public InvitationActionTokenHandler(String id, Class<InvitationActionToken> tokenClass, String defaultErrorMessage, EventType defaultEventType, String defaultEventError) {
super(id, tokenClass, defaultErrorMessage, defaultEventType, defaultEventError);
}
@Override
public Response handleToken(InvitationActionToken invitationActionToken, ActionTokenContext<InvitationActionToken> tokenContext) {
AuthenticationSessionModel authSession = tokenContext.getAuthenticationSession();
final UriInfo uriInfo = tokenContext.getUriInfo();
final RealmModel realm = tokenContext.getRealm();
EventBuilder event = tokenContext.getEvent();
final KeycloakSession session = tokenContext.getSession();
String nextAction = AuthenticationManager.nextRequiredAction(session, authSession, tokenContext.getClientConnection(), tokenContext.getRequest(), uriInfo, event);
return AuthenticationManager.redirectToRequiredActions(session, realm, authSession, uriInfo, nextAction);
}
@Override
public TokenVerifier.Predicate<? super InvitationActionToken>[] getVerifiers(ActionTokenContext<InvitationActionToken> tokenContext) {
return TokenUtils.predicates(
);
}
}
And the manifest in the file META-INF/services/org.keycloak.authentication.actiontoken.ActionTokenHandlerFactory
com.mycompany.providers.registration.actiontoken.InvitationActionTokenHandler
I've already added probably all dependencies which there are for Keycloak
apply plugin: 'java'
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
dependencies {
compileOnly group: 'org.keycloak', name: 'keycloak-model-jpa', version: '6.0.1'
compileOnly group: 'org.keycloak', name: 'keycloak-services', version: '6.0.1'
compileOnly group: 'org.keycloak', name: 'keycloak-server-spi', version: '6.0.1'
compileOnly group: 'org.keycloak', name: 'keycloak-server-spi-private', version: '6.0.1'
compileOnly group: 'org.keycloak', name: 'keycloak-core', version: '6.0.1'
compileOnly group: 'org.keycloak', name: 'keycloak-common', version: '6.0.1'
EDIT: updates
So I pinpointed that the class ActionTokenHandler is not available in the classpath, verified with this snippet in an SPI which is already working
try {
Class cls = Class.forName("org.keycloak.authentication.actiontoken.ActionTokenHandler");
} catch (ClassNotFoundException e) {
//is thrown always
e.printStackTrace();
}
I've changed my gradle dependencies to compileOnly to make sure no classpath issues would happen
You have to provide list of package dependencies to application server. Create jboss-deployment-structure.xml
in src/main/resources/META-INF
directory with the following content:
<jboss-deployment-structure>
<deployment>
<dependencies>
<module name="org.keycloak.keycloak-core" />
<module name="org.keycloak.keycloak-server-spi" />
<module name="org.keycloak.keycloak-server-spi-private" />
<module name="org.keycloak.keycloak-services" />
<module name="org.keycloak.keycloak-common" />
<module name="org.keycloak.keycloak-model-jpa" />
</dependencies>
</deployment>
</jboss-deployment-structure>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With