pub trait SessionStore:
Send
+ Sync
+ 'static {
// Required methods
fn insert_session(
&self,
session: &SessionRecord,
token: &TokenHash,
) -> impl Future<Output = Result<(), StoreError>> + Send;
fn find_by_token(
&self,
token: &TokenHash,
) -> impl Future<Output = Result<Option<TokenLookup>, StoreError>> + Send;
fn apply(
&self,
update: &SessionUpdate,
) -> impl Future<Output = Result<bool, StoreError>> + Send;
fn delete_session(
&self,
session_id: Uuid,
) -> impl Future<Output = Result<bool, StoreError>> + Send;
fn delete_subject_sessions(
&self,
subject: &str,
) -> impl Future<Output = Result<Vec<Uuid>, StoreError>> + Send;
fn list_subject_sessions(
&self,
subject: &str,
) -> impl Future<Output = Result<Vec<SessionRecord>, StoreError>> + Send;
fn delete_expired(
&self,
now: DateTime<Utc>,
idle_cutoff: DateTime<Utc>,
) -> impl Future<Output = Result<u64, StoreError>> + Send;
fn record_event(
&self,
event: &SessionEvent,
) -> impl Future<Output = Result<(), StoreError>> + Send;
fn delete_events_before(
&self,
cutoff: DateTime<Utc>,
) -> impl Future<Output = Result<u64, StoreError>> + Send;
// Provided methods
fn sharded(&self) -> bool { ... }
fn claim_event(
&self,
scope: ClaimScope<'_>,
kind: EventKind,
now: DateTime<Utc>,
window: TimeDelta,
) -> impl Future<Output = Result<bool, StoreError>> + Send { ... }
}Expand description
Session persistence.
Every method must be safe to call concurrently from many processes. Each returned future
must be Send. Timestamps may be stored at microsecond precision.
Required Methods§
Sourcefn insert_session(
&self,
session: &SessionRecord,
token: &TokenHash,
) -> impl Future<Output = Result<(), StoreError>> + Send
fn insert_session( &self, session: &SessionRecord, token: &TokenHash, ) -> impl Future<Output = Result<(), StoreError>> + Send
Stores a new session with token as its current token (issued_at = created_at,
unused, not superseded).
Sourcefn find_by_token(
&self,
token: &TokenHash,
) -> impl Future<Output = Result<Option<TokenLookup>, StoreError>> + Send
fn find_by_token( &self, token: &TokenHash, ) -> impl Future<Output = Result<Option<TokenLookup>, StoreError>> + Send
Finds the session holding token, current or superseded.
Sourcefn apply(
&self,
update: &SessionUpdate,
) -> impl Future<Output = Result<bool, StoreError>> + Send
fn apply( &self, update: &SessionUpdate, ) -> impl Future<Output = Result<bool, StoreError>> + Send
Applies update atomically, in this order:
- If
rotationis set and itsSupersedecondition holds for the current token: supersede it, insert the new token as current, prune old superseded tokens. - Mark
mark_usedused if it belongs to the session and is unused; this includes the token step 1 just inserted. - Set
last_seen_at = nowand everySomefield.
A session must never have more than one current token. Returns whether the rotation
happened; a missing session is not an error and returns false.
Sourcefn delete_session(
&self,
session_id: Uuid,
) -> impl Future<Output = Result<bool, StoreError>> + Send
fn delete_session( &self, session_id: Uuid, ) -> impl Future<Output = Result<bool, StoreError>> + Send
Deletes a session and its tokens. Returns whether it existed.
Sourcefn delete_subject_sessions(
&self,
subject: &str,
) -> impl Future<Output = Result<Vec<Uuid>, StoreError>> + Send
fn delete_subject_sessions( &self, subject: &str, ) -> impl Future<Output = Result<Vec<Uuid>, StoreError>> + Send
Deletes every session of subject (canonical JSON). Returns the ids it deleted.
Sourcefn list_subject_sessions(
&self,
subject: &str,
) -> impl Future<Output = Result<Vec<SessionRecord>, StoreError>> + Send
fn list_subject_sessions( &self, subject: &str, ) -> impl Future<Output = Result<Vec<SessionRecord>, StoreError>> + Send
Every session of subject (canonical JSON), including expired ones not yet purged.
Sourcefn delete_expired(
&self,
now: DateTime<Utc>,
idle_cutoff: DateTime<Utc>,
) -> impl Future<Output = Result<u64, StoreError>> + Send
fn delete_expired( &self, now: DateTime<Utc>, idle_cutoff: DateTime<Utc>, ) -> impl Future<Output = Result<u64, StoreError>> + Send
Deletes sessions with expires_at <= now or last_seen_at <= idle_cutoff. Returns how
many.
Sourcefn record_event(
&self,
event: &SessionEvent,
) -> impl Future<Output = Result<(), StoreError>> + Send
fn record_event( &self, event: &SessionEvent, ) -> impl Future<Output = Result<(), StoreError>> + Send
Appends a security event. Stores without an event log may discard it.
Sourcefn delete_events_before(
&self,
cutoff: DateTime<Utc>,
) -> impl Future<Output = Result<u64, StoreError>> + Send
fn delete_events_before( &self, cutoff: DateTime<Utc>, ) -> impl Future<Output = Result<u64, StoreError>> + Send
Deletes events with at < cutoff. Returns how many. Also deletes event claims older
than cutoff.
Provided Methods§
Sourcefn sharded(&self) -> bool
fn sharded(&self) -> bool
Whether the store partitions data into buckets that must be co-located.
When true, the guard gives every session an id whose session_bucket it picks, and
mines each of the session’s tokens until its token_bucket is the same, so one session’s
records always live together. The default, false, skips that work.
Sourcefn claim_event(
&self,
scope: ClaimScope<'_>,
kind: EventKind,
now: DateTime<Utc>,
window: TimeDelta,
) -> impl Future<Output = Result<bool, StoreError>> + Send
fn claim_event( &self, scope: ClaimScope<'_>, kind: EventKind, now: DateTime<Utc>, window: TimeDelta, ) -> impl Future<Output = Result<bool, StoreError>> + Send
Claims the right to report a kind event for scope, for deduplication across
processes. Succeeds (true) unless a claim for the same scope and kind was made after
now - window, and records now as the new claim when it does. Session and subject
claims are independent. Must be atomic across processes.
The guard claims ClaimScope::Session before recording an unenforced event
(shadow_dedup_window) and ClaimScope::Subject before calling the hook for an
enforced one (alert_dedup_window).
The default always succeeds, which leaves shadow deduplication to each process and disables alert deduplication.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".
Implementations on Foreign Types§
Source§impl<T: SessionStore> SessionStore for Arc<T>
impl<T: SessionStore> SessionStore for Arc<T>
fn sharded(&self) -> bool
fn insert_session( &self, session: &SessionRecord, token: &TokenHash, ) -> impl Future<Output = Result<(), StoreError>> + Send
fn find_by_token( &self, token: &TokenHash, ) -> impl Future<Output = Result<Option<TokenLookup>, StoreError>> + Send
fn apply( &self, update: &SessionUpdate, ) -> impl Future<Output = Result<bool, StoreError>> + Send
fn delete_session( &self, session_id: Uuid, ) -> impl Future<Output = Result<bool, StoreError>> + Send
fn delete_subject_sessions( &self, subject: &str, ) -> impl Future<Output = Result<Vec<Uuid>, StoreError>> + Send
fn list_subject_sessions( &self, subject: &str, ) -> impl Future<Output = Result<Vec<SessionRecord>, StoreError>> + Send
fn delete_expired( &self, now: DateTime<Utc>, idle_cutoff: DateTime<Utc>, ) -> impl Future<Output = Result<u64, StoreError>> + Send
fn record_event( &self, event: &SessionEvent, ) -> impl Future<Output = Result<(), StoreError>> + Send
fn delete_events_before( &self, cutoff: DateTime<Utc>, ) -> impl Future<Output = Result<u64, StoreError>> + Send
fn claim_event( &self, scope: ClaimScope<'_>, kind: EventKind, now: DateTime<Utc>, window: TimeDelta, ) -> impl Future<Output = Result<bool, StoreError>> + Send
Implementors§
impl SessionStore for MemoryStore
impl SessionStore for PgStore
postgres only.impl SessionStore for ValkeyStore
valkey only.