Added function to get all roles of members
This commit is contained in:
parent
31aa9dc066
commit
29bfa8c60e
@ -1,21 +1,8 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use argon2::{
|
||||
password_hash::{rand_core::OsRng, PasswordHasher, SaltString},
|
||||
Argon2, PasswordHash, PasswordVerifier,
|
||||
};
|
||||
use axum::{
|
||||
extract::FromRequestParts,
|
||||
http::{header, request::Parts, HeaderMap, StatusCode},
|
||||
RequestPartsExt,
|
||||
};
|
||||
use axum_extra::{
|
||||
extract::cookie::{Cookie, CookieJar},
|
||||
headers::{authorization::Bearer, Authorization},
|
||||
typed_header::TypedHeaderRejectionReason,
|
||||
TypedHeader,
|
||||
};
|
||||
use bearer::verify_bearer;
|
||||
use axum::http::{header, HeaderMap};
|
||||
use chrono::Utc;
|
||||
pub use error::AuthError;
|
||||
use rand::distr::Alphanumeric;
|
||||
@ -24,58 +11,17 @@ use rand_chacha::ChaCha20Rng;
|
||||
use sqlx::PgPool;
|
||||
use tokio::task;
|
||||
|
||||
use crate::{database::model::Session, model::User};
|
||||
use crate::{
|
||||
database::model::{Session, UserMember},
|
||||
model::{member::Roles, User},
|
||||
};
|
||||
|
||||
mod bearer;
|
||||
mod error;
|
||||
mod scopes;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Permissions<'a>(pub HashSet<&'a str>);
|
||||
|
||||
// Middleware for getting permissions
|
||||
impl<S> FromRequestParts<S> for Permissions<'_>
|
||||
where
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = crate::Error;
|
||||
|
||||
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
// First check if the request has a beaerer token to authenticate
|
||||
match parts.extract::<TypedHeader<Authorization<Bearer>>>().await {
|
||||
Ok(bearer) => {
|
||||
verify_bearer(bearer.token().to_string()).map_err(|_| AuthError::InvalidToken)?;
|
||||
|
||||
let permissions = Permissions {
|
||||
0: HashSet::from(["root"]),
|
||||
};
|
||||
|
||||
return Ok(permissions);
|
||||
}
|
||||
Err(err) => match err.reason() {
|
||||
TypedHeaderRejectionReason::Missing => (),
|
||||
TypedHeaderRejectionReason::Error(_err) => {
|
||||
return Err(AuthError::InvalidToken.into())
|
||||
}
|
||||
_ => return Err(AuthError::Unexpected.into()),
|
||||
},
|
||||
};
|
||||
|
||||
match parts.extract::<CookieJar>().await {
|
||||
Ok(jar) => {
|
||||
if let Some(session_token) = jar.get("session_token") {
|
||||
// TODO: Implement function to retrieve user permissions
|
||||
tracing::info!("{session_token:?}")
|
||||
}
|
||||
}
|
||||
Err(_) => (),
|
||||
}
|
||||
|
||||
Err(AuthError::Unauthorized.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_user_from_header(pool: &PgPool, headers: &HeaderMap) -> Result<User, AuthError> {
|
||||
pub async fn get_user_from_header(
|
||||
pool: &PgPool,
|
||||
headers: &HeaderMap,
|
||||
) -> Result<(Roles, User), AuthError> {
|
||||
let bearer_value = headers.get(header::AUTHORIZATION);
|
||||
let bearer_value = bearer_value
|
||||
.ok_or_else(|| AuthError::InvalidToken)?
|
||||
@ -84,8 +30,6 @@ pub async fn get_user_from_header(pool: &PgPool, headers: &HeaderMap) -> Result<
|
||||
|
||||
let token = get_token_from_bearer(bearer_value)?;
|
||||
|
||||
let potential_user = match token.split_once("_") {
|
||||
Some(("ses", _)) => {
|
||||
let session = match Session::from_token(&pool, &token).await {
|
||||
Ok(s) => s,
|
||||
Err(_) => return Err(AuthError::InvalidToken),
|
||||
@ -100,12 +44,11 @@ pub async fn get_user_from_header(pool: &PgPool, headers: &HeaderMap) -> Result<
|
||||
Err(_) => return Err(AuthError::InvalidToken),
|
||||
};
|
||||
|
||||
db_user.into()
|
||||
}
|
||||
_ => return Err(AuthError::InvalidToken),
|
||||
};
|
||||
let roles = UserMember::get_roles(&pool, &db_user.user_id)
|
||||
.await
|
||||
.unwrap_or(Roles::MEMBER);
|
||||
|
||||
Ok(potential_user)
|
||||
Ok((roles, db_user.into()))
|
||||
}
|
||||
|
||||
pub fn get_token_from_bearer(bearer: &str) -> Result<String, AuthError> {
|
||||
|
@ -1,8 +0,0 @@
|
||||
pub fn verify_bearer(token: String) -> Result<(), ()> {
|
||||
let env_api_token = dotenvy::var("API_TOKEN").map_err(|_| ())?;
|
||||
|
||||
match env_api_token == token {
|
||||
true => Ok(()),
|
||||
false => Err(()),
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
|
@ -1,5 +1,7 @@
|
||||
use sqlx::{PgPool, Postgres};
|
||||
|
||||
use crate::model::member::Roles;
|
||||
|
||||
#[derive(validator::Validate)]
|
||||
pub struct User {
|
||||
pub user_id: uuid::Uuid,
|
||||
@ -81,4 +83,20 @@ impl UserMember {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_roles(pool: &PgPool, user_id: &uuid::Uuid) -> Result<Roles, sqlx::Error> {
|
||||
let roles = sqlx::query_scalar!(
|
||||
"
|
||||
SELECT roles FROM users_members INNER JOIN members ON users_members.member_id = members.member_id AND users_members.user_id = $1;
|
||||
",
|
||||
user_id
|
||||
).fetch_all(pool).await?;
|
||||
|
||||
let roles: Vec<Roles> = roles.into_iter().map(|r| r.into()).collect();
|
||||
let roles = roles
|
||||
.into_iter()
|
||||
.fold(Roles::empty(), |acc, flag| acc | flag);
|
||||
|
||||
Ok(roles)
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ bitflags! {
|
||||
const KADER = 1 << 1;
|
||||
const ZWEMZAKEN = 1 << 2;
|
||||
const WEDSTRIJDEN = 1 << 3;
|
||||
const ADMIN = 1 << 4;
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
|
@ -14,7 +14,7 @@ pub struct Session {
|
||||
impl Session {
|
||||
pub fn new(user_id: uuid::Uuid) -> Self {
|
||||
let session_id = uuid::Uuid::new_v4();
|
||||
let token = format!("ses_{}", generate_session_token());
|
||||
let token = generate_session_token();
|
||||
|
||||
let created_at = Utc::now();
|
||||
let expires_at = Utc::now() + Duration::days(7);
|
||||
|
@ -1,14 +1,5 @@
|
||||
use crate::{
|
||||
auth::{get_user_from_header, Permissions},
|
||||
model::User,
|
||||
AppState,
|
||||
};
|
||||
use axum::{
|
||||
extract::State,
|
||||
http::{HeaderMap, StatusCode},
|
||||
routing::get,
|
||||
Json, Router,
|
||||
};
|
||||
use crate::{auth::get_user_from_header, model::User, AppState};
|
||||
use axum::{extract::State, http::HeaderMap, routing::get, Json, Router};
|
||||
|
||||
pub mod auth;
|
||||
pub mod member;
|
||||
@ -24,10 +15,9 @@ pub fn routes() -> Router<AppState> {
|
||||
|
||||
async fn root(
|
||||
State(state): State<AppState>,
|
||||
// permissions: Permissions<'_>,
|
||||
headers: HeaderMap,
|
||||
) -> Result<Json<User>, crate::Error> {
|
||||
let user = get_user_from_header(&state.pool, &headers).await?;
|
||||
let (_roles, user) = get_user_from_header(&state.pool, &headers).await?;
|
||||
|
||||
Ok(Json(user))
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use axum::{extract::State, routing::post, Router};
|
||||
|
||||
use crate::{auth::Permissions, AppState};
|
||||
use crate::AppState;
|
||||
|
||||
pub mod migrate;
|
||||
|
||||
@ -12,7 +12,6 @@ pub fn routes() -> Router<AppState> {
|
||||
|
||||
pub async fn get_members<'a>(
|
||||
State(state): State<AppState>,
|
||||
permissions: Permissions<'a>,
|
||||
body: String,
|
||||
) -> Result<(), crate::Error> {
|
||||
Ok(())
|
||||
|
@ -2,13 +2,14 @@ use std::collections::HashMap;
|
||||
|
||||
use axum::{
|
||||
extract::{FromRef, State},
|
||||
http::HeaderMap,
|
||||
Json,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use sqlx::PgPool;
|
||||
|
||||
use crate::{
|
||||
auth::{AuthError, Permissions},
|
||||
auth::{get_user_from_header, AuthError},
|
||||
database::model::Member as DbMember,
|
||||
model::{
|
||||
member::{Groups, Name, Roles},
|
||||
@ -20,10 +21,12 @@ use crate::{
|
||||
|
||||
pub async fn migrate_request<'a>(
|
||||
State(state): State<AppState>,
|
||||
permissions: Permissions<'a>,
|
||||
headers: HeaderMap,
|
||||
body: String,
|
||||
) -> Result<Json<MigrationResponse>, crate::Error> {
|
||||
if !permissions.0.contains("root") {
|
||||
let (roles, _user) = get_user_from_header(&state.pool, &headers).await?;
|
||||
|
||||
if !roles.contains(Roles::ADMIN) {
|
||||
return Err(AuthError::NoPermssions.into());
|
||||
}
|
||||
|
||||
@ -50,13 +53,8 @@ pub async fn migrate_request<'a>(
|
||||
|
||||
pub async fn migrate_confirm<'a>(
|
||||
State(state): State<AppState>,
|
||||
permissions: Permissions<'a>,
|
||||
body: String,
|
||||
) -> Result<(), crate::Error> {
|
||||
if !permissions.0.contains("root") {
|
||||
return Err(AuthError::NoPermssions.into());
|
||||
}
|
||||
|
||||
tracing::info!("Migration is confirmed");
|
||||
|
||||
let count = match body.trim().parse::<u32>() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user