Can sign in and sign out
This commit is contained in:
parent
fffa561d43
commit
2f8fd66648
@ -29,6 +29,8 @@ async fn main() -> std::io::Result<()> {
|
|||||||
))
|
))
|
||||||
// Web configuration routes
|
// Web configuration routes
|
||||||
.route("/", web::get().to(web_ui::home))
|
.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
|
// API routes
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
use crate::app_config::AppConfig;
|
use crate::app_config::AppConfig;
|
||||||
use crate::constants::{STATE_KEY, USER_SESSION_KEY};
|
use crate::constants::{STATE_KEY, USER_SESSION_KEY};
|
||||||
use crate::server::{HttpFailure, HttpResult};
|
use crate::server::{HttpFailure, HttpResult};
|
||||||
use crate::user::User;
|
use crate::user::{User, UserID};
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
use actix_session::Session;
|
use actix_session::Session;
|
||||||
use actix_web::HttpResponse;
|
use actix_web::{web, HttpResponse};
|
||||||
use light_openid::primitives::OpenIDConfig;
|
use light_openid::primitives::OpenIDConfig;
|
||||||
|
|
||||||
|
// Main route
|
||||||
pub async fn home(session: Session) -> HttpResult {
|
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 {
|
let Some(user): Option<User> = session.get(USER_SESSION_KEY)? else {
|
||||||
// Generate auth state
|
// Generate auth state
|
||||||
let state = utils::rand_str(10);
|
let state = utils::rand_str(50);
|
||||||
session.insert(STATE_KEY, &state)?;
|
session.insert(STATE_KEY, &state)?;
|
||||||
|
|
||||||
let oidc = AppConfig::get().openid_provider();
|
let oidc = AppConfig::get().openid_provider();
|
||||||
@ -28,3 +29,68 @@ pub async fn home(session: Session) -> HttpResult {
|
|||||||
|
|
||||||
Ok(HttpResponse::Ok().body("You are authenticated!"))
|
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())
|
||||||
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#[derive(Clone, serde::Serialize, serde::Deserialize)]
|
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
||||||
pub struct UserID(String);
|
pub struct UserID(pub String);
|
||||||
|
|
||||||
#[derive(serde::Serialize, serde::Deserialize)]
|
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
pub id: UserID,
|
pub id: UserID,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
Loading…
Reference in New Issue
Block a user