Thursday 14 July 2016

Loading Providers and Themes from Maven Repository

Keycloak has a number of SPIs where you can provide your own providers to hook in custom behavior. The custom providers can be deployed by copying the JAR into the providers directory or it can be deployed as a module which provides greater control of the classpath for the provider.

Keycloak also has the ability to create themes to customize login pages and account management console. These can either be copied to the themes directory or they can also be deployed as modules.

In this post I'll show how you can load custom providers and themes from a Maven repository. This could either be from the local Maven repository or a remove Maven repository.

Loading providers and themes from a Maven repository can be useful for development and also as a distribution mechanism, especially when Keycloak is clustered and you want to make sure all nodes have the same providers and themes.

Before going through these examples make sure you have the Keycloak server installed. If you don't you can get it from keycloak.org. We'll refer to the directory where you have the Keycloak server as KEYCLOAK_HOME.

You also need to download the Keycloak examples as we'll use one of the example providers. You can get them from keycloak.org. Then extract the archive somewhere. We'll refer to the directory with the examples as EXAMPLES_HOME.

Deploying Provider as a Module

Before we load the example provider from Maven we'll first deploy it as a module. There's two reasons for this. Firstly, we'll make sure that we have everything configured correctly and that the provider is working as expected. Secondly, loading the provider from Maven is actually a feature of the JBoss Modules which is what provides the support for modules in the first place.

To deploy the provider go through the following steps: Stop the Keycloak server, then build and install the example provider with the following steps:

cd $EXAMPLES_HOME/providers/event-listener-sysout
mvn clean install
$KEYCLOAK_HOME/bin/jboss-cli.sh --command="module add \
 --name=org.keycloak.examples.event-sysout \
 --resources=target/event-listener-sysout-example.jar \
 --dependencies=org.keycloak.keycloak-core,org.keycloak.keycloak-server-spi"
This will create a module for the example provider. Next we need to configure Keycloak to load providers from the. Open $KEYCLOAK_HOME/standalone/configuration/keycloak-server.json in a text editor and update the providers section to:
"providers": [
    "classpath:${jboss.home.dir}/providers/*",
    "module:org.keycloak.examples.event-sysout"
],

Once you've done that start the Keycloak server and login to the Keycloak Admin Console. Select Events from the menu, then click on the Config tab. Remove the jboss-logging listener, add sysout and click on Save. The sysout event listener is the custom event listener provider we just deployed as a module.

To check that the provider is working as expected logout, then login again. You should see some events on the standard output from the Keycloak server:

10:52:01,844 INFO  [stdout] (default task-50) EVENT: type=LOGOUT..
10:52:04,792 INFO  [stdout] (default task-54) EVENT: type=LOGIN..
10:52:04,976 INFO  [stdout] (default task-57) EVENT: type=CODE_TO_TOKEN..

Loading Provider from the Local Maven Repository

Loading the provider from the local Maven Repository is very easy. In the previous steps we already built and installed the provider into the local Maven Repository so we just need to make the module use the Maven artifact instead of the JAR directly from the module.

First stop the Keycloak server. Then delete the file modules/org/keycloak/examples/event-sysout/main/event-listener-sysout-example.jar. Next open $KEYCLOAK_HOME/modules/org/keycloak/examples/event-sysout/main/module.xml in a text editor and change it to:

<?xml version="1.0" ?>

<module xmlns="urn:jboss:module:1.1" name="org.keycloak.examples.event-sysout">

    <resources>
        <artifact name="org.keycloak:event-listener-sysout-example:2.0.0.Final"/>
    </resources>

    <dependencies>
        <module name="org.keycloak.keycloak-core"/>
        <module name="org.keycloak.keycloak-server-spi"/>
    </dependencies>
</module>

Note: if you are not using version 2.0.0.Final of the examples remember to change the version.

You can now start the server again and try login. You'll hopefully see that the events are still being printed to standard out. As you deleted the JAR from the module directory the provider is now being loaded from the local Maven repository.

Loading Provider from a Remote Maven Repository

Let's start by creating a Nexus repository we can use to deploy the provider to. We'll use Docker and the official Sonatype Nexus image. You can obviously use any Maven Repository you want, but for the sake of completeness we'll include steps to setup the repository as well. Make sure you have Docker installed then run: docker run -d -p 8081:8081 sonatype/nexus After a while you'll have a Sonatype Nexus Maven Repository running at http://localhost:8081. You can login to this with username admin and password admin123. Now let's deploy the example provider to this repository. First edit the file .m2/settings.xml in your home directory and add the credentials for the Sonatype Nexus repository:

<settings>
    ...
    <servers>
        <server>
            <id>local-nexus</id>
            <username>admin</username>
            <password>admin123</password>
        </server>
    </servers>
</settings>
Then edit $EXAMPLES_HOME/providers/event-listener-sysout/pom.xml. Add a distributionManagement element:
<distributionManagement>
    <repository>
        <id>local-nexus</id>
        <name>Local Nexus</name>
        <url>http://localhost:8081/content/repositories/releases</url>
    </repository>
</distributionManagement>
Also, you need to enable the deploy plugin as it's been disabled in the parent POM:
<build>
    <finalName>event-listener-sysout-example</finalName>

    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-deploy-plugin</artifactId>
            <configuration>
                <skip>false</skip>
            </configuration>
        </plugin>
    </plugins>
</build>

Now you can run the following to deploy the provider to the repository:

mvn deploy

Check that it was indeed deployed by opening http://localhost:8081/content/repositories/releases/org/keycloak/event-listener-sysout-example/.

Stop Keycloak. To make sure the provider can indeed be retrieved from the remote Maven repository delete the directory .m2/repository/org/keycloak/event-listener-sysout-example. This will remove the provider from the local Maven repository. You can try to start the Keycloak server again, but you will get a warning. To enable the remote Maven repository start the Keycloak server with:

bin/standalone.sh \
 -Dremote.maven.repo=http://localhost:8081/content/repositories/releases

Keycloak should now start successfully and should download the provider from the remote Maven repository. It'll get cached in the local Maven repository so it won't have to retrieve it every time Keycloak is started.