p2-inc / idp-wizard

Identity Provider setup wizards for Keycloak
https://phasetwo.io
Other
1 stars 1 forks source link

[Question] Organization SSO, user not added to Organization #180

Open MGLL opened 4 weeks ago

MGLL commented 4 weeks ago

Hello,

Linked to my other topic, will exploring Organization SSO / IDP-Wizard.

I noticed that the user is not added to the Organization when login with the configured IdP. Is it a bug or should we configure something additionaly ?
Also, I noticed that upon second login, user is not redirected to the IdP.

Detail

I noticed a strange behaviour, which might be linked to my configuration (configured IdP manually in "Service Provider" and assigned it to the Organization).

First Login

Upon the first login, it correctly redirect to the IdP for user authentication. User can correctly login and access the UI.

I noticed it creates the user in the list of users of the Service Provider, but the user is not assigned to the Organization in which the IdP is assigned.

Second Login

And upon a second login, once the user is part of realm, the user is not redirected to the IdP assigned to the Organization. It ask for the username/password of the current service, which doesn't works.

Setup

Here is the detailed configuration

Service Provider

Service the user try to access.

IdP configuration

image

image

Mappers: image

image

Organization

image

image

Authentication

image

image

IdP

Client created with SAML import

image

image

Scopes

image

image

User info after 1st login

image

image

MGLL commented 4 weeks ago

Solved the first problem, missed image

in IdP configuration.

however, I still have the issue upon second login where it doesn't redirect to the IdP

xgp commented 4 weeks ago

@MGLL was the post org broker login flow set on the IdP by the wizard? It is supposed to do that automatically.

Need to check why the home idp discovery plugin isn't working. Your config looks right.

MGLL commented 4 weeks ago

@xgp after having the bug during SSO configuration with idp-wizard, I tried to configure it from Keycloak directly and assign it to the organization. Missed that I had to add this post login flow, this one is on me.

~So I'm wondering if I missed another configuration for the second issue, where upon a second login, the user is not redirected to the IDP (no issue on 1st login).~

EDIT: actually, I unchecked "Forward to linked IdP" and it started working. On every login, it redirect the user to the assigned IDP.

Capture d’écran 2024-06-03 à 20 13 22

Should the issue be updated to check that as a bug? or is it expected and close it?

xgp commented 4 weeks ago

That configuration parameter is only supposed to change the behavior if the user has an existing link to an IdP. If it is a user that has no link, but matches the email domain, the redirect should work. Does your user have any existing links? If not, this may be a bug.

MGLL commented 4 weeks ago

There is a "Linked identity providers" assigned after 1st login which match the organization IDP.

So I guess it is not a bug, but a matter of configuration and be aware of it 👍

Capture d’écran 2024-06-03 à 21 09 05
MGLL commented 3 weeks ago

Hello again, seems I was able to have back the issue where on next login it doesn't redirect to the SSO assigned to the org even with unchecked "Forward to linked IdP".

Don't know what could be the issue as it started working and not anymore. Gonna dig into it and provide some more info

MGLL commented 3 weeks ago

Found the cause of the problem @xgp

The root cause of the issue is kinda a "bug" as there is a misleading Home-idp-discovery configuration parameter which doesn't work with the actual implementation in keycloak-orgs.

In Home IdP Discovery config Authenticator I have "Require a verified email" disabled. So an user with an email not verified should still be redirected to the required IDP.

image

But in io.phasetwo.service.auth.idp.HomeIdpDiscoverer, in this set of code (else part)

        final Optional<Domain> emailDomain;
        UserModel user = context.getUser();
        if (user == null) {
            LOG.tracef("No user found in AuthenticationFlowContext. Extracting domain from provided username '%s'.",
                username);
            emailDomain = domainExtractor.extractFrom(username);
        } else {
            LOG.tracef("User found in AuthenticationFlowContext. Extracting domain from stored user '%s'.",
                user.getId());
            emailDomain = domainExtractor.extractFrom(user);
        }

We use domainExtractor.extractFrom(user); of io.phasetwo.service.auth.idp.DomainExtractor (as in 2nd login, user is not null) which run the following code

    Optional<Domain> extractFrom(UserModel user) {
        if (!user.isEnabled()) {
            LOG.warnf("User '%s' not enabled", user.getId());
            return Optional.empty();
        }
        String userAttribute = user.getFirstAttribute(config.userAttribute());
        if (userAttribute == null) {
            LOG.warnf("Could not find user attribute '%s' for user '%s'", config.userAttribute(), user.getId());
            return Optional.empty();
        }
        if (EMAIL_ATTRIBUTE.equalsIgnoreCase(config.userAttribute()) && !user.isEmailVerified()) {
            LOG.warnf("Email address of user '%s' is not verified", user.getId());
            return Optional.empty();
        }
        return extractFrom(userAttribute);
    }

and in particular

if (EMAIL_ATTRIBUTE.equalsIgnoreCase(config.userAttribute()) && !user.isEmailVerified()) {
            LOG.warnf("Email address of user '%s' is not verified", user.getId());
            return Optional.empty();
        }

with && !user.isEmailVerified() (as I'm using 'email' user attribute).

Which enforce the user to have a verified email even if the Authenticator is configured to not enforce it. So, as a result, even if the user have an IDP linked (with org or directly), but don't have a verified email, it always return an Optional.empty() as emailDomain.

Which leads to the unexpected behaviour I got where it never redirect to the Org IDP after the 1st login, as it seems to import the user with an email not verified.

If it is fine for you, I will close this issue here and create a bug issue in keycloak-orgs. I could look into it to fix it of course. So idea would either to fix this conditional, and/or set the email to verified when the user is imported.



Also, on a side note, I have found another issue

With this configuration of Home IdP Discovery config image

For a 1st login (user log-in with Org IDP and doesn't exists yet in KC), it actually throw a NullPointerException.

image

As with this set of code

        final Optional<Domain> emailDomain;
        UserModel user = context.getUser();
        if (user == null) {
            LOG.tracef("No user found in AuthenticationFlowContext. Extracting domain from provided username '%s'.",
                username);
            emailDomain = domainExtractor.extractFrom(username);
        } else {
            LOG.tracef("User found in AuthenticationFlowContext. Extracting domain from stored user '%s'.",
                user.getId());
            emailDomain = domainExtractor.extractFrom(user);
        }

        HomeIdpDiscoveryConfig config = new HomeIdpDiscoveryConfig(authenticatorConfig);
        if (config.requireVerifiedEmail()
            && "email".equalsIgnoreCase(config.userAttribute())
            && !user.isEmailVerified()) {
            LOG.infof("Email of user %s not verified. Skipping discovery of linked IdPs", user.getId());
            return homeIdps;
        }

it still run into

        if (config.requireVerifiedEmail()
            && "email".equalsIgnoreCase(config.userAttribute())
            && !user.isEmailVerified()) {
            LOG.infof("Email of user %s not verified. Skipping discovery of linked IdPs", user.getId());
            return homeIdps;
        }

which do && !user.isEmailVerified() with user to null.

MGLL commented 3 weeks ago

also easier, would be to set "Trust Email" to true, in the IdP configuration when it is created. Noticed it is not set when I created the IdP with idp-wizard.

image