From c9cd44b35a22c854e12d955da1b436041858c107 Mon Sep 17 00:00:00 2001 From: mdecimus Date: Mon, 21 Oct 2024 15:54:14 +0200 Subject: [PATCH] Include preferred_username and email in OIDC id_token --- crates/common/src/auth/oauth/oidc.rs | 18 ++++++++++++------ crates/jmap/src/auth/oauth/token.rs | 23 +++++++++++++++++++++-- tests/src/jmap/auth_oauth.rs | 9 +++++++-- tests/src/jmap/mod.rs | 8 ++++---- 4 files changed, 44 insertions(+), 14 deletions(-) diff --git a/crates/common/src/auth/oauth/oidc.rs b/crates/common/src/auth/oauth/oidc.rs index 8722f6dd..8cbf3b04 100644 --- a/crates/common/src/auth/oauth/oidc.rs +++ b/crates/common/src/auth/oauth/oidc.rs @@ -79,10 +79,18 @@ pub struct Userinfo { } #[derive(Debug, Default, Eq, PartialEq, Deserialize, Serialize)] -pub struct Nonce { +pub struct StandardClaims { #[serde(skip_serializing_if = "Option::is_none")] #[serde(default)] pub nonce: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(default)] + pub preferred_username: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(default)] + pub email: Option, } impl Server { @@ -91,7 +99,7 @@ impl Server { subject: impl Into, issuer: impl Into, audience: impl Into, - nonce: Option>, + claims: StandardClaims, ) -> trc::Result { let now = now() as i64; @@ -101,7 +109,7 @@ impl Server { key_id: Some("default".into()), ..Default::default() }), - ClaimsSet:: { + ClaimsSet:: { registered: RegisteredClaims { issuer: Some(issuer.into()), subject: Some(subject.into()), @@ -111,9 +119,7 @@ impl Server { expiry: Some((now + self.core.oauth.oidc_expiry_id_token as i64).into()), ..Default::default() }, - private: Nonce { - nonce: nonce.map(Into::into), - }, + private: claims, }, ) .into_encoded(&self.core.oauth.oidc_signing_secret) diff --git a/crates/jmap/src/auth/oauth/token.rs b/crates/jmap/src/auth/oauth/token.rs index fcd2f36b..bdfc943c 100644 --- a/crates/jmap/src/auth/oauth/token.rs +++ b/crates/jmap/src/auth/oauth/token.rs @@ -5,12 +5,16 @@ */ use common::{ - auth::{oauth::GrantType, AccessToken}, + auth::{ + oauth::{oidc::StandardClaims, GrantType}, + AccessToken, + }, Server, }; use hyper::StatusCode; use std::future::Future; use store::write::Bincode; +use trc::AddContext; use crate::api::{ http::{HttpContext, HttpSessionData, ToHttpResponse}, @@ -292,7 +296,22 @@ impl TokenHandler for Server { None }, id_token: if with_id_token { - match self.issue_id_token(account_id.to_string(), issuer, client_id, nonce) { + // Obtain access token + let access_token = self + .get_cached_access_token(account_id) + .await + .caused_by(trc::location!())?; + + match self.issue_id_token( + account_id.to_string(), + issuer, + client_id, + StandardClaims { + nonce, + preferred_username: access_token.name.clone().into(), + email: access_token.emails.first().cloned(), + }, + ) { Ok(id_token) => Some(id_token), Err(err) => { trc::error!(err); diff --git a/tests/src/jmap/auth_oauth.rs b/tests/src/jmap/auth_oauth.rs index 7230759f..83b43d53 100644 --- a/tests/src/jmap/auth_oauth.rs +++ b/tests/src/jmap/auth_oauth.rs @@ -11,7 +11,7 @@ use biscuit::{jwk::JWKSet, SingleOrMultiple, JWT}; use bytes::Bytes; use common::auth::oauth::{ introspect::OAuthIntrospect, - oidc::Nonce, + oidc::StandardClaims, registration::{ClientRegistrationRequest, ClientRegistrationResponse}, }; use imap_proto::ResponseType; @@ -156,7 +156,7 @@ pub async fn test(params: &mut JMAPTest) { .is_empty()); // Verify ID token using the JWK set - let id_token = JWT::::new_encoded(&id_token) + let id_token = JWT::::new_encoded(&id_token) .decode_with_jwks(&jwk_set, None) .unwrap(); let claims = id_token.payload().unwrap(); @@ -169,6 +169,11 @@ pub async fn test(params: &mut JMAPTest) { Some(SingleOrMultiple::Single(client_id.to_string())) ); assert_eq!(private_claims.nonce, Some("abc1234".to_string())); + assert_eq!( + private_claims.preferred_username, + Some("jdoe@example.com".to_string()) + ); + assert_eq!(private_claims.email, Some("jdoe@example.com".to_string())); // Introspect token let access_introspect: OAuthIntrospect = post_with_auth::( diff --git a/tests/src/jmap/mod.rs b/tests/src/jmap/mod.rs index a5feeb7d..58f4ba52 100644 --- a/tests/src/jmap/mod.rs +++ b/tests/src/jmap/mod.rs @@ -384,12 +384,12 @@ pub async fn jmap_tests() { mailbox::test(&mut params).await; delivery::test(&mut params).await; auth_acl::test(&mut params).await; - auth_limits::test(&mut params).await; + auth_limits::test(&mut params).await;*/ auth_oauth::test(&mut params).await; - event_source::test(&mut params).await; - push_subscription::test(&mut params).await;*/ + /*event_source::test(&mut params).await; + push_subscription::test(&mut params).await; sieve_script::test(&mut params).await; - /*vacation_response::test(&mut params).await; + vacation_response::test(&mut params).await; email_submission::test(&mut params).await; websocket::test(&mut params).await; quota::test(&mut params).await;