Skip to content

Commit

Permalink
Add IdToken::into_claims
Browse files Browse the repository at this point in the history
  • Loading branch information
David Ramos committed Nov 28, 2019
1 parent 13b2169 commit 40bcd1e
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 20 deletions.
24 changes: 20 additions & 4 deletions src/id_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,21 +91,37 @@ where
}

///
/// Verifies and returns the ID token claims.
/// Verifies and returns a reference to the ID token claims.
///
pub fn claims<'a, 'b, JU, K, N>(
pub fn claims<'a, JU, K, N>(
&'a self,
verifier: &'b IdTokenVerifier<JS, JT, JU, K>,
verifier: &IdTokenVerifier<JS, JT, JU, K>,
nonce_verifier: N,
) -> Result<&'a IdTokenClaims<AC, GC>, ClaimsVerificationError>
where
JU: JsonWebKeyUse,
K: JsonWebKey<JS, JT, JU>,
N: NonceVerifier<'a>,
N: NonceVerifier,
{
verifier.verified_claims(&self.0, nonce_verifier)
}

///
/// Verifies and returns the ID token claims.
///
pub fn into_claims<JU, K, N>(
self,
verifier: &IdTokenVerifier<JS, JT, JU, K>,
nonce_verifier: N,
) -> Result<IdTokenClaims<AC, GC>, ClaimsVerificationError>
where
JU: JsonWebKeyUse,
K: JsonWebKey<JS, JT, JU>,
N: NonceVerifier,
{
verifier.verified_claims_owned(self.0, nonce_verifier)
}

///
/// Returns the [`JwsSigningAlgorithm`] used to sign this ID token.
///
Expand Down
71 changes: 55 additions & 16 deletions src/verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -465,17 +465,17 @@ where
///
/// Trait for verifying ID token nonces.
///
pub trait NonceVerifier<'a> {
pub trait NonceVerifier {
///
/// Verifies the nonce.
///
/// Returns `Ok(())` if the nonce is valid, or a string describing the error otherwise.
///
fn verify(self, nonce: Option<&'a Nonce>) -> Result<(), String>;
fn verify(self, nonce: Option<&Nonce>) -> Result<(), String>;
}

impl<'a> NonceVerifier<'a> for &Nonce {
fn verify(self, nonce: Option<&'a Nonce>) -> Result<(), String> {
impl NonceVerifier for &Nonce {
fn verify(self, nonce: Option<&Nonce>) -> Result<(), String> {
if let Some(claims_nonce) = nonce {
if verify_slices_are_equal(claims_nonce.secret().as_bytes(), self.secret().as_bytes())
.is_err()
Expand All @@ -489,11 +489,11 @@ impl<'a> NonceVerifier<'a> for &Nonce {
}
}

impl<'a, F> NonceVerifier<'a> for F
impl<F> NonceVerifier for F
where
F: FnOnce(Option<&'a Nonce>) -> Result<(), String>,
F: for<'a> FnOnce(Option<&'a Nonce>) -> Result<(), String>,
{
fn verify(self, nonce: Option<&'a Nonce>) -> Result<(), String> {
fn verify(self, nonce: Option<&Nonce>) -> Result<(), String> {
self(nonce)
}
}
Expand Down Expand Up @@ -710,14 +710,49 @@ where
AC: AdditionalClaims,
GC: GenderClaim,
JE: JweContentEncryptionAlgorithm<JT>,
N: NonceVerifier<'b>,
N: NonceVerifier,
{
// The code below roughly follows the validation steps described in
// https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation

// Steps 1--3 are handled by the generic JwtClaimsVerifier.
let partially_verified_claims = self.jwt_verifier.verified_claims(jwt)?;

self.verify_claims(partially_verified_claims, nonce_verifier)?;
Ok(partially_verified_claims)
}

pub(super) fn verified_claims_owned<AC, GC, JE, N>(
&self,
jwt: JsonWebToken<JE, JS, JT, IdTokenClaims<AC, GC>, JsonWebTokenJsonPayloadSerde>,
nonce_verifier: N,
) -> Result<IdTokenClaims<AC, GC>, ClaimsVerificationError>
where
AC: AdditionalClaims,
GC: GenderClaim,
JE: JweContentEncryptionAlgorithm<JT>,
N: NonceVerifier,
{
// The code below roughly follows the validation steps described in
// https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation

// Steps 1--3 are handled by the generic JwtClaimsVerifier.
let partially_verified_claims = self.jwt_verifier.verified_claims(jwt)?;

self.verify_claims(&partially_verified_claims, nonce_verifier)?;
Ok(partially_verified_claims)
}

fn verify_claims<'b, AC, GC, N>(
&self,
partially_verified_claims: &'b IdTokenClaims<AC, GC>,
nonce_verifier: N,
) -> Result<(), ClaimsVerificationError>
where
AC: AdditionalClaims,
GC: GenderClaim,
N: NonceVerifier,
{
// 4. If the ID Token contains multiple audiences, the Client SHOULD verify that an azp
// Claim is present.

Expand Down Expand Up @@ -787,7 +822,7 @@ where
(*self.auth_time_verifier_fn)(partially_verified_claims.auth_time())
.map_err(ClaimsVerificationError::InvalidAuthTime)?;

Ok(partially_verified_claims)
Ok(())
}
}

Expand Down Expand Up @@ -1518,7 +1553,7 @@ mod tests {
Jv8mB_jFkTZGVKHTPpObHV-qptJ_rnlwvF_mP5GARBLng-4Yd7nmSr31onYL48QDjGOrwPqQ-IyaCQ"
.to_string(),
))
.expect("failed to deserialize"), |_| Ok(())) {
.expect("failed to deserialize"), |_: Option<&Nonce>| Ok(())) {
Err(ClaimsVerificationError::InvalidIssuer(_)) => {}
other => panic!("unexpected result: {:?}", other),
}
Expand All @@ -1527,15 +1562,19 @@ mod tests {

// Expired token
mock_current_time.set(1544928549 + 3600);
match public_client_verifier.verified_claims(&test_jwt_without_nonce, |_| Ok(())) {
match public_client_verifier
.verified_claims(&test_jwt_without_nonce, |_: Option<&Nonce>| Ok(()))
{
Err(ClaimsVerificationError::Expired(_)) => {}
other => panic!("unexpected result: {:?}", other),
}
mock_current_time.set(1544928549 + 1);

// Invalid issue time
mock_is_valid_issue_time.set(false);
match public_client_verifier.verified_claims(&test_jwt_without_nonce, |_| Ok(())) {
match public_client_verifier
.verified_claims(&test_jwt_without_nonce, |_: Option<&Nonce>| Ok(()))
{
Err(ClaimsVerificationError::Expired(_)) => {}
other => panic!("unexpected result: {:?}", other),
}
Expand All @@ -1545,7 +1584,7 @@ mod tests {

// Successful verification w/o checking nonce
public_client_verifier
.verified_claims(&test_jwt_without_nonce, |_| Ok(()))
.verified_claims(&test_jwt_without_nonce, |_: Option<&Nonce>| Ok(()))
.expect("verification should succeed");

// Missing nonce
Expand Down Expand Up @@ -1620,7 +1659,7 @@ mod tests {

// Missing auth_time (ok)
public_client_verifier
.verified_claims(&test_jwt_without_auth_time, |_| Ok(()))
.verified_claims(&test_jwt_without_auth_time, |_: Option<&Nonce>| Ok(()))
.expect("verification should succeed");

// Missing auth_time (error)
Expand All @@ -1630,7 +1669,7 @@ mod tests {
assert!(auth_time.is_none());
Err("Invalid auth_time claim".to_string())
})
.verified_claims(&test_jwt_without_auth_time, |_| Ok(()))
.verified_claims(&test_jwt_without_auth_time, |_: Option<&Nonce>| Ok(()))
{
Err(ClaimsVerificationError::InvalidAuthTime(_)) => {}
other => panic!("unexpected result: {:?}", other),
Expand All @@ -1654,7 +1693,7 @@ mod tests {

// Successful verification with nonce, acr, and auth_time specified (no expected Nonce)
public_client_verifier
.verified_claims(&test_jwt_with_nonce, |_| Ok(()))
.verified_claims(&test_jwt_with_nonce, |_: Option<&Nonce>| Ok(()))
.expect("verification should succeed");

// Successful verification with nonce, acr, and auth_time specified (w/ expected Nonce)
Expand Down

0 comments on commit 40bcd1e

Please sign in to comment.