Browse Source

Add SSO_SKIP_USERINFO to fix ADFS interop.

OpenID login flow gets claims from the idtoken, and
calls the userinfo endpoint. Unfortunately, IDPs do
not have to implement the userinfo endpoint.
Notably, ADFS does not implement it.

If SSO_SKIP_USERINFO is set to true, Vaultwarden
will not attempt to retrieve claims from userinfo,
and solely uses the identity token instead.
pull/7904/head
Simon Biewald 2 weeks ago
parent
commit
e0bd30b0ca
No known key found for this signature in database GPG Key ID: 1338DFDE0CB97138
  1. 2
      src/config.rs
  2. 9
      src/sso.rs

2
src/config.rs

@ -864,6 +864,8 @@ make_config! {
sso_client_cache_expiration: u32, true, def, 0; sso_client_cache_expiration: u32, true, def, 0;
/// Log all tokens |> `LOG_LEVEL=debug` or `LOG_LEVEL=info,vaultwarden::sso=debug` is required /// Log all tokens |> `LOG_LEVEL=debug` or `LOG_LEVEL=info,vaultwarden::sso=debug` is required
sso_debug_tokens: bool, true, def, false; sso_debug_tokens: bool, true, def, false;
/// Do not call userinfo endpoint, solely use identity token claims (set to true if you use ADFS).
sso_skip_userinfo: bool, true, def, false;
}, },
/// Yubikey settings /// Yubikey settings

9
src/sso.rs

@ -2,6 +2,8 @@ use std::{sync::LazyLock, time::Duration};
use chrono::Utc; use chrono::Utc;
use derive_more::{AsRef, Deref, Display, From, Into}; use derive_more::{AsRef, Deref, Display, From, Into};
use openidconnect::core::{CoreGenderClaim, CoreUserInfoClaims};
use openidconnect::StandardClaims;
use url::Url; use url::Url;
use crate::{ use crate::{
@ -281,7 +283,12 @@ pub async fn exchange_code(
let client = Client::cached().await?; let client = Client::cached().await?;
let (token_response, id_claims) = client.exchange_code(code, client_verifier, &sso_auth).await?; let (token_response, id_claims) = client.exchange_code(code, client_verifier, &sso_auth).await?;
let user_info = client.user_info(token_response.access_token().to_owned()).await?; let user_info: CoreUserInfoClaims;
if CONFIG.sso_skip_userinfo() {
user_info = client.user_info(token_response.access_token().to_owned()).await?;
} else {
user_info = CoreUserInfoClaims::new(StandardClaims::new(id_claims.subject().clone()), Default::default());
}
let email = match id_claims.email().or(user_info.email()) { let email = match id_claims.email().or(user_info.email()) {
None => err!("Neither id token nor userinfo contained an email"), None => err!("Neither id token nor userinfo contained an email"),

Loading…
Cancel
Save