BasicOIDC/src/data/session_identity.rs

111 lines
3.0 KiB
Rust

use actix_identity::Identity;
use serde::{Deserialize, Serialize};
use crate::constants::{MAX_INACTIVITY_DURATION, MAX_SESSION_DURATION, MIN_ACTIVITY_RECORD_TIME};
use crate::data::user::{User, UserID};
use crate::utils::time::time;
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
pub enum SessionStatus {
Invalid,
SignedIn,
NeedNewPassword,
NeedMFA,
}
impl Default for SessionStatus {
fn default() -> Self {
Self::Invalid
}
}
#[derive(Debug, Serialize, Deserialize, Default)]
struct SessionIdentityData {
pub id: UserID,
pub is_admin: bool,
login_time: u64,
last_access: u64,
pub status: SessionStatus,
}
pub struct SessionIdentity<'a>(pub &'a Identity);
impl<'a> SessionIdentity<'a> {
pub fn set_user(&self, user: &User) {
self.set_session_data(&SessionIdentityData {
id: user.uid.clone(),
is_admin: user.admin,
login_time: time(),
last_access: time(),
status: SessionStatus::SignedIn,
});
}
fn get_session_data(&self) -> Option<SessionIdentityData> {
let mut res: Option<SessionIdentityData> = self.0.identity()
.as_deref()
.map(serde_json::from_str)
.map(|f| f.expect("Failed to deserialize session data!"));
// Check if session is valid
if let Some(sess) = &res {
if sess.id.is_empty() {
return None;
}
}
if let Some(session) = res.as_mut() {
if session.login_time + MAX_SESSION_DURATION < time() {
log::info!("Session for {} reached max duration timeout", session.id);
self.0.forget();
return None;
}
if session.last_access + MAX_INACTIVITY_DURATION < time() {
log::info!("Session is expired for {}", session.id);
self.0.forget();
return None;
}
if session.last_access + MIN_ACTIVITY_RECORD_TIME < time() {
log::debug!("Refresh last access for session");
session.last_access = time();
self.set_session_data(session);
}
}
res
}
fn set_session_data(&self, data: &SessionIdentityData) {
let s = serde_json::to_string(data)
.expect("Failed to serialize session data!");
self.0.remember(s);
}
pub fn set_status(&self, status: SessionStatus) {
let mut sess = self.get_session_data().unwrap_or_default();
sess.status = status;
self.set_session_data(&sess);
}
pub fn is_authenticated(&self) -> bool {
self.get_session_data()
.map(|s| s.status == SessionStatus::SignedIn)
.unwrap_or(false)
}
pub fn need_new_password(&self) -> bool {
self.get_session_data()
.map(|s| s.status == SessionStatus::NeedNewPassword)
.unwrap_or(false)
}
pub fn user_id(&self) -> UserID {
self.get_session_data()
.unwrap_or_default()
.id
}
}