@@ -271,7 +271,7 @@ where
271271 return self . handle_unauthenticated_request ( request) ;
272272 }
273273 Err ( e) => {
274- log:: error!( "Found an invalid SQLPage auth cookie : {e}" ) ;
274+ log:: error!( "An auth cookie is present but could not be verified : {e:? }" ) ;
275275 return self . handle_unauthenticated_request ( request) ;
276276 }
277277 }
@@ -379,14 +379,15 @@ fn get_sqlpage_auth_cookie(
379379 } ;
380380 let cookie_value = cookie. value ( ) . to_string ( ) ;
381381
382+ let state = get_state_from_cookie ( request) ?;
382383 let verifier = oidc_client. id_token_verifier ( ) ;
383384 let id_token = CoreIdToken :: from_str ( & cookie_value)
384- . with_context ( || anyhow ! ( "Invalid SQLPage auth cookie" ) ) ?;
385+ . with_context ( || format ! ( "Invalid SQLPage auth cookie: {cookie_value:?} " ) ) ?;
385386
386- let nonce_verifier = |_ : Option < & Nonce > | Ok ( ( ) ) ;
387+ let nonce_verifier = |nonce : Option < & Nonce > | check_nonce ( nonce , & state . nonce ) ;
387388 let claims: & IdTokenClaims < EmptyAdditionalClaims , CoreGenderClaim > = id_token
388389 . claims ( & verifier, nonce_verifier)
389- . with_context ( || anyhow ! ( "Invalid SQLPage auth cookie " ) ) ?;
390+ . with_context ( || format ! ( "Could not verify the ID token: {cookie_value:?} " ) ) ?;
390391 log:: debug!( "The current user is: {claims:?}" ) ;
391392 Ok ( Some ( cookie_value) )
392393}
@@ -562,15 +563,40 @@ struct OidcLoginState {
562563fn hash_nonce ( nonce : & Nonce ) -> String {
563564 use argon2:: password_hash:: { rand_core:: OsRng , PasswordHasher , SaltString } ;
564565 let salt = SaltString :: generate ( & mut OsRng ) ;
565- // low-cost parameters
566- let params = argon2:: Params :: new ( 8 , 1 , 1 , None ) . expect ( "bug: invalid Argon2 parameters" ) ;
566+ // low-cost parameters: oidc tokens are short-lived
567+ let params = argon2:: Params :: new ( 8 , 1 , 1 , Some ( 16 ) ) . expect ( "bug: invalid Argon2 parameters" ) ;
567568 let argon2 = argon2:: Argon2 :: new ( argon2:: Algorithm :: Argon2id , argon2:: Version :: V0x13 , params) ;
568569 let hash = argon2
569570 . hash_password ( nonce. secret ( ) . as_bytes ( ) , & salt)
570571 . expect ( "bug: failed to hash nonce" ) ;
571572 hash. to_string ( )
572573}
573574
575+ fn check_nonce ( id_token_nonce : Option < & Nonce > , state_nonce : & Nonce ) -> Result < ( ) , String > {
576+ match id_token_nonce {
577+ Some ( id_token_nonce) => nonce_matches ( id_token_nonce, state_nonce) ,
578+ None => Err ( "No nonce found in the ID token" . to_string ( ) ) ,
579+ }
580+ }
581+
582+ fn nonce_matches ( id_token_nonce : & Nonce , state_nonce : & Nonce ) -> Result < ( ) , String > {
583+ log:: debug!( "Checking nonce: {} == {}" , id_token_nonce. secret( ) , state_nonce. secret( ) ) ;
584+ let hash = argon2:: password_hash:: PasswordHash :: new ( & id_token_nonce. secret ( ) ) . map_err ( |e| {
585+ format ! (
586+ "Failed to parse state nonce ({}): {e}" ,
587+ id_token_nonce. secret( )
588+ )
589+ } ) ?;
590+ argon2:: password_hash:: PasswordVerifier :: verify_password (
591+ & argon2:: Argon2 :: default ( ) ,
592+ state_nonce. secret ( ) . as_bytes ( ) ,
593+ & hash,
594+ )
595+ . map_err ( |e| format ! ( "Failed to verify nonce ({}): {e}" , state_nonce. secret( ) ) ) ?;
596+ log:: debug!( "Nonce successfully verified" ) ;
597+ Ok ( ( ) )
598+ }
599+
574600impl OidcLoginState {
575601 fn new ( request : & ServiceRequest , auth_url : AuthUrlParams ) -> Self {
576602 Self {
0 commit comments