Event SPI and Users added from other sources (Identity Provider/Federated Provider)

Hello all,
I am looking to synchronize users and their assigned roles between Keycloak and my application.
For this functionality, i was able to find the Event SPI, and create my own customer listener. By listening to Admin events for User/Roles assignments, my listener can fire off events to my application to mimic the behavior.
However, I’ve noticed when users are added to Keycloak through other sources (a Federated Source such as LDAP, or an Identity Provider), this does not fire off the same event, making it impossible for the Event SPI to pick up the action.
Is this the intended behavior? Is the Event SPI limited to actions performed manually in the admin console, or through a direct web call to Keycloak?
I understand that another option available is to extend existing Identity/Federated Providers to intercept the message there, but my concern is that would then ignore any changes made afterwords in Keycloak itself, unless i combine it with the Event SPI.
Is there any other functionality in Keycloak to help perform this task?

Thanks

Hey,

did you find any solution to work around this issue? I’m looking for something similar to have a provider agnostic way to push some data of the known users to my application.

By the logs if have seen that infinispan catches an UserUpdatedEvent. But these are ClusterEvents and are not handled within the EventListener. It looks like I have to register a custom ClusterListener but did not get it working right now. I’m also not sure, if the ClusterListener is supposed to be used that way (if it work’s at all).

Best regards
Thomas

I think the only way to catch all user adds is to implement a UserRegistrationProvider (UserRegistrationProvider (Keycloak Docs Distribution 15.0.2 API)) .
There is good documentation on implementing a User Storage provider here Server Developer Guide and your use case would require only wrapping the add methods in the UserRegistrationProvider.

Thanks for your thoughts. I have added a UserRegistrationProvider, but it also does not trigger if users are imported by an LDAP sync. Also removeUser is not called at all, because the user is not linked to this provider. Any other idea’s which I’m not thinking off? Or may I am doing something wrong?

Do you have “import users” turned on in your LDAP sync? I’m looking at the code, and it appears the addUser method is called when users are added this way. Perhaps I’m misunderstanding it, and it’s actually the ImportSynchronization interface instead.

Regarding removeUser, I know there is another way to get this event. You can use register a listener for the UserModel.UserRemovedEvent. This is a ProviderEvent, which can be registered using the KeycloakSessionFactory. I usually do it in the postInit method of a ProviderFactory implementation like this:

  @Override
  public void postInit(KeycloakSessionFactory factory) {
    factory.register(
        (event) -> {
          if (event instanceof UserModel.UserRemovedEvent) {
            //do something with the event
          }
        });
  }

I’ve got an example here: keycloak-events/UserEventListenerProviderFactory.java at main · p2-inc/keycloak-events · GitHub, which, by the way, I’d love some additions to if you figure out definitively how to get all of the user add/remove events.

Yes, “import users” is active. I have reviewed the code as well, and it “sounds” like the addUser of the providers should be called. So I don’t know why it’s not called.

Thank you for the hint with the UserRemovedEvent, which works (sadly there is no UserUpdatedEvent). I have looked into the implementation of the ClusterListener and how the notification process works. It does not seem to be possible to attach to those events.

Do all provider (Identity & User Federation) create the user in the local storage? I am trying to run the sources locally now, so I may can step into the addUser method.

Identity brokering, yes. User federation, it’s up to the implementation.

Thanks for your very fast responses.

After debugging into the provider, I have seen that the JpaUserProvider is used and not the UserStorageManager as I initalliy thought. Is this something that is configurable?

Because of that there is no call to the registered providers. Instead, as you can see, each registered RequiredActionProviderModel is executed, if addDefaultRequiredActions is true.
I guess I could implement an required action provider to integrate into that process? I will give it a try.

Edit: Well, required action must be solved by the user, when the login occures? That won’t help.

PS: Sorry, I’m very new to keycloak and java as well.

I’m stumped. The JpaUserProvider is the implementation of UserProvider, which is a subinterface of all the User Storage Provider interfaces. Not sure how it is getting called.

@t0ms3n @xgp I found a method that will allow you to tap into users that were synced from LDAP on Keycloak by creating a custom mapper for it. The mapper taps into the onImportUserFromLDAP method from the LDAPStorageMapper. This mapper passes in a UserModel object which contains at the very minimum the username and Keycloak GUID.
I wrote a medium article on it: Keycloak: Event Listener SPI for LDAP / User Federation Sync | by Ivancheahkf | Sep, 2022 | Medium

1 Like