refactor: HttpSession/OptionalHttpSession axum extractors
This commit is contained in:
parent
e28c584b26
commit
44c083a8ef
7 changed files with 111 additions and 81 deletions
|
|
@ -1,23 +1,17 @@
|
|||
use axum::extract::{Form, Path, State};
|
||||
use axum::response::{Html, IntoResponse, Redirect, Response};
|
||||
use axum_extra::extract::cookie::CookieJar;
|
||||
use http::StatusCode;
|
||||
use minijinja::context;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::db::{DatabaseInterface, Operation};
|
||||
use crate::http::HttpState;
|
||||
use crate::http::login::login_page;
|
||||
use crate::http::{HttpSession, HttpState};
|
||||
|
||||
pub async fn get_domain<D: DatabaseInterface>(
|
||||
State(state): State<HttpState<D>>,
|
||||
cookies: CookieJar,
|
||||
session: HttpSession,
|
||||
Path(domain): Path<String>,
|
||||
) -> Response {
|
||||
let Some(session) = state.sessions.get_session(&cookies) else {
|
||||
return login_page(State(state), None).await.into_response();
|
||||
};
|
||||
|
||||
let domain = match state.db.get_domain(&domain).await {
|
||||
Ok(Some(domain)) => domain,
|
||||
Ok(None) => return format!("Domain not found: {domain}").into_response(),
|
||||
|
|
@ -61,13 +55,9 @@ pub struct DomainCreationForm {
|
|||
|
||||
pub async fn create_domain<D: DatabaseInterface>(
|
||||
State(mut state): State<HttpState<D>>,
|
||||
cookies: CookieJar,
|
||||
session: HttpSession,
|
||||
Form(form): Form<DomainCreationForm>,
|
||||
) -> Response {
|
||||
let Some(session) = state.sessions.get_session(&cookies) else {
|
||||
return login_page(State(state), None).await.into_response();
|
||||
};
|
||||
|
||||
let op = Operation::CreateDomain;
|
||||
if !session.user.can_perform(&op) {
|
||||
return "Not authorized to create a new domain".into_response();
|
||||
|
|
|
|||
|
|
@ -1,18 +1,16 @@
|
|||
use axum::extract::State;
|
||||
use axum::response::{Html, IntoResponse, Response};
|
||||
use axum_extra::extract::cookie::CookieJar;
|
||||
use http::StatusCode;
|
||||
use minijinja::context;
|
||||
|
||||
use crate::db::{DatabaseInterface, Operation};
|
||||
use crate::http::HttpState;
|
||||
use crate::http::login::login_page;
|
||||
use crate::http::{HttpSession, HttpState};
|
||||
|
||||
pub async fn home<D: DatabaseInterface>(
|
||||
State(state): State<HttpState<D>>,
|
||||
cookies: CookieJar,
|
||||
// Only logged in users are allowed here
|
||||
session: HttpSession,
|
||||
) -> Response {
|
||||
if let Some(session) = state.sessions.get_session(&cookies) {
|
||||
// When the user has no domain (service admin) list all domains
|
||||
let op = Operation::ListUsers(session.user.domain.clone());
|
||||
let other_users = if session.user.can_perform(&op) {
|
||||
|
|
@ -57,7 +55,4 @@ pub async fn home<D: DatabaseInterface>(
|
|||
.render(ctx)
|
||||
.unwrap();
|
||||
(StatusCode::OK, Html(page)).into_response()
|
||||
} else {
|
||||
login_page(State(state), None).await
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use minijinja::context;
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::db::{DatabaseInterface, UserRef};
|
||||
use crate::http::HttpState;
|
||||
use crate::http::{HttpState, OptionalHttpSession};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct LoginForm {
|
||||
|
|
@ -33,12 +33,24 @@ pub async fn login_page<D: DatabaseInterface>(
|
|||
(StatusCode::OK, Html(page)).into_response()
|
||||
}
|
||||
|
||||
pub async fn get_login<D: DatabaseInterface>(
|
||||
State(state): State<HttpState<D>>,
|
||||
maybe_session: Option<OptionalHttpSession>,
|
||||
) -> Response {
|
||||
if maybe_session.is_some() {
|
||||
return Redirect::to("/").into_response();
|
||||
}
|
||||
|
||||
login_page(State(state), None).await
|
||||
}
|
||||
|
||||
pub async fn post_login<D: DatabaseInterface>(
|
||||
State(state): State<HttpState<D>>,
|
||||
session: Option<OptionalHttpSession>,
|
||||
cookies: CookieJar,
|
||||
Form(form): Form<LoginForm>,
|
||||
) -> Response {
|
||||
if let Some(_session) = state.sessions.get_session(&cookies) {
|
||||
if session.is_some() {
|
||||
// Already logged in
|
||||
return (cookies, Redirect::to("/")).into_response();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,14 +3,15 @@ use axum::response::{IntoResponse, Redirect, Response};
|
|||
use axum_extra::extract::cookie::CookieJar;
|
||||
|
||||
use crate::db::DatabaseInterface;
|
||||
use crate::http::HttpState;
|
||||
use crate::http::login::{LoginError, login_page};
|
||||
use crate::http::{HttpState, OptionalHttpSession};
|
||||
|
||||
pub async fn logout<D: DatabaseInterface>(
|
||||
State(state): State<HttpState<D>>,
|
||||
session: Option<OptionalHttpSession>,
|
||||
cookies: CookieJar,
|
||||
) -> Response {
|
||||
let Some(session) = state.sessions.get_session(&cookies) else {
|
||||
let Some(session) = session else {
|
||||
return (cookies, Redirect::to("/")).into_response();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ mod home;
|
|||
mod login;
|
||||
mod logout;
|
||||
mod session;
|
||||
use session::HttpSessionManager;
|
||||
use session::{HttpSession, HttpSessionManager, OptionalHttpSession};
|
||||
mod user;
|
||||
|
||||
impl AxumListener for Listener {
|
||||
|
|
@ -98,7 +98,7 @@ pub async fn http_listen<D: DatabaseInterface>(listener: Listener, db: Database<
|
|||
let app = { Router::new().nest_service("/assets", ServeDir::new("assets")) };
|
||||
let app = app
|
||||
.route("/", get(home::home))
|
||||
.route("/login", get(home::home))
|
||||
.route("/login", get(login::get_login))
|
||||
.route("/login", post(login::post_login))
|
||||
.route("/logout", get(logout::logout))
|
||||
.route("/domain/{domain}", get(domain::get_domain))
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
use axum::extract::{FromRequestParts, OptionalFromRequestParts};
|
||||
use axum::response::Redirect;
|
||||
use axum_extra::extract::cookie::{Cookie, CookieJar};
|
||||
use http::request::Parts;
|
||||
use uuid::Uuid;
|
||||
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use crate::db::User;
|
||||
use crate::db::{DatabaseInterface, User};
|
||||
use crate::http::HttpState;
|
||||
|
||||
pub const COOKIE_NAME: &str = "lldap_session";
|
||||
|
||||
|
|
@ -78,3 +82,43 @@ impl PartialEq<HttpSession> for HttpSession {
|
|||
self.uuid == other.uuid
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DatabaseInterface> FromRequestParts<HttpState<D>> for HttpSession {
|
||||
type Rejection = Redirect;
|
||||
|
||||
async fn from_request_parts(
|
||||
parts: &mut Parts,
|
||||
state: &HttpState<D>,
|
||||
) -> Result<Self, Self::Rejection> {
|
||||
let cookies = CookieJar::from_request_parts(parts, state).await.unwrap();
|
||||
state
|
||||
.sessions
|
||||
.get_session(&cookies)
|
||||
.ok_or(Redirect::to("/login"))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OptionalHttpSession(pub HttpSession);
|
||||
|
||||
impl std::ops::Deref for OptionalHttpSession {
|
||||
type Target = HttpSession;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DatabaseInterface> OptionalFromRequestParts<HttpState<D>> for OptionalHttpSession {
|
||||
type Rejection = Redirect;
|
||||
|
||||
async fn from_request_parts(
|
||||
parts: &mut Parts,
|
||||
state: &HttpState<D>,
|
||||
) -> Result<Option<Self>, Self::Rejection> {
|
||||
let maybe_session = HttpSession::from_request_parts(parts, state)
|
||||
.await
|
||||
.ok()
|
||||
.map(Self);
|
||||
Ok(maybe_session)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
use axum::extract::{Form, State};
|
||||
use axum::response::{IntoResponse, Redirect, Response};
|
||||
use axum_extra::extract::cookie::CookieJar;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::db::{DatabaseInterface, Role, User};
|
||||
use crate::http::HttpState;
|
||||
use crate::http::login::login_page;
|
||||
use crate::http::{HttpSession, HttpState};
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct UserCreationForm {
|
||||
|
|
@ -16,19 +14,9 @@ pub struct UserCreationForm {
|
|||
|
||||
pub async fn create_user<D: DatabaseInterface>(
|
||||
State(mut state): State<HttpState<D>>,
|
||||
cookies: CookieJar,
|
||||
session: HttpSession,
|
||||
Form(form): Form<UserCreationForm>,
|
||||
) -> Response {
|
||||
let Some(session) = state.sessions.get_session(&cookies) else {
|
||||
return login_page(State(state), None).await.into_response();
|
||||
};
|
||||
|
||||
// let domain = form.domain;
|
||||
// let op = Operation::CreateUser(domain.clone());
|
||||
// if !session.user.can_perform(&op) {
|
||||
// return format!("Not authorized to create a new user on domain {domain}").into_response()
|
||||
// }
|
||||
|
||||
let new_user = User {
|
||||
mail: format!("{}@{}", form.username, form.domain),
|
||||
username: form.username.clone(),
|
||||
|
|
|
|||
Loading…
Reference in a new issue