From bf20e5ad139c0b23090fcca59ae8e32e1eb7ce78 Mon Sep 17 00:00:00 2001 From: Pierre Hubert Date: Wed, 26 Apr 2023 14:37:31 +0200 Subject: [PATCH] Query userinfo endpoint --- src/controllers/openid_controller.rs | 15 ++++++----- src/controllers/providers_controller.rs | 5 ++-- src/data/open_id_user_info.rs | 23 ----------------- src/data/openid_primitive.rs | 33 +++++++++++++++++++++++++ src/data/provider_configuration.rs | 24 +++++++++++++++--- 5 files changed, 63 insertions(+), 37 deletions(-) diff --git a/src/controllers/openid_controller.rs b/src/controllers/openid_controller.rs index d1b5daf..c3127cd 100644 --- a/src/controllers/openid_controller.rs +++ b/src/controllers/openid_controller.rs @@ -20,8 +20,7 @@ use crate::data::code_challenge::CodeChallenge; use crate::data::current_user::CurrentUser; use crate::data::id_token::IdToken; use crate::data::jwt_signer::{JWTSigner, JsonWebKey}; -use crate::data::open_id_user_info::OpenIDUserInfo; -use crate::data::openid_primitive::{OpenIDConfig, TokenResponse}; +use crate::data::openid_primitive::{OpenIDConfig, OpenIDUserInfo, TokenResponse}; use crate::data::session_identity::SessionIdentity; use crate::data::user::User; use crate::utils::string_utils::rand_str; @@ -627,12 +626,12 @@ async fn user_info( }; HttpResponse::Ok().json(OpenIDUserInfo { - name: user.full_name(), + name: Some(user.full_name()), sub: user.uid.0, - given_name: user.first_name, - family_name: user.last_name, - preferred_username: user.username, - email: user.email, - email_verified: true, + given_name: Some(user.first_name), + family_name: Some(user.last_name), + preferred_username: Some(user.username), + email: Some(user.email), + email_verified: Some(true), }) } diff --git a/src/controllers/providers_controller.rs b/src/controllers/providers_controller.rs index 74cd64b..18e21f6 100644 --- a/src/controllers/providers_controller.rs +++ b/src/controllers/providers_controller.rs @@ -225,9 +225,10 @@ pub async fn finish_login( } }; - println!("go on {:?}", token); + // Use access token to get user information + let info = provider_config.get_userinfo(&token).await; + println!("info: {:?}", info); - // TODO : check token signature // TODO : check if user is authorized to access application // TODO : check if 2FA is enabled // TODO : redirect user to login route diff --git a/src/data/open_id_user_info.rs b/src/data/open_id_user_info.rs index 04d35bc..8b13789 100644 --- a/src/data/open_id_user_info.rs +++ b/src/data/open_id_user_info.rs @@ -1,24 +1 @@ -/// Refer to for more information -#[derive(Debug, serde::Serialize)] -pub struct OpenIDUserInfo { - /// Subject - Identifier for the End-User at the Issuer - pub sub: String, - /// End-User's full name in displayable form including all name parts, possibly including titles and suffixes, ordered according to the End-User's locale and preferences. - pub name: String, - - /// Given name(s) or first name(s) of the End-User. Note that in some cultures, people can have multiple given names; all can be present, with the names being separated by space characters. - pub given_name: String, - - /// Surname(s) or last name(s) of the End-User. Note that in some cultures, people can have multiple family names or no family name; all can be present, with the names being separated by space characters. - pub family_name: String, - - /// Shorthand name by which the End-User wishes to be referred to at the RP, such as janedoe or j.doe. This value MAY be any valid JSON string including special characters such as @, /, or whitespace. The RP MUST NOT rely upon this value being unique, as discussed in - pub preferred_username: String, - - /// End-User's preferred e-mail address. Its value MUST conform to the RFC 5322 RFC5322 addr-spec syntax. The RP MUST NOT rely upon this value being unique, as discussed in Section 5.7. - pub email: String, - - /// True if the End-User's e-mail address has been verified; otherwise false. When this Claim Value is true, this means that the OP took affirmative steps to ensure that this e-mail address was controlled by the End-User at the time the verification was performed. The means by which an e-mail address is verified is context-specific, and dependent upon the trust framework or contractual agreements within which the parties are operating. - pub email_verified: bool, -} diff --git a/src/data/openid_primitive.rs b/src/data/openid_primitive.rs index 158633c..86e63e1 100644 --- a/src/data/openid_primitive.rs +++ b/src/data/openid_primitive.rs @@ -72,3 +72,36 @@ pub struct TokenResponse { #[serde(skip_serializing_if = "Option::is_none")] pub id_token: Option, } + +/// Refer to for more information +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct OpenIDUserInfo { + /// Subject - Identifier for the End-User at the Issuer + /// + /// This is the only mandatory field + pub sub: String, + + /// End-User's full name in displayable form including all name parts, possibly including titles and suffixes, ordered according to the End-User's locale and preferences. + #[serde(skip_serializing_if = "Option::is_none")] + pub name: Option, + + /// Given name(s) or first name(s) of the End-User. Note that in some cultures, people can have multiple given names; all can be present, with the names being separated by space characters. + #[serde(skip_serializing_if = "Option::is_none")] + pub given_name: Option, + + /// Surname(s) or last name(s) of the End-User. Note that in some cultures, people can have multiple family names or no family name; all can be present, with the names being separated by space characters. + #[serde(skip_serializing_if = "Option::is_none")] + pub family_name: Option, + + /// Shorthand name by which the End-User wishes to be referred to at the RP, such as janedoe or j.doe. This value MAY be any valid JSON string including special characters such as @, /, or whitespace. The RP MUST NOT rely upon this value being unique, as discussed in + #[serde(skip_serializing_if = "Option::is_none")] + pub preferred_username: Option, + + /// End-User's preferred e-mail address. Its value MUST conform to the RFC 5322 RFC5322 addr-spec syntax. The RP MUST NOT rely upon this value being unique, as discussed in Section 5.7. + #[serde(skip_serializing_if = "Option::is_none")] + pub email: Option, + + /// True if the End-User's e-mail address has been verified; otherwise false. When this Claim Value is true, this means that the OP took affirmative steps to ensure that this e-mail address was controlled by the End-User at the time the verification was performed. The means by which an e-mail address is verified is context-specific, and dependent upon the trust framework or contractual agreements within which the parties are operating. + #[serde(skip_serializing_if = "Option::is_none")] + pub email_verified: Option, +} diff --git a/src/data/provider_configuration.rs b/src/data/provider_configuration.rs index e0a5d95..eaf079e 100644 --- a/src/data/provider_configuration.rs +++ b/src/data/provider_configuration.rs @@ -8,7 +8,7 @@ use crate::actors::providers_states_actor::ProviderLoginState; use crate::constants::OIDC_PROVIDERS_LIFETIME; use crate::data::app_config::AppConfig; use crate::data::jwt_signer::JsonWebKey; -use crate::data::openid_primitive::TokenResponse; +use crate::data::openid_primitive::{OpenIDUserInfo, TokenResponse}; use crate::data::provider::Provider; use crate::utils::err::Res; use crate::utils::time::time; @@ -32,7 +32,7 @@ pub struct ProviderJWKs { #[derive(Debug, Clone)] pub struct ProviderConfiguration { pub discovery: ProviderDiscovery, - pub keys: ProviderJWKs, + //pub keys: ProviderJWKs, pub expire: u64, } @@ -72,6 +72,22 @@ impl ProviderConfiguration { .json() .await?) } + + /// Retrieve information about the user, using given [TokenResponse] + pub async fn get_userinfo(&self, token: &TokenResponse) -> Res { + Ok(reqwest::Client::new() + .get( + self.discovery + .userinfo_endpoint + .as_ref() + .expect("Userinfo endpoint is required by this implementation!"), + ) + .header("Authorization", format!("Bearer {}", token.access_token)) + .send() + .await? + .json() + .await?) + } } thread_local! { @@ -108,11 +124,11 @@ impl ProviderConfigurationHelper { .json() .await?; - let keys: ProviderJWKs = reqwest::get(&discovery.jwks_uri).await?.json().await?; + // let keys: ProviderJWKs = reqwest::get(&discovery.jwks_uri).await?.json().await?; Ok(ProviderConfiguration { discovery, - keys, + // keys, expire: time() + OIDC_PROVIDERS_LIFETIME, }) }