Extending FreeMarkerLoginFormsProvider for custom theme attributes

Hello

I’m currently exploring the upgrade from major 16 to 17 and trying to figure out if it will work with our custom services.

After some finagling, i’ve managed to get pretty much everything to work except the following feature which we really need.

I have a custom SPI that extends FreeMarkLoginFormsProvider, i’m extending it in order to add attributes to the createCommonAttributes method, which then let’s me add new attributes to the theme, the attributes are coming form the realm attributes.
(Everything would be much simpler if the ftl files had access to realm attributes, but they dont)

But the problem is that in order to extend this class, i needed to add a custom spi in the standalone file as such:

embed-server --server-config=standalone-ha.xml
/subsystem=keycloak-server/spi=login:add()
/subsystem=keycloak-server/spi=login/provider=freemarker:add(enabled="false")
/subsystem=keycloak-server/spi=login/provider=csps-freemarker-login-messages:add(enabled="true")
stop-embedded-server

The above is not possible anymore in keycloak 17 and up since jboss-cli.sh is no longer in the bin folder of keycloak.

I’m wondering, is extending the theme and adding new attributes that can be fetched from the ftl files is still possible through the FreeMarkerLoginFormsProvider class in keycloak 17 and up?

Here’s my class for the interested

public class CustomFreeMarkerLoginFormsProvider extends FreeMarkerLoginFormsProvider {

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

    @Override
    protected void createCommonAttributes(Theme theme, Locale locale, Properties messagesBundle,
            UriBuilder baseUriBuilder, LoginFormsPages page) {
        super.createCommonAttributes(theme, locale, messagesBundle, baseUriBuilder, page);

        if (realm != null) {
            // Setting the messages and title from the realm attributes.
            if ("fr".equals(locale.toString().toLowerCase())) {
                attributes.put("dangerMessage", realm.getAttribute("dangerMessageFrench"));
                attributes.put("warningMessage", realm.getAttribute("warningMessageFrench"));
                attributes.put("infoMessage", realm.getAttribute("infoMessageFrench"));
                attributes.put("dangerMessageTitle", realm.getAttribute("dangerMessageTitleFrench"));
                attributes.put("warningMessageTitle", realm.getAttribute("warningMessageTitleFrench"));
                attributes.put("infoMessageTitle", realm.getAttribute("infoMessageTitleFrench"));
            } else {
                attributes.put("dangerMessage", realm.getAttribute("dangerMessageEnglish"));
                attributes.put("warningMessage", realm.getAttribute("warningMessageEnglish"));
                attributes.put("infoMessage", realm.getAttribute("infoMessageEnglish"));
                attributes.put("dangerMessageTitle", realm.getAttribute("dangerMessageTitleEnglish"));
                attributes.put("warningMessageTitle", realm.getAttribute("warningMessageTitleEnglish"));
                attributes.put("infoMessageTitle", realm.getAttribute("infoMessageTitleEnglish"));
            }

            // Getting the CSPS maintenance mode execution config.
            AuthenticatorConfigModel authenticatorConfig = realm
                    .getAuthenticatorConfigByAlias("CSPS maintenance mode execution config");

            if (authenticatorConfig != null) {
                Boolean maintenance = Boolean.parseBoolean(authenticatorConfig.getConfig().get("maintenance"));
                if (maintenance) {
                    // The maintenance config is enabled, setting a theme attribute.
                    attributes.put("maintenanceModeEnabled", maintenance);
                }
            }
        }
    }
}

As you can see, i’m setting up attributes that are fetched from the realm attributes. Then my ftl files can access the attributes this way:

<@dangerMessage?interpret />

I’ve found this

I’ll give it a try and post some updates

The above seems to have done the trick.

I’ve modified my init script to start keycloak with the following 2 attributes:

/opt/keycloak/bin/kc.sh "${keycloak_cmd_arguments[@]}" --spi-login-freemarker-enabled=false --spi-login-csps-freemarker-login-messages-enabled=true

This starts keycloak with the SPI being updated.
The theme can now access the variables.