From fa531fb03d82ecb2d76d83963bfabcca734ba0d2 Mon Sep 17 00:00:00 2001 From: dowwie Date: Wed, 12 Jun 2019 08:14:18 -0400 Subject: [PATCH 1/5] updated session logic to support login and logout functionality --- .gitignore | 1 + src/session.rs | 77 +++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 68 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 42d0755dd..c786504ea 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ Cargo.lock target/ guide/build/ /gh-pages +/.history *.so *.out diff --git a/src/session.rs b/src/session.rs index 935a7ce22..bb8e890d1 100644 --- a/src/session.rs +++ b/src/session.rs @@ -1,10 +1,7 @@ -use std::collections::HashMap; -use std::iter; -use std::rc::Rc; - +use std::{collections::HashMap, iter, rc::Rc}; use actix::prelude::*; use actix_service::{Service, Transform}; -use actix_session::Session; +use actix_session::{Session, SessionStatus}; use actix_utils::cloneable::CloneableService; use actix_web::cookie::{Cookie, CookieJar, Key, SameSite}; use actix_web::dev::{ServiceRequest, ServiceResponse}; @@ -14,7 +11,7 @@ use futures::future::{err, ok, Either, Future, FutureResult}; use futures::Poll; use rand::{distributions::Alphanumeric, rngs::OsRng, Rng}; use redis_async::resp::RespValue; -use time::Duration; +use time::{self, Duration}; use crate::redis::{Command, RedisActor}; @@ -147,10 +144,32 @@ where }; srv.call(req).and_then(move |mut res| { - if let Some(state) = Session::get_changes(&mut res) { - Either::A(inner.update(res, state, value)) - } else { - Either::B(ok(res)) + match Session::get_changes(&mut res) { + (SessionStatus::Unchanged, _) => + Either::A(Either::A(ok(res))), + (SessionStatus::Changed, Some(state)) => + Either::B(Either::A(inner.update(res, state, value))), + (SessionStatus::Purged, Some(_)) => { + Either::B(Either::B( + inner.clear_cache(value) + .and_then(move |_| + match inner.remove_cookie(&mut res){ + Ok(_) => Either::A(ok(res)), + Err(_err) => Either::B(err( + error::ErrorInternalServerError(_err))) + }) + )) + }, + (SessionStatus::Renewed, Some(state)) => { + Either::A( + Either::B( + inner.clear_cache(value) + .and_then(move |_| + inner.update(res, state, None)) + ) + ) + }, + (_, None) => unreachable!() } }) })) @@ -289,4 +308,42 @@ impl Inner { ), } } + + /// removes cache entry + fn clear_cache(&self, value: Option) + -> impl Future { + if let Some(key) = value { + Either::A( + self.addr + .send(Command(resp_array!["DEL", key])) + .map_err(Error::from) + .and_then(|res| + match res { + // redis responds with number of deleted records + Ok(RespValue::Integer(x)) if x > 0 => Ok(()), + _ => Err(error::ErrorInternalServerError( + "failed to remove session from cache")) + } + ) + ) + } else { + Either::B(err(error::ErrorInternalServerError( + "missing session key - unexpected"))) + } + } + + /// invalidates session cookie + fn remove_cookie(&self, res: &mut ServiceResponse) + -> Result<(), Error> { + let mut cookie = Cookie::named(self.name.clone()); + cookie.set_value(""); + cookie.set_max_age(Duration::seconds(0)); + cookie.set_expires(time::now() - Duration::days(365)); + + let val = HeaderValue::from_str(&cookie.to_string()) + .map_err(|err| error::ErrorInternalServerError(err))?; + res.headers_mut().append(header::SET_COOKIE, val); + + Ok(()) + } } From 1086180267f989ae8bda2137e99aec2e5541716e Mon Sep 17 00:00:00 2001 From: dowwie Date: Tue, 18 Jun 2019 13:47:14 -0400 Subject: [PATCH 2/5] resolved bug related to updating session cookie --- src/session.rs | 58 ++++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/src/session.rs b/src/session.rs index bb8e890d1..275bd0f2a 100644 --- a/src/session.rs +++ b/src/session.rs @@ -151,23 +151,33 @@ where Either::B(Either::A(inner.update(res, state, value))), (SessionStatus::Purged, Some(_)) => { Either::B(Either::B( - inner.clear_cache(value) - .and_then(move |_| - match inner.remove_cookie(&mut res){ - Ok(_) => Either::A(ok(res)), - Err(_err) => Either::B(err( - error::ErrorInternalServerError(_err))) - }) + if let Some(val) = value { + Either::A( + inner.clear_cache(val) + .and_then(move |_| + match inner.remove_cookie(&mut res){ + Ok(_) => Either::A(ok(res)), + Err(_err) => Either::B(err( + error::ErrorInternalServerError(_err))) + }) + ) + } else { + Either::B(err(error::ErrorInternalServerError("unexpected"))) + } )) }, (SessionStatus::Renewed, Some(state)) => { + if let Some(val) = value { Either::A( Either::B( - inner.clear_cache(value) + inner.clear_cache(val) .and_then(move |_| inner.update(res, state, None)) ) ) + } else { + Either::B(Either::A(inner.update(res, state, None))) + } }, (_, None) => unreachable!() } @@ -285,7 +295,6 @@ impl Inner { }; let state: HashMap<_, _> = state.collect(); - match serde_json::to_string(&state) { Err(e) => Either::A(err(e.into())), Ok(body) => Either::B( @@ -310,26 +319,19 @@ impl Inner { } /// removes cache entry - fn clear_cache(&self, value: Option) + fn clear_cache(&self, key: String) -> impl Future { - if let Some(key) = value { - Either::A( - self.addr - .send(Command(resp_array!["DEL", key])) - .map_err(Error::from) - .and_then(|res| - match res { - // redis responds with number of deleted records - Ok(RespValue::Integer(x)) if x > 0 => Ok(()), - _ => Err(error::ErrorInternalServerError( - "failed to remove session from cache")) - } - ) - ) - } else { - Either::B(err(error::ErrorInternalServerError( - "missing session key - unexpected"))) - } + self.addr + .send(Command(resp_array!["DEL", key])) + .map_err(Error::from) + .and_then(|res| { + match res { + // redis responds with number of deleted records + Ok(RespValue::Integer(x)) if x > 0 => Ok(()), + _ => Err(error::ErrorInternalServerError( + "failed to remove session from cache")) + } + }) } /// invalidates session cookie From 48ddb769152634f9d75c75f0d51fb807a4a32988 Mon Sep 17 00:00:00 2001 From: dowwie Date: Mon, 1 Jul 2019 14:20:18 -0400 Subject: [PATCH 3/5] updated logic to create session on new request wo cookie --- src/session.rs | 54 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/src/session.rs b/src/session.rs index 275bd0f2a..315dc189e 100644 --- a/src/session.rs +++ b/src/session.rs @@ -145,38 +145,50 @@ where srv.call(req).and_then(move |mut res| { match Session::get_changes(&mut res) { - (SessionStatus::Unchanged, _) => - Either::A(Either::A(ok(res))), - (SessionStatus::Changed, Some(state)) => - Either::B(Either::A(inner.update(res, state, value))), - (SessionStatus::Purged, Some(_)) => { - Either::B(Either::B( - if let Some(val) = value { + (SessionStatus::Unchanged, None) => + Either::A(Either::A(Either::A(ok(res)))), + (SessionStatus::Unchanged, Some(state)) => + Either::A(Either::A(Either::B( + if value.is_none(){ // implies the session is new Either::A( - inner.clear_cache(val) - .and_then(move |_| - match inner.remove_cookie(&mut res){ - Ok(_) => Either::A(ok(res)), - Err(_err) => Either::B(err( - error::ErrorInternalServerError(_err))) - }) + inner.update(res, state, value) ) } else { - Either::B(err(error::ErrorInternalServerError("unexpected"))) + Either::B( + ok(res) + ) + } + ))), + (SessionStatus::Changed, Some(state)) => + Either::A(Either::B(Either::A(inner.update(res, state, value)))), + (SessionStatus::Purged, Some(_)) => { + if let Some(val) = value { + Either::A(Either::B(Either::B(Either::A( + inner.clear_cache(val) + .and_then(move |_| + match inner.remove_cookie(&mut res){ + Ok(_) => Either::A(ok(res)), + Err(_err) => Either::B(err( + error::ErrorInternalServerError(_err))) + }) + )))) + } else { + Either::A(Either::B(Either::B(Either::B( + err(error::ErrorInternalServerError("unexpected")) + )))) } - )) }, (SessionStatus::Renewed, Some(state)) => { if let Some(val) = value { - Either::A( - Either::B( + Either::B(Either::A( inner.clear_cache(val) .and_then(move |_| inner.update(res, state, None)) - ) - ) + )) } else { - Either::B(Either::A(inner.update(res, state, None))) + Either::B(Either::B( + inner.update(res, state, None) + )) } }, (_, None) => unreachable!() From 1d1ff6606336edbd84af6e657e92e26a8427b001 Mon Sep 17 00:00:00 2001 From: dowwie Date: Thu, 4 Jul 2019 06:10:03 -0400 Subject: [PATCH 4/5] updated version to 0.7 and added comments to CHANGES.md --- CHANGES.md | 11 +++++++++++ Cargo.toml | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index d8a1632f0..55ffc6b6b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,16 @@ # Changes + +## 0.7.0 (2019-xx-xx) + +* Upgraded logic that evaluates session state, including new SessionStatus field, + and introduced ``session.renew()`` and ``session.purge()`` functionality. + Use ``renew()`` to cycle the session key at successful login. ``renew()`` keeps a + session's state while replacing the old cookie and session key with new ones. + Use ``purge()`` at logout to invalidate the session cookie and remove the + session's redis cache entry. + + ## 0.6.0 (2019-05-18) * actix-web 1.0.0 compatibility diff --git a/Cargo.toml b/Cargo.toml index b1c82a7d4..64b83b133 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-redis" -version = "0.6.0" +version = "0.7.0" authors = ["Nikolay Kim "] description = "Redis integration for actix framework" license = "MIT/Apache-2.0" From 3244a359df842396162d8878ba82ec6df6547a9c Mon Sep 17 00:00:00 2001 From: dowwie Date: Mon, 8 Jul 2019 07:15:20 -0400 Subject: [PATCH 5/5] reverted to 0.6 because it wasn't ever released --- CHANGES.md | 8 +++----- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 55ffc6b6b..3e22d0019 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,7 +1,9 @@ # Changes -## 0.7.0 (2019-xx-xx) +## 0.6.0 (2019-07-08) + +* actix-web 1.0.0 compatibility * Upgraded logic that evaluates session state, including new SessionStatus field, and introduced ``session.renew()`` and ``session.purge()`` functionality. @@ -11,10 +13,6 @@ session's redis cache entry. -## 0.6.0 (2019-05-18) - -* actix-web 1.0.0 compatibility - ## 0.5.1 (2018-08-02) diff --git a/Cargo.toml b/Cargo.toml index 64b83b133..b1c82a7d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-redis" -version = "0.7.0" +version = "0.6.0" authors = ["Nikolay Kim "] description = "Redis integration for actix framework" license = "MIT/Apache-2.0"