From 5414e2655bdc51d34b22a901cacea3e995fdb130 Mon Sep 17 00:00:00 2001 From: Dany Gagnon Date: Thu, 15 Feb 2024 05:14:17 -0500 Subject: [PATCH] Add the ability to change the keys (#348) * feat: add the ability to change the session key store in redis * feat: change everywhere the constants are used * refactor: add formatting with cargo fmt --------- Co-authored-by: Dany Gagnon --- actix-identity/src/config.rs | 24 ++++++++++++++ actix-identity/src/identity.rs | 33 ++++++++++--------- actix-identity/src/middleware.rs | 3 ++ .../tests/integration/integration.rs | 27 +++++++++++++++ 4 files changed, 72 insertions(+), 15 deletions(-) diff --git a/actix-identity/src/config.rs b/actix-identity/src/config.rs index a10514e9c..5afbe1009 100644 --- a/actix-identity/src/config.rs +++ b/actix-identity/src/config.rs @@ -9,6 +9,9 @@ pub(crate) struct Configuration { pub(crate) on_logout: LogoutBehaviour, pub(crate) login_deadline: Option, pub(crate) visit_deadline: Option, + pub(crate) id_key: &'static str, + pub(crate) last_visit_unix_timestamp_key: &'static str, + pub(crate) login_unix_timestamp_key: &'static str, } impl Default for Configuration { @@ -17,6 +20,9 @@ impl Default for Configuration { on_logout: LogoutBehaviour::PurgeSession, login_deadline: None, visit_deadline: None, + id_key: "actix_identity.user_id", + last_visit_unix_timestamp_key: "actix_identity.last_visited_at", + login_unix_timestamp_key: "actix_identity.logged_in_at", } } } @@ -58,6 +64,24 @@ impl IdentityMiddlewareBuilder { } } + /// Set a custom key to identify the user in the session. + pub fn id_key(mut self, key: &'static str) -> Self { + self.configuration.id_key = key; + self + } + + /// Set a custom key to store the last visited unix timestamp. + pub fn last_visit_unix_timestamp_key(mut self, key: &'static str) -> Self { + self.configuration.last_visit_unix_timestamp_key = key; + self + } + + /// Set a custom key to store the login unix timestamp. + pub fn login_unix_timestamp_key(mut self, key: &'static str) -> Self { + self.configuration.login_unix_timestamp_key = key; + self + } + /// Determines how [`Identity::logout`](crate::Identity::logout) affects the current session. /// /// By default, the current session is purged ([`LogoutBehaviour::PurgeSession`]). diff --git a/actix-identity/src/identity.rs b/actix-identity/src/identity.rs index 9a75ede72..66cf5e775 100644 --- a/actix-identity/src/identity.rs +++ b/actix-identity/src/identity.rs @@ -82,6 +82,9 @@ pub(crate) struct IdentityInner { pub(crate) logout_behaviour: LogoutBehaviour, pub(crate) is_login_deadline_enabled: bool, pub(crate) is_visit_deadline_enabled: bool, + pub(crate) id_key: &'static str, + pub(crate) last_visit_unix_timestamp_key: &'static str, + pub(crate) login_unix_timestamp_key: &'static str, } impl IdentityInner { @@ -101,15 +104,11 @@ impl IdentityInner { /// Retrieve the user id attached to the current session. fn get_identity(&self) -> Result { self.session - .get::(ID_KEY)? + .get::(self.id_key)? .ok_or_else(|| MissingIdentityError.into()) } } -pub(crate) const ID_KEY: &str = "actix_identity.user_id"; -pub(crate) const LAST_VISIT_UNIX_TIMESTAMP_KEY: &str = "actix_identity.last_visited_at"; -pub(crate) const LOGIN_UNIX_TIMESTAMP_KEY: &str = "actix_identity.logged_in_at"; - impl Identity { /// Return the user id associated to the current session. /// @@ -130,7 +129,7 @@ impl Identity { pub fn id(&self) -> Result { self.0 .session - .get(ID_KEY)? + .get(self.0.id_key)? .ok_or_else(|| LostIdentityError.into()) } @@ -153,13 +152,15 @@ impl Identity { /// ``` pub fn login(ext: &Extensions, id: String) -> Result { let inner = IdentityInner::extract(ext); - inner.session.insert(ID_KEY, id)?; + inner.session.insert(inner.id_key, id)?; let now = OffsetDateTime::now_utc().unix_timestamp(); if inner.is_login_deadline_enabled { - inner.session.insert(LOGIN_UNIX_TIMESTAMP_KEY, now)?; + inner.session.insert(inner.login_unix_timestamp_key, now)?; } if inner.is_visit_deadline_enabled { - inner.session.insert(LAST_VISIT_UNIX_TIMESTAMP_KEY, now)?; + inner + .session + .insert(inner.last_visit_unix_timestamp_key, now)?; } inner.session.renew(); Ok(Self(inner)) @@ -191,12 +192,12 @@ impl Identity { self.0.session.purge(); } LogoutBehaviour::DeleteIdentityKeys => { - self.0.session.remove(ID_KEY); + self.0.session.remove(self.0.id_key); if self.0.is_login_deadline_enabled { - self.0.session.remove(LOGIN_UNIX_TIMESTAMP_KEY); + self.0.session.remove(self.0.login_unix_timestamp_key); } if self.0.is_visit_deadline_enabled { - self.0.session.remove(LAST_VISIT_UNIX_TIMESTAMP_KEY); + self.0.session.remove(self.0.last_visit_unix_timestamp_key); } } } @@ -212,7 +213,7 @@ impl Identity { Ok(self .0 .session - .get(LOGIN_UNIX_TIMESTAMP_KEY)? + .get(self.0.login_unix_timestamp_key)? .map(OffsetDateTime::from_unix_timestamp) .transpose() .map_err(SessionExpiryError)?) @@ -222,7 +223,7 @@ impl Identity { Ok(self .0 .session - .get(LAST_VISIT_UNIX_TIMESTAMP_KEY)? + .get(self.0.last_visit_unix_timestamp_key)? .map(OffsetDateTime::from_unix_timestamp) .transpose() .map_err(SessionExpiryError)?) @@ -230,7 +231,9 @@ impl Identity { pub(crate) fn set_last_visited_at(&self) -> Result<(), LoginError> { let now = OffsetDateTime::now_utc().unix_timestamp(); - self.0.session.insert(LAST_VISIT_UNIX_TIMESTAMP_KEY, now)?; + self.0 + .session + .insert(self.0.last_visit_unix_timestamp_key, now)?; Ok(()) } } diff --git a/actix-identity/src/middleware.rs b/actix-identity/src/middleware.rs index 82d32c879..ec691e9b7 100644 --- a/actix-identity/src/middleware.rs +++ b/actix-identity/src/middleware.rs @@ -114,6 +114,9 @@ where logout_behaviour: configuration.on_logout.clone(), is_login_deadline_enabled: configuration.login_deadline.is_some(), is_visit_deadline_enabled: configuration.visit_deadline.is_some(), + id_key: configuration.id_key, + last_visit_unix_timestamp_key: configuration.last_visit_unix_timestamp_key, + login_unix_timestamp_key: configuration.login_unix_timestamp_key, }; req.extensions_mut().insert(identity_inner); enforce_policies(&req, &configuration); diff --git a/actix-identity/tests/integration/integration.rs b/actix-identity/tests/integration/integration.rs index 9753d4e2d..1246545e8 100644 --- a/actix-identity/tests/integration/integration.rs +++ b/actix-identity/tests/integration/integration.rs @@ -28,6 +28,33 @@ async fn login_works() { assert!(response.status().is_success()); } +#[actix_web::test] +async fn custom_keys_work_as_expected() { + let custom_id_key = "custom.user_id"; + let custom_last_visited_key = "custom.last_visited_at"; + let custom_logged_in_key = "custom.logged_in_at"; + + let app = TestApp::spawn_with_config( + IdentityMiddleware::builder() + .id_key(custom_id_key) + .last_visit_unix_timestamp_key(custom_last_visited_key) + .login_unix_timestamp_key(custom_logged_in_key), + ); + let user_id = user_id(); + + let body = app.post_login(user_id.clone()).await; + assert_eq!(body.user_id, Some(user_id.clone())); + + let response = app.get_identity_required().await; + assert!(response.status().is_success()); + + let response = app.post_logout().await; + assert!(response.status().is_success()); + + let response = app.get_identity_required().await; + assert_eq!(response.status(), StatusCode::UNAUTHORIZED); +} + #[actix_web::test] async fn logging_in_again_replaces_the_current_identity() { let app = TestApp::spawn();