Story
I'm using keycloak 6.0.1. I have one realm with two types of users: Admins and regular users. I need a theme that can distinguish between them since the logins are different (3 fields vs 2 fields). Therefore I want to extend the provider FreeMarkerLoginFormsProvider to pass through a custom parameter. I'm using keycloak deployer to deploy my SPIs.
Problem
Keycloak unfortunately throws an exception while deployment:
09:55:32,170 ERROR [org.jboss.as.controller.management-operation] (DeploymentScanner-threads - 1) WFLYCTL0013: Operation ("full-replace-deployment") failed - address: ([]) - failure description: {"WFLYCTL0080: Failed services" => {"jboss.deployment.unit.\"spi-1.0.0.jar\".POST_MODULE" => "WFLYSRV0153: Failed to process phase POST_MODULE of deployment \"spi-1.0.0.jar\" Caused by: java.lang.NoClassDefFoundError: org/keycloak/theme/FreeMarkerUtil Caused by: java.lang.ClassNotFoundException: org.keycloak.theme.FreeMarkerUtil from [Module \"deployment.spi-1.0.0.jar\" from Service Module Loader]"}} 09:55:32,165 ERROR [org.jboss.msc.service.fail] (MSC service thread 1-3) MSC000001: Failed to start service jboss.deployment.unit."spi-1.0.0.jar".POST_MODULE: org.jboss.msc.service.StartException in service jboss.deployment.unit."spi-1.0.0.jar".POST_MODULE: WFLYSRV0153: Failed to process phase POST_MODULE of deployment "spi-1.0.0.jar" at org.jboss.as.server@8.0.0.Final//org.jboss.as.server.deployment.DeploymentUnitPhaseService.start(DeploymentUnitPhaseService.java:183) at org.jboss.msc@1.4.5.Final//org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:1738) at org.jboss.msc@1.4.5.Final//org.jboss.msc.service.ServiceControllerImpl$StartTask.execute(ServiceControllerImpl.java:1700) at org.jboss.msc@1.4.5.Final//org.jboss.msc.service.ServiceControllerImpl$ControllerTask.run(ServiceControllerImpl.java:1558) 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:834) Caused by: java.lang.NoClassDefFoundError: org/keycloak/theme/FreeMarkerUtil at deployment.spi-1.0.0.jar//com.example.keycloak.spi.CustomFreeMarkerLoginFormsProviderFactory.init(CustomFreeMarkerLoginFormsProviderFactory.java:23) at org.keycloak.keycloak-services@6.0.1//org.keycloak.services.DefaultKeycloakSessionFactory.loadFactories(DefaultKeycloakSessionFactory.java:217) at org.keycloak.keycloak-services@6.0.1//org.keycloak.services.DefaultKeycloakSessionFactory.deploy(DefaultKeycloakSessionFactory.java:115) at org.keycloak.keycloak-services@6.0.1//org.keycloak.provider.ProviderManagerRegistry.deploy(ProviderManagerRegistry.java:42) at org.keycloak.keycloak-wildfly-server-subsystem@6.0.1//org.keycloak.subsystem.server.extension.KeycloakProviderDeploymentProcessor.deploy(KeycloakProviderDeploymentProcessor.java:55) at org.jboss.as.server@8.0.0.Final//org.jboss.as.server.deployment.DeploymentUnitPhaseService.start(DeploymentUnitPhaseService.java:176) ... 8 more Caused by: java.lang.ClassNotFoundException: org.keycloak.theme.FreeMarkerUtil from [Module "deployment.spi-1.0.0.jar" from Service Module Loader] 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) ... 14 more
I've also tried the module approach but then I get a NullPointerException:
09:23:09,394 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (default task-1) Uncaught server error: java.lang.NullPointerException at org.keycloak.keycloak-services@6.0.1//org.keycloak.protocol.AuthorizationEndpointBase.createAuthenticationSession(AuthorizationEndpointBase.java:193) at org.keycloak.keycloak-services@6.0.1//org.keycloak.protocol.oidc.endpoints.AuthorizationEndpoint.process(AuthorizationEndpoint.java:141) at org.keycloak.keycloak-services@6.0.1//org.keycloak.protocol.oidc.endpoints.AuthorizationEndpoint.buildGet(AuthorizationEndpoint.java:108) 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:566) at org.jboss.resteasy.resteasy-jaxrs@3.6.3.Final//org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:139)...
I've been following the official docs. My other custom Pbkdf2PasswordHashProvider actually works just fine. Am I missing something here?
Source
import org.keycloak.forms.login.freemarker.FreeMarkerLoginFormsProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.theme.FreeMarkerUtil;
public class CustomFreeMarkerLoginFormsProvider extends FreeMarkerLoginFormsProvider {
public CustomFreeMarkerLoginFormsProvider(KeycloakSession session, FreeMarkerUtil freeMarker) {
super(session, freeMarker);
setAttribute("isAdmin", uriInfo.getPath().contains("admin"));
}
}