mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2026-03-22 09:49:20 -07:00
Improve sso auth flow (#6205)
Co-authored-by: Timshel <timshel@users.noreply.github.com>
This commit is contained in:
@@ -7,8 +7,8 @@ use url::Url;
|
||||
|
||||
use crate::{
|
||||
api::{ApiResult, EmptyResult},
|
||||
db::models::SsoNonce,
|
||||
sso::{OIDCCode, OIDCState},
|
||||
db::models::SsoAuth,
|
||||
sso::{OIDCCode, OIDCCodeChallenge, OIDCCodeVerifier, OIDCState},
|
||||
CONFIG,
|
||||
};
|
||||
|
||||
@@ -107,7 +107,11 @@ impl Client {
|
||||
}
|
||||
|
||||
// The `state` is encoded using base64 to ensure no issue with providers (It contains the Organization identifier).
|
||||
pub async fn authorize_url(state: OIDCState, redirect_uri: String) -> ApiResult<(Url, SsoNonce)> {
|
||||
pub async fn authorize_url(
|
||||
state: OIDCState,
|
||||
client_challenge: OIDCCodeChallenge,
|
||||
redirect_uri: String,
|
||||
) -> ApiResult<(Url, SsoAuth)> {
|
||||
let scopes = CONFIG.sso_scopes_vec().into_iter().map(Scope::new);
|
||||
let base64_state = data_encoding::BASE64.encode(state.to_string().as_bytes());
|
||||
|
||||
@@ -122,22 +126,21 @@ impl Client {
|
||||
.add_scopes(scopes)
|
||||
.add_extra_params(CONFIG.sso_authorize_extra_params_vec());
|
||||
|
||||
let verifier = if CONFIG.sso_pkce() {
|
||||
let (pkce_challenge, pkce_verifier) = PkceCodeChallenge::new_random_sha256();
|
||||
auth_req = auth_req.set_pkce_challenge(pkce_challenge);
|
||||
Some(pkce_verifier.into_secret())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if CONFIG.sso_pkce() {
|
||||
auth_req = auth_req
|
||||
.add_extra_param::<&str, String>("code_challenge", client_challenge.clone().into())
|
||||
.add_extra_param("code_challenge_method", "S256");
|
||||
}
|
||||
|
||||
let (auth_url, _, nonce) = auth_req.url();
|
||||
Ok((auth_url, SsoNonce::new(state, nonce.secret().clone(), verifier, redirect_uri)))
|
||||
Ok((auth_url, SsoAuth::new(state, client_challenge, nonce.secret().clone(), redirect_uri)))
|
||||
}
|
||||
|
||||
pub async fn exchange_code(
|
||||
&self,
|
||||
code: OIDCCode,
|
||||
nonce: SsoNonce,
|
||||
client_verifier: OIDCCodeVerifier,
|
||||
sso_auth: &SsoAuth,
|
||||
) -> ApiResult<(
|
||||
StandardTokenResponse<
|
||||
IdTokenFields<
|
||||
@@ -155,17 +158,21 @@ impl Client {
|
||||
|
||||
let mut exchange = self.core_client.exchange_code(oidc_code);
|
||||
|
||||
let verifier = PkceCodeVerifier::new(client_verifier.into());
|
||||
if CONFIG.sso_pkce() {
|
||||
match nonce.verifier {
|
||||
None => err!(format!("Missing verifier in the DB nonce table")),
|
||||
Some(secret) => exchange = exchange.set_pkce_verifier(PkceCodeVerifier::new(secret)),
|
||||
exchange = exchange.set_pkce_verifier(verifier);
|
||||
} else {
|
||||
let challenge = PkceCodeChallenge::from_code_verifier_sha256(&verifier);
|
||||
if challenge.as_str() != String::from(sso_auth.client_challenge.clone()) {
|
||||
err!(format!("PKCE client challenge failed"))
|
||||
// Might need to notify admin ? how ?
|
||||
}
|
||||
}
|
||||
|
||||
match exchange.request_async(&self.http_client).await {
|
||||
Err(err) => err!(format!("Failed to contact token endpoint: {:?}", err)),
|
||||
Ok(token_response) => {
|
||||
let oidc_nonce = Nonce::new(nonce.nonce);
|
||||
let oidc_nonce = Nonce::new(sso_auth.nonce.clone());
|
||||
|
||||
let id_token = match token_response.extra_fields().id_token() {
|
||||
None => err!("Token response did not contain an id_token"),
|
||||
|
||||
Reference in New Issue
Block a user