Can sign in and sign out

This commit is contained in:
Pierre HUBERT 2025-01-21 21:40:07 +01:00
parent fffa561d43
commit 2f8fd66648
3 changed files with 75 additions and 7 deletions

View File

@ -29,6 +29,8 @@ async fn main() -> std::io::Result<()> {
))
// Web configuration routes
.route("/", web::get().to(web_ui::home))
.route("/oidc_cb", web::get().to(web_ui::oidc_cb))
.route("/sign_out", web::get().to(web_ui::sign_out))
// API routes
// TODO

View File

@ -1,17 +1,18 @@
use crate::app_config::AppConfig;
use crate::constants::{STATE_KEY, USER_SESSION_KEY};
use crate::server::{HttpFailure, HttpResult};
use crate::user::User;
use crate::user::{User, UserID};
use crate::utils;
use actix_session::Session;
use actix_web::HttpResponse;
use actix_web::{web, HttpResponse};
use light_openid::primitives::OpenIDConfig;
// Main route
pub async fn home(session: Session) -> HttpResult {
// Get user information
// Get user information, requesting authentication if information is missing
let Some(user): Option<User> = session.get(USER_SESSION_KEY)? else {
// Generate auth state
let state = utils::rand_str(10);
let state = utils::rand_str(50);
session.insert(STATE_KEY, &state)?;
let oidc = AppConfig::get().openid_provider();
@ -28,3 +29,68 @@ pub async fn home(session: Session) -> HttpResult {
Ok(HttpResponse::Ok().body("You are authenticated!"))
}
#[derive(serde::Deserialize)]
pub struct AuthCallbackQuery {
code: String,
state: String,
}
// Authenticate user callback
pub async fn oidc_cb(session: Session, query: web::Query<AuthCallbackQuery>) -> HttpResult {
if session.get(STATE_KEY)? != Some(query.state.to_string()) {
return Ok(HttpResponse::BadRequest()
.append_header(("content-type", "text/html"))
.body("State mismatch! <a href='/'>Try again</a>"));
}
let oidc = AppConfig::get().openid_provider();
let config = OpenIDConfig::load_from_url(oidc.configuration_url)
.await
.map_err(HttpFailure::OpenID)?;
let (token, _) = match config
.request_token(
oidc.client_id,
oidc.client_secret,
&query.code,
&oidc.redirect_url,
)
.await
{
Ok(t) => t,
Err(e) => {
log::error!("Failed to request user token! {e}");
return Ok(HttpResponse::BadRequest()
.append_header(("content-type", "text/html"))
.body("Authentication failed! <a href='/'>Try again</a>"));
}
};
let (user, _) = config
.request_user_info(&token)
.await
.map_err(HttpFailure::OpenID)?;
let user = User {
id: UserID(user.sub),
name: user.name.unwrap_or("no_name".to_string()),
email: user.email.unwrap_or("no@mail.com".to_string()),
};
log::info!("Successful authentication as {:?}", user);
session.insert(USER_SESSION_KEY, user)?;
Ok(HttpResponse::Found()
.insert_header(("location", "/"))
.finish())
}
/// De-authenticate user
pub async fn sign_out(session: Session) -> HttpResult {
session.remove(USER_SESSION_KEY);
Ok(HttpResponse::Found()
.insert_header(("location", "/"))
.finish())
}

View File

@ -1,7 +1,7 @@
#[derive(Clone, serde::Serialize, serde::Deserialize)]
pub struct UserID(String);
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
pub struct UserID(pub String);
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
pub struct User {
pub id: UserID,
pub name: String,