Keycloak ThemeSelectorProviderFactory not a subtype error while adding custom user storage SPI

Viewed 427

I’m trying to add a simple custom user storage SPI in keycloak 17.0.0. I have followed the keycloak documentation for creation of custom user storage SPI, But when I try to build kc I’m getting error:

    ERROR: Failed to run 'build' command.
ERROR: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
    [error]: Build step org.keycloak.quarkus.deployment.KeycloakProcessor#configureProviders threw an exception: java.util.ServiceConfigurationError: org.keycloak.theme.ThemeSelectorProviderFactory: keycloak.spi.test.file.PropertyFileUserStorageProviderFactory not a subtype
    at java.base/java.util.ServiceLoader.fail(ServiceLoader.java:589)
    at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNextService(ServiceLoader.java:1237)
    at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNext(ServiceLoader.java:1265)
    at java.base/java.util.ServiceLoader$2.hasNext(ServiceLoader.java:1300)
    at java.base/java.util.ServiceLoader$3.hasNext(ServiceLoader.java:1385)
    at org.keycloak.provider.DefaultProviderLoader.load(DefaultProviderLoader.java:60)
    at org.keycloak.provider.ProviderManager.load(ProviderManager.java:94)
    at org.keycloak.quarkus.deployment.KeycloakProcessor.loadFactories(KeycloakProcessor.java:456)
    at org.keycloak.quarkus.deployment.KeycloakProcessor.configureProviders(KeycloakProcessor.java:254)
    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 io.quarkus.deployment.ExtensionLoader$2.execute(ExtensionLoader.java:882)
    at io.quarkus.builder.BuildContext.run(BuildContext.java:277)
    at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
    at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
    at java.base/java.lang.Thread.run(Thread.java:829)
    at org.jboss.threads.JBossThread.run(JBossThread.java:501)

ERROR: Build failure: Build failed due to errors
    [error]: Build step org.keycloak.quarkus.deployment.KeycloakProcessor#configureProviders threw an exception: java.util.ServiceConfigurationError: org.keycloak.theme.ThemeSelectorProviderFactory: keycloak.spi.test.file.PropertyFileUserStorageProviderFactory not a subtype
    at java.base/java.util.ServiceLoader.fail(ServiceLoader.java:589)
    at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNextService(ServiceLoader.java:1237)
    at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNext(ServiceLoader.java:1265)
    at java.base/java.util.ServiceLoader$2.hasNext(ServiceLoader.java:1300)
    at java.base/java.util.ServiceLoader$3.hasNext(ServiceLoader.java:1385)
    at org.keycloak.provider.DefaultProviderLoader.load(DefaultProviderLoader.java:60)
    at org.keycloak.provider.ProviderManager.load(ProviderManager.java:94)
    at org.keycloak.quarkus.deployment.KeycloakProcessor.loadFactories(KeycloakProcessor.java:456)
    at org.keycloak.quarkus.deployment.KeycloakProcessor.configureProviders(KeycloakProcessor.java:254)
    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 io.quarkus.deployment.ExtensionLoader$2.execute(ExtensionLoader.java:882)
    at io.quarkus.builder.BuildContext.run(BuildContext.java:277)
    at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
    at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
    at java.base/java.lang.Thread.run(Thread.java:829)
    at org.jboss.threads.JBossThread.run(JBossThread.java:501)

ERROR: org.keycloak.theme.ThemeSelectorProviderFactory: keycloak.spi.test.file.PropertyFileUserStorageProviderFactory not a subtype
For more details run the same command passing the '--verbose' option. Also you can use '--help' to see the details about the usage of the particular command.

POM.xml content is:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>keycloack-SPI-Demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <properties>
        <java.version>11</java.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.keycloak</groupId>
            <artifactId>keycloak-core</artifactId>
            <version>17.0.0</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.keycloak</groupId>
            <artifactId>keycloak-server-spi</artifactId>
            <version>17.0.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>3.3.0</version>
                <configuration>
                    <finalName>my-user-provider</finalName>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <appendAssemblyId>false</appendAssemblyId>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

I’m creating jar with mvn command mvn clean compile assembly:single and placing that jar in providers directory.

Content of my UserStorageFactory class is given below:

public class PropertyFileUserStorageProviderFactory implements UserStorageProviderFactory<PropertyFileUserStorageProvider> {
    private static final String PROVIDER_NAME = "property-file";
    protected Properties properties = new Properties();
    private static final Logger logger = Logger.getLogger(PropertyFileUserStorageProviderFactory.class.getName());

    @Override
    public PropertyFileUserStorageProvider create(KeycloakSession keycloakSession, ComponentModel componentModel) {
        return new PropertyFileUserStorageProvider(keycloakSession, componentModel, properties);
    }

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

    @Override
    public void init(Config.Scope config) {
        String path = config.get("path");
        InputStream is = getClass().getClassLoader().getResourceAsStream(path);

        if (is == null) {
            logger.severe("Could not find users.properties in classpath");
        } else {
            try {
                properties.load(is);
            } catch (IOException ex) {
                logger.severe("Failed to load users.properties file" +  ex);
            }
        }
    }

    @Override
    public void close() {
        UserStorageProviderFactory.super.close();
    }

    @Override
    public void postInit(KeycloakSessionFactory factory) {
        UserStorageProviderFactory.super.postInit(factory);
    }

    @Override
    public UserStorageProvider create(KeycloakSession session) {
        return UserStorageProviderFactory.super.create(session);
    }

    @Override
    public List<ProviderConfigProperty> getConfigProperties() {
        return UserStorageProviderFactory.super.getConfigProperties();
    }

    @Override
    public String getHelpText() {
        return UserStorageProviderFactory.super.getHelpText();
    }

    @Override
    public void validateConfiguration(KeycloakSession session, RealmModel realm, ComponentModel config) throws ComponentValidationException {
        UserStorageProviderFactory.super.validateConfiguration(session, realm, config);
    }

    @Override
    public void onCreate(KeycloakSession session, RealmModel realm, ComponentModel model) {
        UserStorageProviderFactory.super.onCreate(session, realm, model);
    }

    @Override
    public List<ProviderConfigProperty> getCommonProviderConfigProperties() {
        return UserStorageProviderFactory.super.getCommonProviderConfigProperties();
    }

    @Override
    public Map<String, Object> getTypeMetadata() {
        return UserStorageProviderFactory.super.getTypeMetadata();
    }

I'm not sure what I'm doing wrong.

1 Answers

Resolved it. Just found that my file in META-INF file was name for ThemeSelectorProviderFactory instead of UserStorageProviderFactory.

Related