Skip to content

Commit 31b548b

Browse files
committed
Use persistent sessions for authentication.
1 parent d07af26 commit 31b548b

File tree

2 files changed

+59
-3
lines changed

2 files changed

+59
-3
lines changed

src/controllers/util.rs

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
use chrono::Utc;
2-
use conduit_cookie::RequestSession;
2+
use conduit_cookie::RequestCookies;
33

44
use super::prelude::*;
5-
5+
use crate::controllers::user::session::SESSION_COOKIE_NAME;
66
use crate::middleware::log_request;
7-
use crate::models::{ApiToken, User};
7+
use crate::models::{ApiToken, PersistentSession, User};
88
use crate::util::errors::{
99
account_locked, forbidden, internal, AppError, AppResult, InsecurelyGeneratedTokenRevoked,
1010
};
11+
use conduit_cookie::RequestSession;
1112

1213
#[derive(Debug)]
1314
pub struct AuthenticatedUser {
@@ -67,6 +68,7 @@ fn verify_origin(req: &dyn RequestExt) -> AppResult<()> {
6768
fn authenticate_user(req: &dyn RequestExt) -> AppResult<AuthenticatedUser> {
6869
let conn = req.db_conn()?;
6970

71+
// TODO(adsnaider): Remove this.
7072
let session = req.session();
7173
let user_id_from_session = session.get("user_id").and_then(|s| s.parse::<i32>().ok());
7274

@@ -80,6 +82,34 @@ fn authenticate_user(req: &dyn RequestExt) -> AppResult<AuthenticatedUser> {
8082
});
8183
}
8284

85+
if let Some(session_token) = req
86+
.cookies()
87+
.get(SESSION_COOKIE_NAME)
88+
.map(|cookie| cookie.value())
89+
{
90+
let ip_addr = req.remote_addr().ip();
91+
92+
let user_agent = req
93+
.headers()
94+
.get(header::USER_AGENT)
95+
.and_then(|value| value.to_str().ok())
96+
.unwrap_or_default();
97+
98+
if let Some(session) = PersistentSession::find_from_token_and_update(
99+
&conn,
100+
session_token,
101+
ip_addr,
102+
user_agent,
103+
)? {
104+
let user = User::find(&conn, session.user_id)
105+
.map_err(|e| e.chain(internal("user_id from session not found in the database")))?;
106+
return Ok(AuthenticatedUser {
107+
user,
108+
token_id: None,
109+
});
110+
}
111+
}
112+
83113
// Otherwise, look for an `Authorization` header on the request
84114
let maybe_authorization = req
85115
.headers()

src/models/persistent_session.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,32 @@ impl PersistentSession {
4444
}
4545
}
4646

47+
pub fn find_from_token_and_update(
48+
conn: &PgConnection,
49+
token: &str,
50+
ip_address: IpAddr,
51+
user_agent: &str,
52+
) -> Result<Option<Self>, SessionError> {
53+
let hashed_token = SecureToken::parse(SecureTokenKind::Session, token)
54+
.ok_or(SessionError::InvalidSessionToken)?;
55+
let sessions = persistent_sessions::table
56+
.filter(persistent_sessions::revoked.eq(false))
57+
.filter(persistent_sessions::hashed_token.eq(hashed_token));
58+
59+
conn.transaction(|| {
60+
diesel::update(sessions.clone())
61+
.set((
62+
persistent_sessions::last_used_at.eq(diesel::dsl::now),
63+
persistent_sessions::last_ip_address.eq(IpNetwork::from(ip_address)),
64+
persistent_sessions::last_user_agent.eq(user_agent),
65+
))
66+
.get_result(conn)
67+
.optional()
68+
})
69+
.or_else(|_| sessions.first(conn).optional())
70+
.map_err(SessionError::DieselError)
71+
}
72+
4773
pub fn revoke_from_token(conn: &PgConnection, token: &str) -> Result<usize, SessionError> {
4874
let hashed_token = SecureToken::parse(SecureTokenKind::Session, token)
4975
.ok_or(SessionError::InvalidSessionToken)?;

0 commit comments

Comments
 (0)