mirror of
				https://gitlab.com/comunic/comunicapiv3
				synced 2025-11-04 09:34:04 +00:00 
			
		
		
		
	Can authenticate admin with reset token
This commit is contained in:
		
							
								
								
									
										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);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user