Skip to main content

alibi_core/
authenticated_user.rs

1//! Authenticated identity without inventing an application-owned storage model.
2//!
3//! A cookie cache deliberately retains the authenticated output snapshot until
4//! its expiry. The stored variant keeps the complete real model for callers
5//! whose contracts require fields absent from that public snapshot.
6
7use crate::{AuthSchema, AuthUser, UserView};
8use chrono::{DateTime, Utc};
9use serde::{Serialize, Serializer};
10use std::{borrow::Cow, fmt};
11
12/// The identity established by a cache-aware session read.
13///
14/// This type does not imply that a cached identity still has a database row or
15/// current permissions. Sensitive stateful operations must use storage-backed
16/// authentication instead.
17pub enum AuthenticatedUser<S: AuthSchema> {
18    Stored(crate::AdapterRecord<S::User>),
19    Cached(Box<UserView>),
20}
21
22impl<S: AuthSchema> Clone for AuthenticatedUser<S> {
23    fn clone(&self) -> Self {
24        match self {
25            Self::Stored(user) => Self::Stored(user.clone()),
26            Self::Cached(user) => Self::Cached(user.clone()),
27        }
28    }
29}
30
31impl<S: AuthSchema> fmt::Debug for AuthenticatedUser<S> {
32    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33        match self {
34            Self::Stored(user) => f.debug_tuple("Stored").field(user).finish(),
35            Self::Cached(user) => f.debug_tuple("Cached").field(user).finish(),
36        }
37    }
38}
39
40impl<S: AuthSchema> Serialize for AuthenticatedUser<S> {
41    fn serialize<T: Serializer>(&self, serializer: T) -> Result<T::Ok, T::Error> {
42        match self {
43            Self::Stored(user) => user.serialize(serializer),
44            Self::Cached(user) => user.serialize(serializer),
45        }
46    }
47}
48
49macro_rules! delegate {
50    ($name:ident, $output:ty) => {
51        fn $name(&self) -> $output {
52            match self {
53                Self::Stored(user) => user.$name(),
54                Self::Cached(user) => user.$name(),
55            }
56        }
57    };
58}
59
60impl<S: AuthSchema> AuthUser for AuthenticatedUser<S> {
61    delegate!(adapter_snapshot, Option<&crate::AdapterOutput>);
62    delegate!(retained_user_view, Option<&crate::UserView>);
63    delegate!(additional_fields, crate::field_policy::FieldOutput);
64    delegate!(id, Cow<'_, str>);
65    delegate!(email, Option<&str>);
66    delegate!(name, Option<&str>);
67    delegate!(email_verified, bool);
68    delegate!(image, Option<&str>);
69    delegate!(created_at, DateTime<Utc>);
70    delegate!(updated_at, DateTime<Utc>);
71    delegate!(username, Option<&str>);
72    delegate!(display_username, Option<&str>);
73    delegate!(two_factor_enabled, bool);
74    delegate!(two_factor_enabled_value, Option<bool>);
75    delegate!(role, Option<&str>);
76    delegate!(banned, bool);
77    delegate!(banned_value, Option<bool>);
78    delegate!(ban_reason, Option<&str>);
79    delegate!(ban_expires, Option<DateTime<Utc>>);
80    delegate!(metadata, &serde_json::Value);
81    delegate!(is_anonymous, Option<bool>);
82    delegate!(phone_number, Option<&str>);
83    delegate!(phone_number_verified, Option<bool>);
84    delegate!(last_login_method, Option<&str>);
85}