BasicOIDC/src/actors/openid_sessions_actor.rs

176 lines
4.8 KiB
Rust
Raw Normal View History

2022-04-09 10:18:59 +00:00
use actix::Message;
2022-11-11 11:26:02 +00:00
use actix::{Actor, AsyncContext, Context, Handler};
2022-04-09 10:18:59 +00:00
use crate::constants::*;
2022-04-15 18:08:31 +00:00
use crate::data::access_token::AccessToken;
use crate::data::app_config::AppConfig;
2022-04-09 10:18:59 +00:00
use crate::data::client::ClientID;
2022-04-14 16:04:01 +00:00
use crate::data::code_challenge::CodeChallenge;
2022-04-15 18:08:31 +00:00
use crate::data::jwt_signer::JWTSigner;
2022-04-09 10:18:59 +00:00
use crate::data::user::UserID;
2022-04-15 18:08:31 +00:00
use crate::utils::err::Res;
use crate::utils::string_utils::rand_str;
2022-04-09 10:18:59 +00:00
use crate::utils::time::time;
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, Eq, PartialEq)]
pub struct SessionID(pub String);
#[derive(Clone, Debug)]
pub struct Session {
pub session_id: SessionID,
pub client: ClientID,
pub user: UserID,
2022-04-13 17:07:58 +00:00
pub auth_time: u64,
2022-04-09 10:18:59 +00:00
pub redirect_uri: String,
pub authorization_code: String,
2022-04-12 18:40:44 +00:00
pub authorization_code_expire_at: u64,
2022-04-09 10:18:59 +00:00
2022-04-15 18:08:31 +00:00
pub access_token: Option<String>,
2022-04-12 18:40:44 +00:00
pub access_token_expire_at: u64,
pub refresh_token: String,
pub refresh_token_expire_at: u64,
2022-04-09 10:18:59 +00:00
pub nonce: Option<String>,
2022-04-14 16:04:01 +00:00
pub code_challenge: Option<CodeChallenge>,
2022-04-09 10:18:59 +00:00
}
impl Session {
pub fn is_expired(&self) -> bool {
2022-11-11 11:26:02 +00:00
self.authorization_code_expire_at < time()
&& self.access_token_expire_at < time()
2022-04-12 18:40:44 +00:00
&& self.refresh_token_expire_at < time()
2022-04-09 10:18:59 +00:00
}
2022-04-15 18:08:31 +00:00
2022-11-11 11:26:02 +00:00
pub fn regenerate_access_and_refresh_tokens(
&mut self,
app_config: &AppConfig,
jwt_signer: &JWTSigner,
) -> Res {
2022-04-15 18:08:31 +00:00
let access_token = AccessToken {
issuer: app_config.website_origin.to_string(),
2022-04-19 17:40:36 +00:00
subject_identifier: self.user.clone().0,
2022-04-15 18:08:31 +00:00
issued_at: time(),
exp_time: time() + OPEN_ID_ACCESS_TOKEN_TIMEOUT,
rand_val: rand_str(OPEN_ID_ACCESS_TOKEN_LEN),
nonce: self.nonce.clone(),
};
self.access_token_expire_at = access_token.exp_time;
self.access_token = Some(jwt_signer.sign_token(access_token.to_jwt_claims())?);
self.refresh_token = rand_str(OPEN_ID_REFRESH_TOKEN_LEN);
self.refresh_token_expire_at = OPEN_ID_REFRESH_TOKEN_TIMEOUT + time();
Ok(())
}
2022-04-09 10:18:59 +00:00
}
#[derive(Message)]
#[rtype(result = "()")]
pub struct PushNewSession(pub Session);
2022-04-12 18:40:44 +00:00
#[derive(Message)]
#[rtype(result = "Option<Session>")]
pub struct FindSessionByAuthorizationCode(pub String);
2022-04-14 15:02:47 +00:00
#[derive(Message)]
#[rtype(result = "Option<Session>")]
pub struct FindSessionByRefreshToken(pub String);
2022-04-15 15:04:23 +00:00
#[derive(Message)]
#[rtype(result = "Option<Session>")]
pub struct FindSessionByAccessToken(pub String);
2022-04-14 15:02:47 +00:00
#[derive(Message)]
#[rtype(result = "()")]
pub struct UpdateSession(pub Session);
2022-04-09 10:25:56 +00:00
#[derive(Default)]
2022-04-09 10:18:59 +00:00
pub struct OpenIDSessionsActor {
session: Vec<Session>,
}
impl OpenIDSessionsActor {
pub fn clean_old_sessions(&mut self) {
self.session.retain(|s| !s.is_expired());
}
}
impl Actor for OpenIDSessionsActor {
type Context = Context<Self>;
fn started(&mut self, ctx: &mut Self::Context) {
// Clean up at a regular interval failed attempts
ctx.run_interval(OPEN_ID_SESSION_CLEANUP_INTERVAL, |act, _ctx| {
log::trace!("Cleaning up old login sessions");
act.clean_old_sessions();
});
}
}
impl Handler<PushNewSession> for OpenIDSessionsActor {
type Result = ();
fn handle(&mut self, msg: PushNewSession, _ctx: &mut Self::Context) -> Self::Result {
self.session.push(msg.0)
}
2022-04-12 18:40:44 +00:00
}
impl Handler<FindSessionByAuthorizationCode> for OpenIDSessionsActor {
type Result = Option<Session>;
2022-11-11 11:26:02 +00:00
fn handle(
&mut self,
msg: FindSessionByAuthorizationCode,
_ctx: &mut Self::Context,
) -> Self::Result {
2022-04-12 18:40:44 +00:00
self.session
.iter()
.find(|f| f.authorization_code.eq(&msg.0))
.cloned()
}
}
2022-04-14 15:02:47 +00:00
impl Handler<FindSessionByRefreshToken> for OpenIDSessionsActor {
type Result = Option<Session>;
fn handle(&mut self, msg: FindSessionByRefreshToken, _ctx: &mut Self::Context) -> Self::Result {
self.session
.iter()
.find(|f| f.refresh_token.eq(&msg.0))
.cloned()
}
}
2022-04-15 15:04:23 +00:00
impl Handler<FindSessionByAccessToken> for OpenIDSessionsActor {
type Result = Option<Session>;
fn handle(&mut self, msg: FindSessionByAccessToken, _ctx: &mut Self::Context) -> Self::Result {
self.session
.iter()
2022-11-11 11:26:02 +00:00
.find(|f| {
f.access_token
.as_ref()
.map(|t| t.eq(&msg.0))
.unwrap_or(false)
})
2022-04-15 15:04:23 +00:00
.cloned()
}
}
2022-04-14 15:02:47 +00:00
impl Handler<UpdateSession> for OpenIDSessionsActor {
type Result = ();
fn handle(&mut self, msg: UpdateSession, _ctx: &mut Self::Context) -> Self::Result {
2022-11-11 11:26:02 +00:00
if let Some(r) = self
.session
.iter()
.enumerate()
.find(|f| f.1.session_id.eq(&msg.0.session_id))
.map(|f| f.0)
{
2022-04-14 15:02:47 +00:00
self.session[r] = msg.0;
}
}
2022-11-11 11:26:02 +00:00
}