Search code examples
javajbosskeycloakkeycloak-services

Keycloak Provider not found


i got a Keycloak 4.2.1 Server and im trying to implement a custom "LoginFormsProvider" for it. My goal is to extend to the login page (freemarker) with an additional component, in my case a simple information box. The content of that box i would like to set in the Provider class.

I already have implement two other custom provider and they works fine (UserStorageProvider and EventListenerProvider). So my .jar file is found by the server.

But i have problems with the "LoginFormsProvider". The Server does not find the provider. See the stacktrace below...

I added a file "org.keycloak.login.LoginFormsProviderFactory" in the "META-INF/services" path with the package and class name, "de.test.login.TestLoginFactory" (without quotes).

Which leads to the Factory Class of my Provider. Like i did it for the other providers.

My FactoryClass looks like this:

package de.test.login;

import java.util.LinkedHashMap;
import java.util.Map;

import org.jboss.logging.Logger;
import org.keycloak.Config.Scope;
import org.keycloak.freemarker.FreeMarkerUtil;
import org.keycloak.login.LoginFormsProvider;
import org.keycloak.login.LoginFormsProviderFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.provider.ServerInfoAwareProviderFactory;

public class TestLoginFactory  implements  LoginFormsProviderFactory{

    private FreeMarkerUtil freeMarker;
    private final static String PROVIDER = "test-login-provider";

    @Override
    public LoginFormsProvider create(KeycloakSession session) {
        return new TestLoginProvider(session, freeMarker);
    }

    @Override
    public void init(Scope config) {        
        freeMarker = new FreeMarkerUtil();
    }

    @Override
    public void postInit(KeycloakSessionFactory factory) {
    }

    @Override
    public void close() {
        freeMarker = null;
    }

    @Override
    public String getId() {
        return PROVIDER;
    }

}

Here the Provider class:

package de.test.login;

import javax.ws.rs.core.Response;

import org.jboss.logging.Logger;
import org.keycloak.freemarker.FreeMarkerUtil;
import org.keycloak.login.freemarker.FreeMarkerLoginFormsProvider;
import org.keycloak.models.KeycloakSession;

public class TestLoginProvider extends FreeMarkerLoginFormsProvider{

    final private Logger logger = Logger.getLogger(this.getClass());

    public TestLoginProvider(KeycloakSession session, FreeMarkerUtil freeMarker) {
        super(session, freeMarker);
    }

    @Override
    public Response createLogin(){
        logger.info("do crazy stuff");
        Response response = super.createLogin();
        return response;        
    }       
}

In my standalone.xml i added a spi declaration near by the other spi declarations.

<spi name="login">
    <default-provider>test-login-provider</default-provider>
</spi>

Here the complete section of the standalone.xml:

...
    <subsystem xmlns="urn:jboss:domain:keycloak-server:1.1">
        <web-context>auth</web-context>
        <providers>
            <provider>
                classpath:${jboss.home.dir}/providers/*                 
            </provider>
        </providers>
        <master-realm-name>master</master-realm-name>
        <scheduled-task-interval>900</scheduled-task-interval>
        <theme>
            <staticMaxAge>2592000</staticMaxAge>
            <cacheThemes>true</cacheThemes>
            <cacheTemplates>true</cacheTemplates>
            <dir>${jboss.home.dir}/themes</dir>
        </theme>
        <spi name="eventsStore">
            <provider name="jpa" enabled="true">
                <properties>
                    <property name="exclude-events" value="[&quot;REFRESH_TOKEN&quot;]"/>
                </properties>
            </provider>
        </spi>
        <spi name="userCache">
            <provider name="default" enabled="true"/>
        </spi>
        <spi name="userSessionPersister">
            <default-provider>jpa</default-provider>
        </spi>
        <spi name="timer">
            <default-provider>basic</default-provider>
        </spi>
        <spi name="login">
            <default-provider>test-login-provider</default-provider>
        </spi>      
        <spi name="connectionsHttpClient">
            <provider name="default" enabled="true"/>
        </spi>
        <spi name="connectionsJpa">
            <provider name="default" enabled="true">
                <properties>
                    <property name="dataSource" value="java:jboss/datasources/KeycloakDS"/>
                    <property name="initializeEmpty" value="true"/>
                    <property name="migrationStrategy" value="update"/>
                    <property name="migrationExport" value="${jboss.home.dir}/keycloak-database-update.sql"/>
                </properties>
            </provider>
        </spi>
        <spi name="realmCache">
            <provider name="default" enabled="true"/>
        </spi>
        <spi name="connectionsInfinispan">
            <default-provider>default</default-provider>
            <provider name="default" enabled="true">
                <properties>
                    <property name="cacheContainer" value="java:comp/env/infinispan/Keycloak"/>
                </properties>
            </provider>
        </spi>
        <spi name="jta-lookup">
            <default-provider>${keycloak.jta.lookup.provider:jboss}</default-provider>
            <provider name="jboss" enabled="true"/>
        </spi>
        <spi name="publicKeyStorage">
            <provider name="infinispan" enabled="true">
                <properties>
                    <property name="minTimeBetweenRequests" value="10"/>
                </properties>
            </provider>
        </spi>
        <spi name="x509cert-lookup">
            <default-provider>${keycloak.x509cert.lookup.provider:default}</default-provider>
            <provider name="default" enabled="true"/>
        </spi>
    </subsystem>
...

Now when i start the server i got the stacktrace below. I dont know why he cannot find the Factory class?

I checked the .jar file and there are not missing any files.

Stacktrace:

 
08:54:32,971 INFO  [org.jboss.as.server] (Thread-2) WFLYSRV0220: Server shutdown has been requested via an OS signal
08:54:32,973 ERROR [org.jboss.msc.service.fail] (ServerService Thread Pool -- 49) MSC000001: Failed to start service jboss.undertow.deployment.default-server.default-host./auth: org.jboss.msc.service.StartException in service jboss.undertow.deployment.default-server.default-host./auth: java.lang.RuntimeException: RESTEASY003325: Failed to construct public org.keycloak.services.resources.KeycloakApplication(javax.servlet.ServletContext,org.jboss.resteasy.core.Dispatcher)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentService$1.run(UndertowDeploymentService.java:84)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
    at org.jboss.threads.JBossThread.run(JBossThread.java:320)
Caused by: java.lang.RuntimeException: RESTEASY003325: Failed to construct public org.keycloak.services.resources.KeycloakApplication(javax.servlet.ServletContext,org.jboss.resteasy.core.Dispatcher)
    at org.jboss.resteasy.core.ConstructorInjectorImpl.construct(ConstructorInjectorImpl.java:162)
    at org.jboss.resteasy.spi.ResteasyProviderFactory.createProviderInstance(ResteasyProviderFactory.java:2298)
    at org.jboss.resteasy.spi.ResteasyDeployment.createApplication(ResteasyDeployment.java:340)
    at org.jboss.resteasy.spi.ResteasyDeployment.start(ResteasyDeployment.java:253)
    at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.init(ServletContainerDispatcher.java:120)
    at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.init(HttpServletDispatcher.java:36)
    at io.undertow.servlet.core.LifecyleInterceptorInvocation.proceed(LifecyleInterceptorInvocation.java:117)
    at org.wildfly.extension.undertow.security.RunAsLifecycleInterceptor.init(RunAsLifecycleInterceptor.java:78)
    at io.undertow.servlet.core.LifecyleInterceptorInvocation.proceed(LifecyleInterceptorInvocation.java:103)
    at io.undertow.servlet.core.ManagedServlet$DefaultInstanceStrategy.start(ManagedServlet.java:250)
    at io.undertow.servlet.core.ManagedServlet.createServlet(ManagedServlet.java:133)
    at io.undertow.servlet.core.DeploymentManagerImpl$2.call(DeploymentManagerImpl.java:565)
    at io.undertow.servlet.core.DeploymentManagerImpl$2.call(DeploymentManagerImpl.java:536)
    at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:42)
    at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
    at org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction.lambda$create$0(SecurityContextThreadSetupAction.java:105)
    at org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction$$Lambda$847/1223919585.call(Unknown Source)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1508)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction$$Lambda$848/1436296213.call(Unknown Source)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1508)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction$$Lambda$848/1436296213.call(Unknown Source)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1508)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction$$Lambda$848/1436296213.call(Unknown Source)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1508)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction$$Lambda$848/1436296213.call(Unknown Source)
    at io.undertow.servlet.core.DeploymentManagerImpl.start(DeploymentManagerImpl.java:578)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentService.startContext(UndertowDeploymentService.java:100)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentService$1.run(UndertowDeploymentService.java:81)
    ... 6 more
Caused by: java.lang.RuntimeException: Failed to find provider test-login-provider for login
    at org.keycloak.services.DefaultKeycloakSessionFactory.checkProvider(DefaultKeycloakSessionFactory.java:171)
    at org.keycloak.services.DefaultKeycloakSessionFactory.init(DefaultKeycloakSessionFactory.java:90)
    at org.keycloak.services.resources.KeycloakApplication.createSessionFactory(KeycloakApplication.java:326)
    at org.keycloak.services.resources.KeycloakApplication.(KeycloakApplication.java:117)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
    at org.jboss.resteasy.core.ConstructorInjectorImpl.construct(ConstructorInjectorImpl.java:150)
    ... 33 more

If you guys need some more information let me know.

Did i forgot something or is there a mistake?

I would be very thankful for your help.

kind regards


Solution

  • What version of keycloak do you use? If it is one of the later versions (above 1.x), then you seem to use the "wrong" import statments in your classes.

    Please try to update all necessary dependencies and see, if this will work.