Link IdP to existing user

Hi

I’m trying to get a First Login flow working whereby only pre-created users are allowed to log in.
MS Azure AD is used as trusted IdP. The users are created in Keycloak with username+email and without any IdP Links.

My IdP uses SAML2.0 and has mappers configured for username and email. Username is a Attribute Importer and username uses the Username Template Importer with template ${ATTRIBUTE.http://schemas.xmlsoap.org/ws/2005/05/identity/claims/onpremisessamaccountname}. I verified that both these are mapped correctly (ie, with the default First Broker
Login flow the account is created with the expected parameters).

The only way I can get existing users to link to the IdP is using “Create User If Unique” in the First Login flow, as described in the “Automatically Link Existing First Login Flow” documentation item, but that would also create user accounts for about anyone, which is not what I want.

I’ve tried to use “Automatically Set Existing User” (to set the existing user to the auth context) and then “Confirm Link Existing Account”. But here the login page returns “Invalid username or password” and the server logs contain:

Failed authentication: org.keycloak.authentication.AuthenticationFlowException: Unexpected state. There is no existing duplicated user identified in ClientSession

It seems that authSession.getAuthNote(EXISTING_USER_INFO); fails to look up the existing user, which seems to be (only?) set by IdpCreateUserIfUniqueAuthenticator.

Is this a supported flow ?

I’m using Keycloak 8.0.1, the client uses OIDC.
Thank you in advance for your help.

  • Jan
2 Likes

I also have this problem, did you ever figure it out?

Hello,
same issue here. Anybody has found a solution?

@jan @Queuecumber have you discovered something?

Thanks

Have you tried asking this question on the Keycloak mailing list? You might get an answer there. I am also interested.

@mreinli I’ve tried to send a message few minutes ago, I hope that someone will answer.

I’ve configured Okta as IdP (I’m using SAML, but it seems that the error is not related to SAML or OpenID, nor to the type of IdP used) and then configured an Authentication flow with “Automatically Set Existing User”.

When I try to login using my IdP I receive an “Invalid username or password” error and in Keycloak log I see this exception:

[org.keycloak.services] (default task-227) KC-SERVICES0013: Failed authentication: org.keycloak.authentication.AuthenticationFlowException: Unexpected state. There is no existing duplicated user identified in ClientSession
        at org.keycloak.keycloak-services@10.0.1//org.keycloak.authentication.authenticators.broker.AbstractIdpAuthenticator.getExistingUser(AbstractIdpAuthenticator.java:120)
        at org.keycloak.keycloak-services@10.0.1//org.keycloak.authentication.authenticators.broker.IdpEmailVerificationAuthenticator.authenticateImpl(IdpEmailVerificationAuthenticator.java:83)
        at org.keycloak.keycloak-services@10.0.1//org.keycloak.authentication.authenticators.broker.AbstractIdpAuthenticator.authenticate(AbstractIdpAuthenticator.java:76)
        at org.keycloak.keycloak-services@10.0.1//org.keycloak.authentication.DefaultAuthenticationFlow.processSingleFlowExecutionModel(DefaultAuthenticationFlow.java:438)
        at org.keycloak.keycloak-services@10.0.1//org.keycloak.authentication.DefaultAuthenticationFlow.processFlow(DefaultAuthenticationFlow.java:247)
        at org.keycloak.keycloak-services@10.0.1//org.keycloak.authentication.AuthenticationProcessor.authenticateOnly(AuthenticationProcessor.java:976)
        at org.keycloak.keycloak-services@10.0.1//org.keycloak.services.resources.LoginActionsService$1.authenticateOnly(LoginActionsService.java:792)
        at org.keycloak.keycloak-services@10.0.1//org.keycloak.authentication.AuthenticationProcessor.authenticate(AuthenticationProcessor.java:838)
        at org.keycloak.keycloak-services@10.0.1//org.keycloak.services.resources.LoginActionsService.processFlow(LoginActionsService.java:313)
        at org.keycloak.keycloak-services@10.0.1//org.keycloak.services.resources.LoginActionsService.brokerLoginFlow(LoginActionsService.java:822)
        at org.keycloak.keycloak-services@10.0.1//org.keycloak.services.resources.LoginActionsService.firstBrokerLoginGet(LoginActionsService.java:716)
        at jdk.internal.reflect.GeneratedMethodAccessor1103.invoke(Unknown Source)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
[...]

The same if I use “Confirm Link Existing Account” and “Verify Existing Account By Email”. The only way for login is to manual link the Keycloak user with my IdP (by create an Identity Provider Links in user settings).

It seems that there is something wrong during the lookup of the existing user.

In SAML assertion I’m sending the email address as NameID, and I’m sending also firstName, lastName and email as additional attribute.

Do you have any suggestion on how to solve?

Yeah actually I found

It’s a bug in keycloak and they seem to be a reluctant to fix it for whatever reason. I have very few users so I solved it by manually querying the idp for the information keycloak uses and then copying it into the relevant fields in the UI. So there is no sign up process for my users I just make them myself. Obviously that’s a poor solution though, what we really need is someone to take over that PR and persuade the maintainers to merge it.

By relevant fields you mean the fields in the Identity Provider Links tab?

I was thinking about populating those fields via the Admin API so the process looks as following:

  1. Create the users in Keycloak via Admin API

  2. Create Identity Provider Link by populating userId and username via Admin API

    POST https://{{ base_url }}/auth/admin/realms/{{ realm }}/users/5d2d5da9-0a6e-407e-8741-02b5e45f6722/federated-identity/azuread

    {
    “identityProvider”:“azuread”,
    “userId”:“Y_dic5QcdT17AEzoazK-4FqAmufXMgQ7V9SbMJTep6U”,
    userName":"johndoe@example.onmicrosoft.com
    }

I figured out that the userId field has to match the value in the subject claim and the username field has to match the preferred_username claim of the token issued from the IdP.

I am not sure if other user attributes of the Keycloak user have to match. Is this documented somewhere or do you know where to look at in the source code?

Add “Automatically Link Brokered Account” execution plan to your flow.
Below are the steps to add execution plan

  1. Go to Authentication page in keycloak
  2. Select the flow which you are using in your Identity Provider. In my case it is “Simple Login Flow”
  3. Click “Add execution” button
  4. Select “Automatically Link Brokered Account” from the Provider list.
  5. Click Save button
  6. Then click ALTERNATIVE against the Automatically Link Brokered Account in the list.
    Your Simple Login Flow will look like this

After seeing

 Unexpected state. There is no existing duplicated user identified in ClientSession

and

 type=IDENTITY_PROVIDER_FIRST_LOGIN_ERROR, realmId=realm, clientId=public-api, userId=null, ipAddress=40.113.125.116, error=invalid_user_credentials, identity_provider=oidc-customers, auth_method=openid-connect

In our logs, we found out that we had configured Detect Existing Broker User and Automatically Set Existing User in the wrong order.
This is the order as correctly described in the documentation. But the error message doesn’t make this obvious. In particular error=invalid_user_credentials set us initially on the wrong track.

Hi, SamTheisens

I change the authentication flow as you said. when I have a exist user, then I use idp to login, user will login successful.

I hope if there is no user in database, when user login by idp will create a user automatically.

But now, if use this flow, user will not create user automatically.

I try to read doc to custom authentication flow by code, but doc is too simple.

Can you give me some advice?

The scenario you describe is not the topic of this discussion:

I’m trying to get a First Login flow working whereby only pre-created users are allowed to log in.

I don’t have experience with supporting both user linking and creation, but it sounds like you would need to include “Create user if unique” in your flow.

Thanks for your reply!

The scenario I described does look a little different from this discussion. Because this discussion only allows the business system to create users and the idp to update them when idp log in for the first time. What I want to achieve is that when the user does not exist, the user can be created by both the business system and the idp, and then both can log in.

I tried to add “Create user if unique”, when business system has create user, idp login will error, beacause idp can’t create user.

I am replying under this discussion because it is a somewhat similar scenario to mine and I saw your response. If you have time and are willing, I would like to discuss with you.