Search code examples
transactionskeycloakkeycloak-services

How do I write a simple transaction wrapper in a Keycloak SPI extension?


By following this Keycloak developer guide, I was trying to write an SPI extension that helps federate a custom user service (think of it as a data store with a bunch of CRUD REST APIs handling user data) into Keycloak.

One basic scenario I wanted to achieve is that when a new user logs in via Keycloak, her/his information needs to be propagated to the custom user service by creating a user entry.

By implementing the UserRegistrationProvider interface, I have below method in my provider.

    @Override
    public UserModel addUser(RealmModel realm, String username) {
        log.infov("Adding new user: username={0}", username);
        User user = new User();
        // do something to populate the user object with additional attributes, e.g. those edited via the Keycloak console UI
        UserModel userModel = createAdapter(realm, user);
        return userModel;
    }

The strange thing is that this interface method only takes in the username argument as a string. I don't know how to access other user attributes. I found below two posts on this issue.

UserRegistrationProvider value object add method

Custom federation - webservice

The reply from the Keycloak team is that a transaction wrapper can be applied to persist changes only when the transaction is committed. A good example is the official implementation for LDAP federation. And this is the source code for LDAP transaction.

But that code portion is too much to read. Appreciate it if someone can provide a simple and succinct way of implementing it.


Solution

  • After reading through Keycloak's source code on LDAP provider, I figured out that the data persistence step can occur in a customised transaction that is enlisted after the main transaction.

    The repository referenced above is a file based Keycloak user storage provider I experimented with. Hope it could provide some insights on this.