Add authentication from upstream providers #107
@ -20,8 +20,7 @@ use crate::data::code_challenge::CodeChallenge;
|
|||||||
use crate::data::current_user::CurrentUser;
|
use crate::data::current_user::CurrentUser;
|
||||||
use crate::data::id_token::IdToken;
|
use crate::data::id_token::IdToken;
|
||||||
use crate::data::jwt_signer::{JWTSigner, JsonWebKey};
|
use crate::data::jwt_signer::{JWTSigner, JsonWebKey};
|
||||||
use crate::data::open_id_user_info::OpenIDUserInfo;
|
use crate::data::openid_primitive::{OpenIDConfig, OpenIDUserInfo, TokenResponse};
|
||||||
use crate::data::openid_primitive::{OpenIDConfig, TokenResponse};
|
|
||||||
use crate::data::session_identity::SessionIdentity;
|
use crate::data::session_identity::SessionIdentity;
|
||||||
use crate::data::user::User;
|
use crate::data::user::User;
|
||||||
use crate::utils::string_utils::rand_str;
|
use crate::utils::string_utils::rand_str;
|
||||||
@ -627,12 +626,12 @@ async fn user_info(
|
|||||||
};
|
};
|
||||||
|
|
||||||
HttpResponse::Ok().json(OpenIDUserInfo {
|
HttpResponse::Ok().json(OpenIDUserInfo {
|
||||||
name: user.full_name(),
|
name: Some(user.full_name()),
|
||||||
sub: user.uid.0,
|
sub: user.uid.0,
|
||||||
given_name: user.first_name,
|
given_name: Some(user.first_name),
|
||||||
family_name: user.last_name,
|
family_name: Some(user.last_name),
|
||||||
preferred_username: user.username,
|
preferred_username: Some(user.username),
|
||||||
email: user.email,
|
email: Some(user.email),
|
||||||
email_verified: true,
|
email_verified: Some(true),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -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 user is authorized to access application
|
||||||
// TODO : check if 2FA is enabled
|
// TODO : check if 2FA is enabled
|
||||||
// TODO : redirect user to login route
|
// TODO : redirect user to login route
|
||||||
|
@ -1,24 +1 @@
|
|||||||
/// Refer to <https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims> 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,
|
|
||||||
}
|
|
||||||
|
@ -72,3 +72,36 @@ pub struct TokenResponse {
|
|||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub id_token: Option<String>,
|
pub id_token: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Refer to <https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims> 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<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.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub given_name: Option<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.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub family_name: Option<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
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub preferred_username: Option<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.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub email: Option<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.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub email_verified: Option<bool>,
|
||||||
|
}
|
||||||
|
@ -8,7 +8,7 @@ use crate::actors::providers_states_actor::ProviderLoginState;
|
|||||||
use crate::constants::OIDC_PROVIDERS_LIFETIME;
|
use crate::constants::OIDC_PROVIDERS_LIFETIME;
|
||||||
use crate::data::app_config::AppConfig;
|
use crate::data::app_config::AppConfig;
|
||||||
use crate::data::jwt_signer::JsonWebKey;
|
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::data::provider::Provider;
|
||||||
use crate::utils::err::Res;
|
use crate::utils::err::Res;
|
||||||
use crate::utils::time::time;
|
use crate::utils::time::time;
|
||||||
@ -32,7 +32,7 @@ pub struct ProviderJWKs {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ProviderConfiguration {
|
pub struct ProviderConfiguration {
|
||||||
pub discovery: ProviderDiscovery,
|
pub discovery: ProviderDiscovery,
|
||||||
pub keys: ProviderJWKs,
|
//pub keys: ProviderJWKs,
|
||||||
pub expire: u64,
|
pub expire: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,6 +72,22 @@ impl ProviderConfiguration {
|
|||||||
.json()
|
.json()
|
||||||
.await?)
|
.await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieve information about the user, using given [TokenResponse]
|
||||||
|
pub async fn get_userinfo(&self, token: &TokenResponse) -> Res<OpenIDUserInfo> {
|
||||||
|
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! {
|
thread_local! {
|
||||||
@ -108,11 +124,11 @@ impl ProviderConfigurationHelper {
|
|||||||
.json()
|
.json()
|
||||||
.await?;
|
.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 {
|
Ok(ProviderConfiguration {
|
||||||
discovery,
|
discovery,
|
||||||
keys,
|
// keys,
|
||||||
expire: time() + OIDC_PROVIDERS_LIFETIME,
|
expire: time() + OIDC_PROVIDERS_LIFETIME,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user