1
0
mirror of https://gitlab.com/comunic/comunicapiv3 synced 2024-11-22 13:29:21 +00:00

Can authenticate admin with reset token

This commit is contained in:
Pierre HUBERT 2021-05-11 16:52:57 +02:00
parent 25830fe6d1
commit d8ec093786
9 changed files with 146 additions and 6 deletions

View 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 }
}
}

View File

@ -2,4 +2,5 @@
//! //!
//! @author Pierre Hubert //! @author Pierre Hubert
pub mod admin_auth_options; pub mod admin_auth_options;
pub mod admin_auth_success;

View File

@ -160,9 +160,15 @@ pub const PASSWORD_RESET_TOKEN_LIFETIME: u64 = 60 * 60 * 6;
/// Length of admin reset tokens /// Length of admin reset tokens
pub const ADMIN_RESET_TOKEN_LENGTH: usize = 255; 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; 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 /// Minimum password length
pub const PASSWORD_MIN_LENGTH: usize = 3; pub const PASSWORD_MIN_LENGTH: usize = 3;

View File

@ -3,10 +3,12 @@
//! @author Pierre Hubert //! @author Pierre Hubert
use crate::api_data::admin::admin_auth_options::AdminAuthOptions; 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::base_request_handler::BaseRequestHandler;
use crate::data::http_request_handler::HttpRequestHandler; 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::routes::RequestResult;
use crate::utils::date_utils::time;
/// Get admin auth options /// Get admin auth options
pub fn get_auth_options(r: &mut HttpRequestHandler) -> RequestResult { 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)?; let admin = admin_account_helper::find_admin_by_email(&mail)?;
r.set_response(AdminAuthOptions::new(&admin)) 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))
} }

View File

@ -2,7 +2,7 @@
//! //!
//! @author Pierre Hubert //! @author Pierre Hubert
#[derive(Copy, Clone, Eq, PartialEq)] #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
pub struct AdminID(u64); pub struct AdminID(u64);
impl AdminID { impl AdminID {
@ -38,4 +38,14 @@ pub struct AdminKey {
pub admin_id: AdminID, pub admin_id: AdminID,
pub name: String, pub name: String,
pub key: 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
} }

View 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)
}

View File

@ -22,4 +22,5 @@ pub mod push_notifications_helper;
pub mod independent_push_notifications_service_helper; pub mod independent_push_notifications_service_helper;
pub mod firebase_notifications_helper; pub mod firebase_notifications_helper;
pub mod forez_presence_helper; pub mod forez_presence_helper;
pub mod admin_account_helper; pub mod admin_account_helper;
pub mod admin_access_token_helper;

View File

@ -337,5 +337,6 @@ pub fn get_routes() -> Vec<Route> {
// Admin accounts controller // 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_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)),
] ]
} }

View File

@ -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::base_request_handler::{BaseRequestHandler, PostFile, RequestValue};
use crate::data::config::Config; use crate::data::config::Config;
use crate::data::http_request_handler::HttpRequestHandler; 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::{get_routes, RequestResult, Route, RouteScope};
use crate::routes::Method::{GET, POST}; use crate::routes::Method::{GET, POST};
use crate::utils::user_data_utils::user_data_path; 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 // Initialize limit helper
requests_limit_helper::init(); requests_limit_helper::init();
admin_access_token_helper::init();
let addr = conf.server_listen_address(); let addr = conf.server_listen_address();
println!("Start to listen on http://{}/", addr); println!("Start to listen on http://{}/", addr);