3

I have two custom authentication method on Keycloak.

One of them is custom implemented user federation. I configured it for X realm. System uses this implementation for login with username / password method. This implementation calls my federation service and it validates sent user. It works successfully and authenticates federated users.

Second one is an identity broking (openid connect). I configured a custom openid provider to Y realm. It works successfully and validates provider's users.

I configured both of them to same realm. When i try to use login with custom identity provider, authentication flow works correctly. In the end of flow, configured user federation (custom implemented user federation) triggers with username which comes from identity broking (custom identity provider) login process and it calls my federation service again.

When i try to login with identity providers, i do not want the user federation (custom implemented user federation) to work. It must work only when i try to login with username / password login.

How can i block working of user federation on this scenario?

Please share your experience. Thanks

Batuhan
  • 463
  • 2
  • 6
  • 22
  • Did you find the answer to this? – Ehsan Oct 21 '20 at 18:00
  • @Ehsan sorry for my late answer. Yes, i applied one solution. I created a Flow. (placed under Authentication/Flows menu). It contains only one auth type. (Create User If Unique(create unique user config) => as ALTERNATIVE). After that, i associated this flow with my custom identity provider. (you need to open Identity Providers menu and select your identity provider settings. And you need to select created flow for "First Login Flow" dropdown). After that, i blocked working of user federation on this scenario. I hope this process can help you. – Batuhan Dec 18 '20 at 17:17

1 Answers1

4

I had the same issue of the identity provider and custom user federation not both working at the same time. My solution wasn't to block user federation but to change my custom user federation code. The implementation of the method that returns the user from the UserLookupProvider interface (getUserByEmail/Username/Id) must be coded to return a AbstractUserAdapterFederatedStorage. This implementation of UserModel provides implementation for methods needed by keycloak to internalize users from identity providers. Additionally I implemented UserQueryProvider interface along with UserStorageProvider, UserLookupProvider, CredentialInputValidator to be able to see these users from the keycloak admin console.

From their documentation: Keycloak comes with a helper class org.keycloak.storage.adapter.AbstractUserAdapterFederatedStorage that will delegate every single UserModel method except get/set of username to user federated storage.

...interface UserQueryProvider. If you do not implement this interface, then users will not be viewable in the admin console. You’ll still be able to login though.

Ref: https://www.keycloak.org/docs/latest/server_development/#_user-storage-spi

Code: note: A custom keycloak user storage should have at least two classes. One main one that does the heavy lifting that must implement at least UserStorageProvider. And another that is a factory that calls this class. More on this on their Server Development guide. The following code goes in the main class (not the factory):

@Override
    public UserModel getUserByUsername(String username, RealmModel realm) {

        [...]

            userModel = createUserModel(username, realm);

        [...]

        return userModel;
    }

protected UserModel createUserModel( String username, RealmModel realm) {
        return new AbstractUserAdapterFederatedStorage(session, realm, model) {
            @Override
            public String getUsername() {
                return username;
            }

            @Override
            public void setUsername(String username) {
//retrieves user through repository and sets the keycloak user to its username. (Seems redundant but works!)
                usersService.getUserDetails(username).setUsername(username);
                }
            };
        }