zitadel / zitadel

ZITADEL - Identity infrastructure, simplified for you.
https://zitadel.com
Apache License 2.0
8.63k stars 544 forks source link

[Bug]: Possible bug - Register on IDP do not use domain discovery #6890

Closed zs-ko closed 9 months ago

zs-ko commented 11 months ago

Preflight Checklist

Environment

Self-hosted

Version

v2.40.4

Describe the problem caused by this bug

unsure if this is intended or just a bug. When a new user clicks on an external IDP (azure,google) without an active account Zitadel will only create that account in the default organization and ignore domain coming from the external idp even if the username and email are the same and there exists an org with that domain name registered in the Zitadel instance.

To reproduce

create org add domain name same as used in idp add and enable idp in default instance, default org and new test org enable create account on idp enable domain discovery on all orgs click on idp and notice that the email domain for the user is ignored and forces the default org.

Screenshots

No response

Expected behavior

No response

Operating System

No response

Relevant Configuration

No response

Additional Context

No response

hifabienne commented 11 months ago

hei @zs-ko The behaviour is intended. It depend where you create your idps, per default users will always be registered to the default organization. You can send an organization scope to select the organization urn:zitadel:iam:org:id:{id} https://zitadel.com/docs/apis/openidoauth/scopes#reserved-scopes

Or you can use domain discorvery: https://zitadel.com/docs/guides/solution-scenarios/domain-discovery

zs-ko commented 11 months ago

Ok, we have enabled domain discovery but still new users are registered to the default domain when using External SSO providers. This do not happen if they enter a username(email) in the username field. then they are registered to the correct tenant. This only happens when a new user logs inn trough sso. I would have expected the new user to then be registered on the correct org or be redirected to the org and then registered. But when SSO is enabled on the instance this only allows for existing users that have used the sso from the default instance to log inn.

francis-j commented 10 months ago

I have the same issue. Domain discovery is enabled, but logging in via SSO with a domain registered to a non-default organization doesn't work. I get the errors below, which seems to suggest that ZITADEL is trying to add the domain to the default organization, rather than looking at the other organization domains. There is also no reason for the user to see an error about domains already being reserved...so feels like an internal bug.

Microsoft - External User Not Found Domain is already reserved and cannot be used.

hifabienne commented 10 months ago

Hei, I quickly checked this by myself and can't reproduce it works perfectly fine. So what I did:

  1. create a new organisation company A
  2. add a verified domain to that organization: companya.com
  3. add idp, disable username password
  4. go to login and enter fabienne@companya.com
  5. user is redirected to idp and authenticates
  6. user is redirected back to zitadel and doesn't exist, I click register
  7. User is created in organization company a

Can you tell me where you are doing something different? Or try with the flow mentioned above?

francis-j commented 10 months ago

My scenario is slightly different:

  1. Create organisation: Company A
  2. Add verified domain to that organisation: companya.com
  3. Add Microsoft as external IdP with tenant type: organizations
  4. Add user to organisation: usera@companya.com
  5. Go to login and click Microsoft button
  6. User is redirected to Microsoft login and authenticates as usera@companya.com
  7. User is redirected back to zitadel and gets the domain reserved error

The idea is that authorised users are created in their associated organisation beforehand by an admin within that organisation. With auto-creation disabled, I no longer get the domain reserved error, just the Microsoft External User not found error.

image

hifabienne commented 10 months ago

My scenario is slightly different:

  1. Create organisation: Company A
  2. Add verified domain to that organisation: companya.com
  3. Add Microsoft as external IdP with tenant type: organizations
  4. Add user to organisation: usera@companya.com
  5. Go to login and click Microsoft button
  6. User is redirected to Microsoft login and authenticates as usera@companya.com
  7. User is redirected back to zitadel and gets the domain reserved error
  8. User is also offered to Link account. Clicking the button redirects back to login but doesn't link anything

The idea is that authorised users are created in their associated organisation beforehand by an admin within that organisation.

Ok. Thanks for the clarification that helped. So the problem is that you do not specify which organisation you want. When the user clicks on the microsoft button in step 5, this is the microsoft button of the default organization. You would need to specify the organization with the organization scope urn:zitadel:iam:org:id:{id} The domain discovery is to find out to which organization the user belongs in the first place. But we do not know when you come back from the idp.

francis-j commented 10 months ago

How is this supposed to work for a SaaS application with a common login page? Is the suggestion then to not have an instance level IdP and instead configure this per organization? Would this flow work?

  1. Go to zitadel login
  2. Enter email address: usera@companya.com
  3. Domain discovery finds user organisation and redirects with organisation scope
  4. Click Microsoft button and authenticate
hifabienne commented 10 months ago

How is this supposed to work for a SaaS application with a common login page? Is the suggestion then to not have an instance level IdP and instead configure this per organization? Would this flow work?

  1. Go to zitadel login
  2. Enter email address: usera@companya.com
  3. Domain discovery finds user organisation and redirects with organisation scope
  4. Click Microsoft button and authenticate

yes that should work. so as the user always belongs to an orgnization somehow zitadel needs to know to which one. we did a recent change about what should be shown when opening up the login without a context. https://zitadel.com/docs/support/advisory/a10003

so for example if you have social logins like google, github for your default organization, and then specifc azure ads for your other organizations you would just let them enter the username in the first input.

francis-j commented 10 months ago

Thanks, then it really is better not to show any IdPs on the contextless login screen as that will definitely cause confusion!

zs-ko commented 10 months ago

yes, i agree. the default instance will cause confusions and result in users beeing registered on the wrong org.

When i think about this, would this not defy the intent of the domain discovery.

When i have the following org with domain Company A: companya.com Company B: companyb.com

then i have not check for add suffix to domain so the function would be If this settings is disabled, you have to ensure that usernames are unique over all organizations

Then when you on the default instance click login with Azure and when domain discovery is allowed i think it should default to the registerd domain by domain discovery.

a user that belongs to the Company A by domain companya.com should not be able to be placed outside Company A org.

This would allow for less confusion in the login flow and simpler/faster login process for end users leveraging external idp.

francis-j commented 10 months ago

yes, i agree. the default instance will cause confusions and result in users beeing registered on the wrong org.

When i think about this, would this not defy the intent of the domain discovery.

When i have the following org with domain Company A: companya.com Company B: companyb.com

then i have not check for add suffix to domain so the function would be If this settings is disabled, you have to ensure that usernames are unique over all organizations

Then when you on the default instance click login with Azure and when domain discovery is allowed i think it should default to the registerd domain by domain discovery.

a user that belongs to the Company A by domain companya.com should not be able to be placed outside Company A org.

This would allow for less confusion in the login flow and simpler/faster login process for end users leveraging external idp.

I agree, it would be a lot simpler of domain discovery just placed users in their associated organisation rather than the default org. Is it also not dangerous to allow users from different organisations to mix in the same org?

@hifabienne I'm still unable to log in via Microsoft even when the IdP is on companya. I get the same error where the user cannot be found. It's as if domain discovery just isn't working fully when the user doesn't live in the default organisation. It correctly identifies that companya has Microsoft as an IdP, but it looks like the organisation scope is not set on the redirect URI. This is the URL that zitadel redirects to:

https://login.microsoftonline.com/<Tenant ID>/oauth2/v2.0/authorize?client_id=<Client ID>&login_hint=<External Name>&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fui%2Flogin%2Flogin%2Fexternalidp%2Fcallback&response_type=code&scope=openid+profile+email+User.Read&state=241887275904929796

hifabienne commented 10 months ago

As the idps always belong to a organization it is hard to do a domain discovery there, as ZITADEL already has a specified organization. So far the domain discovery is mainly to identify if a user does not yet exist to know to which organization to redirect.

I agree that there could be some improvements, but I am a little hesitant at the moment, as it might be not the same process for every costomer. We try to build a flow that works for most of the customers.

If you need more flexibility or another flow, you could build your own login ui, and use our session API.

Yes when the user doesn't exist you will still get a not found error and then the user has to register. you can also enable auto register in that case the user should be created automatically

francis-j commented 10 months ago

As the idps always belong to a organization it is hard to do a domain discovery there, as ZITADEL already has a specified organization. So far the domain discovery is mainly to identify if a user does not yet exist to know to which organization to redirect.

Is that the case for IdPs defined at an instance level? I would have thought that this would then scan all organisation domains and redirect with the matched organisation scope.

Yes when the user doesn't exist you will still get a not found error and then the user has to register. you can also enable auto register in that case the user should be created automatically

I still can't get it working with the IdP on the organisation, specifically when the user is pre-created. I'm adding the user via the management API. Do you see an issue with the request?


{
    userName = humanUser.Username,
    profile = new
    {
        firstName = humanUser.FirstName,
        lastName = humanUser.LastName,
        displayName = humanUser.DisplayName,
        preferredLanguage = "en",
    },
    email = new
    {
        email = humanUser.EmailAddress,
        isEmailVerified = true
    },
    password = humanUser.Password,
    passwordChangeRequired = false,
    idps = (object[])(humanUser.UseBasicAuth ? [] : [new
    {
        configId = idpId,
        externalUserId = humanUser.EmailAddress,
        displayName = humanUser.DisplayName,
    }])
});
hifabienne commented 10 months ago

As the idps always belong to a organization it is hard to do a domain discovery there, as ZITADEL already has a specified organization. So far the domain discovery is mainly to identify if a user does not yet exist to know to which organization to redirect.

Is that the case for IdPs defined at an instance level? I would have thought that this would then scan all organisation domains and redirect with the matched organisation scope.

Yes when the user doesn't exist you will still get a not found error and then the user has to register. you can also enable auto register in that case the user should be created automatically

I still can't get it working with the IdP on the organisation, specifically when the user is pre-created. I'm adding the user via the management API. Do you see an issue with the request?

{
    userName = humanUser.Username,
    profile = new
    {
        firstName = humanUser.FirstName,
        lastName = humanUser.LastName,
        displayName = humanUser.DisplayName,
        preferredLanguage = "en",
    },
    email = new
    {
        email = humanUser.EmailAddress,
        isEmailVerified = true
    },
    password = humanUser.Password,
    passwordChangeRequired = false,
    idps = (object[])(humanUser.UseBasicAuth ? [] : [new
    {
        configId = idpId,
        externalUserId = humanUser.EmailAddress,
        displayName = humanUser.DisplayName,
    }])
});

Yes it is also the case with idps created on the instance level. We recently made a change to the login, so the instance settings will never trigger instead the default organization does. But as this would be a breaking behaviour change it is behind a feature flag. you can find the details here: https://zitadel.com/docs/support/advisory/a10003

the creation does look fine for me

hifabienne commented 9 months ago

I will close this issue for now. As we have changed the behaviour, with the advisory above. Feel free to reopen, if you still face the problem and can provide more information