mirror of
https://gitlab.com/comunic/comunicapiv3
synced 2024-12-27 22:18:51 +00:00
Can authenticate admin with reset token
This commit is contained in:
parent
25830fe6d1
commit
d8ec093786
18
src/api_data/admin/admin_auth_success.rs
Normal file
18
src/api_data/admin/admin_auth_success.rs
Normal file
@ -0,0 +1,18 @@
|
||||
//! # Admin authentication success
|
||||
//!
|
||||
//! Structure returned when an administrator successfully authenticate
|
||||
//!
|
||||
//! @author Pierre Hubert
|
||||
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct AdminAuthSuccess {
|
||||
token: String
|
||||
}
|
||||
|
||||
impl AdminAuthSuccess {
|
||||
pub fn new(t: String) -> Self {
|
||||
Self { token: t }
|
||||
}
|
||||
}
|
@ -2,4 +2,5 @@
|
||||
//!
|
||||
//! @author Pierre Hubert
|
||||
|
||||
pub mod admin_auth_options;
|
||||
pub mod admin_auth_options;
|
||||
pub mod admin_auth_success;
|
@ -160,9 +160,15 @@ pub const PASSWORD_RESET_TOKEN_LIFETIME: u64 = 60 * 60 * 6;
|
||||
/// Length of admin reset tokens
|
||||
pub const ADMIN_RESET_TOKEN_LENGTH: usize = 255;
|
||||
|
||||
/// Duration of the validity of a password reset token (1 hour)
|
||||
/// Duration of the validity of an admin password reset token (1 hour)
|
||||
pub const ADMIN_RESET_TOKEN_LIFETIME: u64 = 60 * 60;
|
||||
|
||||
/// Length of an admin access token
|
||||
pub const ADMIN_ACCESS_TOKEN_LENGTH: usize = 300;
|
||||
|
||||
/// Duration of the validation of an admin access token without refresh
|
||||
pub const ADMIN_ACCESS_TOKEN_LIFETIME: u64 = 60 * 10;
|
||||
|
||||
/// Minimum password length
|
||||
pub const PASSWORD_MIN_LENGTH: usize = 3;
|
||||
|
||||
|
@ -3,10 +3,12 @@
|
||||
//! @author Pierre Hubert
|
||||
|
||||
use crate::api_data::admin::admin_auth_options::AdminAuthOptions;
|
||||
use crate::api_data::admin::admin_auth_success::AdminAuthSuccess;
|
||||
use crate::data::base_request_handler::BaseRequestHandler;
|
||||
use crate::data::http_request_handler::HttpRequestHandler;
|
||||
use crate::helpers::admin_account_helper;
|
||||
use crate::helpers::{admin_access_token_helper, admin_account_helper};
|
||||
use crate::routes::RequestResult;
|
||||
use crate::utils::date_utils::time;
|
||||
|
||||
/// Get admin auth options
|
||||
pub fn get_auth_options(r: &mut HttpRequestHandler) -> RequestResult {
|
||||
@ -14,4 +16,23 @@ pub fn get_auth_options(r: &mut HttpRequestHandler) -> RequestResult {
|
||||
let admin = admin_account_helper::find_admin_by_email(&mail)?;
|
||||
|
||||
r.set_response(AdminAuthOptions::new(&admin))
|
||||
}
|
||||
|
||||
/// Login admin using a reset token
|
||||
pub fn auth_with_reset_token(r: &mut HttpRequestHandler) -> RequestResult {
|
||||
let reset_token = r.post_string("token")?;
|
||||
let admin = admin_account_helper::find_admin_by_email(&r.post_email("mail")?)?;
|
||||
|
||||
let token = r.some_or_internal_error(
|
||||
admin.reset_token,
|
||||
"Specified user has not valid reset token for now!",
|
||||
)?;
|
||||
|
||||
if !token.token.eq(&reset_token) || time() > token.expire {
|
||||
return r.forbidden("Specified reset token is invalid!".to_string());
|
||||
}
|
||||
|
||||
let token = admin_access_token_helper::create(admin.id)?;
|
||||
|
||||
r.set_response(AdminAuthSuccess::new(token))
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
//!
|
||||
//! @author Pierre Hubert
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
|
||||
pub struct AdminID(u64);
|
||||
|
||||
impl AdminID {
|
||||
@ -38,4 +38,14 @@ pub struct AdminKey {
|
||||
pub admin_id: AdminID,
|
||||
pub name: String,
|
||||
pub key: String,
|
||||
}
|
||||
|
||||
/// Admin access token
|
||||
///
|
||||
/// Used to store authentication of an admin
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AdminAccessToken {
|
||||
pub token: String,
|
||||
pub id: AdminID,
|
||||
pub last_refresh: u64
|
||||
}
|
80
src/helpers/admin_access_token_helper.rs
Normal file
80
src/helpers/admin_access_token_helper.rs
Normal file
@ -0,0 +1,80 @@
|
||||
//! # Admin access token helper
|
||||
//!
|
||||
//! @author Pierre Hubert
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use crate::constants::{ADMIN_ACCESS_TOKEN_LENGTH, ADMIN_ACCESS_TOKEN_LIFETIME};
|
||||
use crate::data::admin::{AdminAccessToken, AdminID};
|
||||
use crate::data::error::{ExecError, Res};
|
||||
use crate::utils::crypt_utils::rand_str;
|
||||
use crate::utils::date_utils::time;
|
||||
|
||||
static mut CACHE: Option<Arc<Mutex<HashMap<AdminID, AdminAccessToken>>>> = None;
|
||||
|
||||
/// Initialize this helper
|
||||
pub fn init() {
|
||||
unsafe {
|
||||
let map = HashMap::new();
|
||||
CACHE = Some(Arc::new(Mutex::new(map)));
|
||||
}
|
||||
}
|
||||
|
||||
/// Create and return a new access token for an admin
|
||||
pub fn create(id: AdminID) -> Res<String> {
|
||||
let map = unsafe {
|
||||
CACHE.as_ref().unwrap().lock()
|
||||
};
|
||||
|
||||
let token = AdminAccessToken {
|
||||
token: rand_str(ADMIN_ACCESS_TOKEN_LENGTH),
|
||||
id,
|
||||
last_refresh: time(),
|
||||
};
|
||||
|
||||
map?.insert(id, token.clone());
|
||||
|
||||
Ok(token.token)
|
||||
}
|
||||
|
||||
/// Remove an access token from the list
|
||||
pub fn destroy(id: AdminID) -> Res {
|
||||
let map = unsafe {
|
||||
CACHE.as_ref().unwrap().lock()
|
||||
};
|
||||
|
||||
map?.remove(&id);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Find an admin by its access token
|
||||
pub fn find_by_token(t: &str) -> Res<AdminAccessToken> {
|
||||
let map = unsafe {
|
||||
CACHE.as_ref().unwrap().lock()
|
||||
};
|
||||
let mut map = map?;
|
||||
|
||||
let token = map.iter()
|
||||
.filter(|p| p.1.token.eq(t))
|
||||
.next();
|
||||
|
||||
let mut token = match token {
|
||||
None => {
|
||||
return Err(ExecError::boxed_new("The token was not recognized as an admin token!"));
|
||||
}
|
||||
Some(t) => t.1
|
||||
}.clone();
|
||||
|
||||
|
||||
if token.last_refresh + ADMIN_ACCESS_TOKEN_LIFETIME < time() {
|
||||
return Err(ExecError::boxed_new("The token has expired!"));
|
||||
}
|
||||
|
||||
token.last_refresh = time();
|
||||
|
||||
map.insert(token.id, token.clone());
|
||||
|
||||
Ok(token)
|
||||
}
|
@ -22,4 +22,5 @@ pub mod push_notifications_helper;
|
||||
pub mod independent_push_notifications_service_helper;
|
||||
pub mod firebase_notifications_helper;
|
||||
pub mod forez_presence_helper;
|
||||
pub mod admin_account_helper;
|
||||
pub mod admin_account_helper;
|
||||
pub mod admin_access_token_helper;
|
@ -337,5 +337,6 @@ pub fn get_routes() -> Vec<Route> {
|
||||
|
||||
// Admin accounts controller
|
||||
Route::limited_admin_post_without_login("/admin/accounts/auth_options", Box::new(admin_account_controller::get_auth_options), LimitPolicy::FAILURE(5)),
|
||||
Route::limited_admin_post_without_login("/admin/accounts/auth_with_reset_token", Box::new(admin_account_controller::auth_with_reset_token), LimitPolicy::FAILURE(5)),
|
||||
]
|
||||
}
|
@ -17,7 +17,7 @@ use crate::controllers::{rtc_relay_controller, user_ws_controller};
|
||||
use crate::data::base_request_handler::{BaseRequestHandler, PostFile, RequestValue};
|
||||
use crate::data::config::Config;
|
||||
use crate::data::http_request_handler::HttpRequestHandler;
|
||||
use crate::helpers::{api_helper, requests_limit_helper};
|
||||
use crate::helpers::{api_helper, requests_limit_helper, admin_access_token_helper};
|
||||
use crate::routes::{get_routes, RequestResult, Route, RouteScope};
|
||||
use crate::routes::Method::{GET, POST};
|
||||
use crate::utils::user_data_utils::user_data_path;
|
||||
@ -352,6 +352,8 @@ pub async fn start_server(conf: &Config) -> std::io::Result<()> {
|
||||
// Initialize limit helper
|
||||
requests_limit_helper::init();
|
||||
|
||||
admin_access_token_helper::init();
|
||||
|
||||
let addr = conf.server_listen_address();
|
||||
println!("Start to listen on http://{}/", addr);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user