Loading Custom service provider from other extension

Hello,

I have created and loaded a custom Service provider and the same is accessible via rest endpoints and also visible on the console under the provider’s tab.

I am now trying to customize the authentication flow by extending the “Authenticator” interface.
Here in the overridden method “authenticate” I would like to invoke one of the custom provider methods.

The question is how do get a custom provider instance in some other module?
Note: I tried calling " session.getProviderClass(“custom-provider-name”) "where the string is the name of the custom provider but it always returns null (in spite of it being functional )

Any views on how can I achieve this?

Thanks,
Romil

Use the class name of your custom SPI. E.g. session.getProvider(JpaConnectionProvider.class)

Thanks for a quick response.
Since this method would be invoked in some other extension (extension to Authenticator interface), this would give a compilation error. Not sure if I am missing something?
for e.g session.getProvider(customProvider.class) , here code compilation fails, as customProvider class is not found.

Yes, you would need to be able to compile against the SPI. How were you intending to use it without being able to code/compile against it? Maybe I’m not understanding your question. The usual case for loading a provider in the session is to use it.

Well, the custom service provider is already deployed as a module.
Now I am trying to access the same via some other extension.

Custom SPi loaded into Keyloak server as a module is :

Now I am trying to load a custom IP Authenticator (link below) and as part of overridden method “authenticate()” want to access the loaded Spi method for e,g listCompanies()

The question is the same, how under say IPAuthenticator.java method one can access a custom service provider already loaded. Any example or reference would help!

Hope this provides some clarity?

You would need to

  1. Import the (ExampleService) extension into your project’s pom:
        <dependency>
            <groupId>org.keycloak</groupId>
            <artifactId>keycloak-examples-providers-domain-extension</artifactId>
            <scope>provided</scope>
        </dependency>
  1. Import the (ExampleService) provider in your jboss-deployment-structure.xml or jar’s manifest.mf:
<jboss-deployment-structure>
    <deployment>
        <dependencies>
            <module name="org.keycloak.keycloak-examples-providers-domain-extension" export="true" />
            ...
        </dependencies>
    </deployment>
</jboss-deployment-structure>
Created-By: Maven Jar Plugin 3.2.0
Build-Jdk-Spec: 11
Dependencies: org.keycloak.keycloak-examples-providers-domain-extension, ...
  1. Load the provider from the KeycloakSession in your IPAuthenticator.java code:
    session.getProvider(ExampleService.class);
1 Like

Thanks, this does help.
But I still get below error upon login when its triying to load the IPAutenticator extension
upon invoking → session.getProvider(ExampleService.class);
java.lang.ClassNotFoundException: org.keycloak.examples.domainextension.spi.ExampleService from [Module “deployment.keycloak-ip-authenticator.jar”]

-Romil

Sorry, I think you need to remove the provided scope from the dependency.

I tried removing the provided scope as well. But no luck.

I am using AccessService class which implements Spi
public class AccessSpi implements Spi {

The custom Spi is all working fine and I see it listed as well on UI under Server info.

Do we need a custom spi jar to be loaded/copied to some other place as well ? or needs to be wrapped in the IPAuthenticator jar as well?

13:10:47,838 INFO  [org.jboss.as.repository] (DeploymentScanner-threads - 1) WFLYDR0002: Content removed from location /Users/rshah35/optum/project/repos/keycloak/keycloak-15.0.2/standalone/data/content/d2/bf9eb3d7ac89938c2a372e7cb45c697be8dbff/content
13:11:05,468 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (default task-1) Uncaught server error: java.lang.NoClassDefFoundError: org/keycloak/examples/domainextension/spi/AccessService
	at deployment.keycloak-ip-authenticator.jar//com.github.lukaszbudnik.keycloak.ipauthenticator.IPAuthenticator.getAllowedPermission(IPAuthenticator.java:51)
	at deployment.keycloak-ip-authenticator.jar//com.github.lukaszbudnik.keycloak.ipauthenticator.IPAuthenticator.authenticate(IPAuthenticator.java:28)
	at org.keycloak.keycloak-services@15.0.2//org.keycloak.authentication.DefaultAuthenticationFlow.processSingleFlowExecutionModel(DefaultAuthenticationFlow.java:446)
	at org.keycloak.keycloak-services@15.0.2//org.keycloak.authentication.DefaultAuthenticationFlow.processFlow(DefaultAuthenticationFlow.java:253)
	at org.keycloak.keycloak-services@15.0.2//org.keycloak.authentication.DefaultAuthenticationFlow.processSingleFlowExecutionModel(DefaultAuthenticationFlow.java:389)

IP Authenticator pom file has the dependency listed, I loaded the SPI jar in the local maven repository and added the dependency in the pom file.

       <dependency>
            <groupId>org.keycloak</groupId>
            <artifactId>domain-extension-example</artifactId>
            <version>1.0</version>
        </dependency>

Strange part is even using existing SPI , it returns null ( though no class not found exception)
session.getProvider(ThemeProvider.class) → Returns null

Have you installed the provider in the standalone config? There’s an example of how to do that here: keycloak/examples/providers/domain-extension at master · keycloak/keycloak · GitHub

yes, as mentioned above, the provider is independently loaded and working fine. It’s when being attempted to load via getProviders() in some other deployment where it fails.

        <subsystem xmlns="urn:jboss:domain:keycloak-server:1.1">
            <web-context>auth</web-context>
            <providers>
                <provider>
                    classpath:${jboss.home.dir}/providers/*
                </provider>
                <provider>
                    module:org.keycloak.examples.domain-extension-example
                </provider>
            </providers>```

Does each custom deployment for e.g here IPAuthenticator need to bundle the jar or the getProvider(..) method invoked by them is supposed to fetch it from the container?