Finish OIDC login
This commit is contained in:
moneymgr_backend
@ -1,7 +1,9 @@
|
||||
use crate::app_config::AppConfig;
|
||||
use crate::controllers::HttpResult;
|
||||
use crate::controllers::{HttpFailure, HttpResult};
|
||||
use crate::extractors::money_session::MoneySession;
|
||||
use actix_web::HttpResponse;
|
||||
use crate::services::users_service;
|
||||
use actix_remote_ip::RemoteIP;
|
||||
use actix_web::{HttpResponse, web};
|
||||
use light_openid::primitives::OpenIDConfig;
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
@ -10,7 +12,7 @@ struct StartOIDCResponse {
|
||||
}
|
||||
|
||||
/// Start OIDC authentication
|
||||
pub async fn start_oidc(session: MoneySession) -> HttpResult {
|
||||
pub async fn start_oidc(session: MoneySession, remote_ip: RemoteIP) -> HttpResult {
|
||||
let prov = AppConfig::get().openid_provider();
|
||||
|
||||
let conf = match OpenIDConfig::load_from_url(prov.configuration_url).await {
|
||||
@ -22,7 +24,7 @@ pub async fn start_oidc(session: MoneySession) -> HttpResult {
|
||||
}
|
||||
};
|
||||
|
||||
let state = match session.gen_oidc_state() {
|
||||
let state = match session.gen_oidc_state(remote_ip.0) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
log::error!("Failed to generate auth state! {e}");
|
||||
@ -39,4 +41,66 @@ pub async fn start_oidc(session: MoneySession) -> HttpResult {
|
||||
}))
|
||||
}
|
||||
|
||||
// TODO : take from previous projects
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct FinishOpenIDLoginQuery {
|
||||
code: String,
|
||||
state: String,
|
||||
}
|
||||
|
||||
/// Finish OIDC authentication
|
||||
pub async fn finish_oidc(
|
||||
session: MoneySession,
|
||||
remote_ip: RemoteIP,
|
||||
req: web::Json<FinishOpenIDLoginQuery>,
|
||||
) -> HttpResult {
|
||||
if let Err(e) = session.validate_state(&req.state, remote_ip.0) {
|
||||
log::error!("Failed to validate OIDC CB state! {e}");
|
||||
return Ok(HttpResponse::BadRequest().json("Invalid state!"));
|
||||
}
|
||||
|
||||
let prov = AppConfig::get().openid_provider();
|
||||
|
||||
let conf = OpenIDConfig::load_from_url(prov.configuration_url)
|
||||
.await
|
||||
.map_err(HttpFailure::OpenID)?;
|
||||
|
||||
let (token, _) = conf
|
||||
.request_token(
|
||||
prov.client_id,
|
||||
prov.client_secret,
|
||||
&req.code,
|
||||
&AppConfig::get().oidc_redirect_url(),
|
||||
)
|
||||
.await
|
||||
.map_err(HttpFailure::OpenID)?;
|
||||
let (user_info, _) = conf
|
||||
.request_user_info(&token)
|
||||
.await
|
||||
.map_err(HttpFailure::OpenID)?;
|
||||
|
||||
if user_info.email_verified != Some(true) {
|
||||
log::error!("Email is not verified!");
|
||||
return Ok(HttpResponse::Unauthorized().json("Email unverified by IDP!"));
|
||||
}
|
||||
|
||||
let mail = match user_info.email {
|
||||
Some(m) => m,
|
||||
None => {
|
||||
return Ok(HttpResponse::Unauthorized().json("Email not provided by the IDP!"));
|
||||
}
|
||||
};
|
||||
|
||||
let user_name = user_info.name.unwrap_or_else(|| {
|
||||
format!(
|
||||
"{} {}",
|
||||
user_info.given_name.as_deref().unwrap_or(""),
|
||||
user_info.family_name.as_deref().unwrap_or("")
|
||||
)
|
||||
});
|
||||
|
||||
let user = users_service::create_or_update_user(&mail, &user_name).await?;
|
||||
|
||||
session.set_user(&user)?;
|
||||
|
||||
Ok(HttpResponse::Ok().finish())
|
||||
}
|
||||
|
Reference in New Issue
Block a user