soma_auth/
sqlite_assertions.rs1use rusqlite::params;
2
3use crate::error::AuthError;
4
5use super::{SqliteStore, hash_token, sqlite_error};
6
7const MAX_ASSERTION_ISSUER_BYTES: usize = 2048;
8const MAX_ASSERTION_JTI_BYTES: usize = 256;
9const MAX_ASSERTION_LIFETIME_SECS: i64 = 300;
10const MAX_ASSERTION_CLOCK_SKEW_SECS: i64 = 60;
11
12impl SqliteStore {
13 pub async fn consume_assertion_jti(
17 &self,
18 issuer: &str,
19 jti: &str,
20 issued_at: i64,
21 expires_at: i64,
22 now: i64,
23 ) -> Result<bool, AuthError> {
24 if issuer.is_empty() || issuer.len() > MAX_ASSERTION_ISSUER_BYTES {
25 return Ok(false);
26 }
27 if jti.is_empty() || jti.len() > MAX_ASSERTION_JTI_BYTES {
28 return Ok(false);
29 }
30 if issued_at > now + MAX_ASSERTION_CLOCK_SKEW_SECS
31 || expires_at <= now
32 || expires_at.saturating_sub(issued_at) > MAX_ASSERTION_LIFETIME_SECS
33 {
34 return Ok(false);
35 }
36
37 let issuer = issuer.to_owned();
38 let jti = jti.to_owned();
39 self.with_conn(move |conn| {
40 conn.execute_batch("BEGIN IMMEDIATE")
41 .map_err(sqlite_error)?;
42 let result = (|| {
43 conn.execute(
44 "DELETE FROM assertion_jtis WHERE expires_at <= ?1",
45 params![now],
46 )
47 .map_err(sqlite_error)?;
48 conn.execute(
49 "INSERT OR IGNORE INTO assertion_jtis (issuer, jti, expires_at)
50 VALUES (?1, ?2, ?3)",
51 params![issuer, jti, expires_at],
52 )
53 .map(|inserted| inserted == 1)
54 .map_err(sqlite_error)
55 })();
56 match result {
57 Ok(consumed) => {
58 conn.execute_batch("COMMIT").map_err(sqlite_error)?;
59 Ok(consumed)
60 }
61 Err(error) => {
62 let _ = conn.execute_batch("ROLLBACK");
63 Err(error)
64 }
65 }
66 })
67 .await
68 }
69
70 pub async fn revoke_refresh_token(
72 &self,
73 refresh_token: &str,
74 client_id: &str,
75 ) -> Result<bool, AuthError> {
76 let token_hash = hash_token(refresh_token);
77 let client_id = client_id.to_owned();
78 self.with_conn(move |conn| {
79 conn.execute(
80 "DELETE FROM refresh_tokens
81 WHERE refresh_token_hash = ?1 AND client_id = ?2",
82 params![token_hash, client_id],
83 )
84 .map(|deleted| deleted == 1)
85 .map_err(sqlite_error)
86 })
87 .await
88 }
89}
90
91#[cfg(test)]
92#[path = "sqlite_assertions_tests.rs"]
93mod tests;