elastic / kibana

Your window into the Elastic Stack
https://www.elastic.co/products/kibana
Other
19.71k stars 8.12k forks source link

Cannot do IDP initiated login with more than one OIDC provider #190177

Open Ronnie76er opened 1 month ago

Ronnie76er commented 1 month ago

Kibana version: 8.13.4

Elasticsearch version: 8.13.4

Server OS version: ESS

Original install method (e.g. download page, yum, from source, etc.): ESS

Describe the bug:

I have two OIDC authentication providers. When using the "Login Selector Screen", both of these providers work.

When I try to do IDP initiated login, via /api/security/oidc/initiate_login?iss=<some iss name>, only one of the OIDC providers works, and the other does not.

I can see that after the initiate_login request goes, it calls the correct /authorize url for the issuer provided, and then gets an auth code back at the /api/security/oidc/callback URL. So, up until here, everything appears to be correct. However, the callback URL returns a 401, and back at the Login selector screen with the message: "Try logging in again, and if the problem persists, contact your system administrator."

Additionally, in the log for ES, there is a message that is as follows:

Authentication to realm <wrong realm> failed - Failed to authenticate user with OpenID Connect (Caused by org.elasticsearch.ElasticsearchSecurityException: Failed to exchange code for Id Token. Code=[invalid_grant], Description=[The authorization code is invalid or has expired.])

Which states it's trying to use the code against the wrong IDP.

I was trying to follow the code, I believe this stems from https://github.com/elastic/kibana/blob/main/x-pack/plugins/security/server/authentication/authenticator.ts#L320-L349. The idea is that it is suppose to try with all the OIDC providers, going on to the next one if the previous one is notHandled().

When using an auth code with an incorrect IDP, it doesn't return notHandled(), it returns failed(), so if the first IDP isn't the correct one to receive the auth code, it will enter the if (!authenticationResult.notHandled()) branch, and return a failed auth result.

I imagine it's like this because of the logic stated in https://github.com/elastic/kibana/issues/26040, which makes sense, the idea being that it should move on if it couldn't "handle" the authentication due to not enough information. In OIDC world, there is enough information for it to attempt the authentication (trading the auth code for an ID token), it's just doing so with the wrong IDP.

Steps to reproduce:

  1. Create two OIDC providers, and ensure they work using the login selector
  2. Attempt an IDP initiated login (GET /api/security/oidc/initiate_login?iss=<some iss name> with both

Expected behavior: Both should log you in.

elasticmachine commented 3 weeks ago

Pinging @elastic/kibana-security (Team:Security)