From 5972bcb63ccf0a6b65667f9b372ea795ff97033f Mon Sep 17 00:00:00 2001 From: David Dal Busco Date: Thu, 12 Feb 2026 06:53:56 +0100 Subject: [PATCH] feat(auth): use a standardized trait to read nonce instead of passing function --- .../openid/credentials/delegation/impls.rs | 4 ++ .../openid/credentials/delegation/verify.rs | 19 +-------- src/libs/auth/src/openid/jwt/types.rs | 1 + src/libs/auth/src/openid/jwt/verify.rs | 41 +++++-------------- 4 files changed, 17 insertions(+), 48 deletions(-) diff --git a/src/libs/auth/src/openid/credentials/delegation/impls.rs b/src/libs/auth/src/openid/credentials/delegation/impls.rs index d0b1f9aec5..5cd4c43909 100644 --- a/src/libs/auth/src/openid/credentials/delegation/impls.rs +++ b/src/libs/auth/src/openid/credentials/delegation/impls.rs @@ -34,4 +34,8 @@ impl JwtClaims for DelegationClaims { fn iat(&self) -> Option { self.iat } + + fn nonce(&self) -> Option<&str> { + self.nonce.as_deref() + } } diff --git a/src/libs/auth/src/openid/credentials/delegation/verify.rs b/src/libs/auth/src/openid/credentials/delegation/verify.rs index 1b41d83c0d..59379462c8 100644 --- a/src/libs/auth/src/openid/credentials/delegation/verify.rs +++ b/src/libs/auth/src/openid/credentials/delegation/verify.rs @@ -58,14 +58,6 @@ fn verify_openid_credentials( client_id: &OpenIdAuthProviderClientId, salt: &Salt, ) -> VerifyOpenIdDelegationCredentialsResult { - let assert_nonce = |claims: &DelegationClaims, nonce: &String| -> Result<(), JwtVerifyError> { - if claims.nonce.as_deref() != Some(nonce.as_str()) { - return Err(JwtVerifyError::BadClaim("nonce".to_string())); - } - - Ok(()) - }; - let assert_audience = |claims: &DelegationClaims| -> Result<(), JwtVerifyError> { if claims.aud != client_id.as_str() { return Err(JwtVerifyError::BadClaim("aud".to_string())); @@ -74,15 +66,8 @@ fn verify_openid_credentials( Ok(()) }; - let token = verify_openid_jwt( - jwt, - provider.issuers(), - &jwks.keys, - salt, - assert_nonce, - assert_audience, - ) - .map_err(VerifyOpenidCredentialsError::JwtVerify)?; + let token = verify_openid_jwt(jwt, provider.issuers(), &jwks.keys, salt, assert_audience) + .map_err(VerifyOpenidCredentialsError::JwtVerify)?; let credential = OpenIdDelegationCredential::from(token); diff --git a/src/libs/auth/src/openid/jwt/types.rs b/src/libs/auth/src/openid/jwt/types.rs index 080269b7af..7c2e774d7f 100644 --- a/src/libs/auth/src/openid/jwt/types.rs +++ b/src/libs/auth/src/openid/jwt/types.rs @@ -3,6 +3,7 @@ pub(crate) mod token { pub trait JwtClaims { fn iat(&self) -> Option; + fn nonce(&self) -> Option<&str>; } #[derive(Clone, Deserialize)] diff --git a/src/libs/auth/src/openid/jwt/verify.rs b/src/libs/auth/src/openid/jwt/verify.rs index a3becac5ae..5de3d5cf49 100644 --- a/src/libs/auth/src/openid/jwt/verify.rs +++ b/src/libs/auth/src/openid/jwt/verify.rs @@ -11,17 +11,15 @@ fn pick_key<'a>(kid: &str, jwks: &'a [Jwk]) -> Option<&'a Jwk> { jwks.iter().find(|j| j.kid.as_deref() == Some(kid)) } -pub fn verify_openid_jwt( +pub fn verify_openid_jwt( jwt: &str, issuers: &[&str], jwks: &[Jwk], salt: &Salt, - assert_nonce: Nonce, assert_custom: Custom, ) -> Result, JwtVerifyError> where Claims: DeserializeOwned + JwtClaims, - Nonce: FnOnce(&Claims, &String) -> Result<(), JwtVerifyError>, Custom: FnOnce(&Claims) -> Result<(), JwtVerifyError>, { // 1) Read header to get `kid` @@ -68,9 +66,12 @@ where let c = &token.claims; // 6) Checks the nonce - i.e. the caller + salt is present in the jwt + // This ensures the JWT has not been intercepted and submitted with a different identity. let nonce = build_nonce(salt); - assert_nonce(c, &nonce)?; + if c.nonce() != Some(nonce.as_str()) { + return Err(JwtVerifyError::BadClaim("nonce".to_string())); + } // 7) Assert custom fields according consumer's flow assert_custom(c)?; @@ -177,6 +178,9 @@ mod verify_tests { fn iat(&self) -> Option { self.iat } + fn nonce(&self) -> Option<&str> { + self.nonce.as_deref() + } } fn claims( @@ -222,13 +226,6 @@ mod verify_tests { } } - fn assert_nonce(claims: &GoogleClaims, nonce: &String) -> Result<(), JwtVerifyError> { - if claims.nonce.as_deref() != Some(nonce.as_str()) { - return Err(JwtVerifyError::BadClaim("nonce".to_string())); - } - Ok(()) - } - fn assert_audience(claims: &GoogleClaims) -> Result<(), JwtVerifyError> { if claims.aud != AUD_OK { return Err(JwtVerifyError::BadClaim("aud".to_string())); @@ -260,7 +257,6 @@ mod verify_tests { &[ISS_GOOGLE], &[jwk_with_kid(KID_OK)], &salt, - assert_nonce, assert_audience, ) .expect("should verify"); @@ -294,7 +290,6 @@ mod verify_tests { &[ISS_GOOGLE], &[jwk_with_kid(KID_OK)], &salt, - assert_nonce, assert_audience, ) .unwrap_err(); @@ -325,7 +320,6 @@ mod verify_tests { &[ISS_GOOGLE], &[jwk_with_kid(KID_OK)], &salt, - assert_nonce, assert_audience, ) .unwrap_err(); @@ -357,7 +351,6 @@ mod verify_tests { &[ISS_GOOGLE], &[jwk_with_kid(KID_OK)], &salt, - assert_nonce, assert_audience, ) .unwrap_err(); @@ -388,7 +381,6 @@ mod verify_tests { &[ISS_GOOGLE], &[jwk_with_kid(KID_OK)], &salt, - assert_nonce, assert_audience, ) .unwrap_err(); @@ -419,7 +411,6 @@ mod verify_tests { &[ISS_GOOGLE], &[jwk_with_kid(KID_OK)], &salt, - assert_nonce, assert_audience, ) .unwrap_err(); @@ -448,7 +439,6 @@ mod verify_tests { &[ISS_GOOGLE], &[jwk_with_kid(KID_OK)], &salt, - assert_nonce, assert_audience, ) .unwrap_err(); @@ -480,7 +470,6 @@ mod verify_tests { &[ISS_GOOGLE], &[jwk_with_kid(KID_OK)], &salt, - assert_nonce, assert_audience, ) .unwrap_err(); @@ -512,7 +501,6 @@ mod verify_tests { &[ISS_GOOGLE], &[jwk_with_kid(KID_OK)], &salt, - assert_nonce, assert_audience, ) .unwrap_err(); @@ -545,7 +533,6 @@ mod verify_tests { &[ISS_GOOGLE], &[jwk_with_kid(KID_OK)], &salt, - assert_nonce, assert_audience, ) .unwrap_err(); @@ -587,15 +574,8 @@ mod verify_tests { }), }; - let err = verify_openid_jwt( - &token, - &[ISS_GOOGLE], - &[bad_jwk], - &salt, - assert_nonce, - assert_audience, - ) - .unwrap_err(); + let err = verify_openid_jwt(&token, &[ISS_GOOGLE], &[bad_jwk], &salt, assert_audience) + .unwrap_err(); assert!(matches!(err, JwtVerifyError::BadSig(_))); } @@ -630,7 +610,6 @@ mod verify_tests { &[ISS_GOOGLE], &[jwk_with_kid(KID_OK)], &salt, - assert_nonce, assert_audience, ) .expect("should verify");