Skip to main content

alibi_core/session/
request.rs

1//! Session authentication consumes logical credential input, not an invented HTTP request.
2
3use crate::AuthContext;
4use crate::types::RequestExtensions;
5use crate::utils::json::JsValue;
6use crate::{AuthRequest, AuthSchema, HttpMethod, SessionView, UserView};
7use std::collections::HashMap;
8
9/// Input and trusted state used by the shared physical/cache session readers.
10/// Implementations must never populate authenticated state from client data.
11pub trait SessionRequest: Send + Sync {
12    /// Retain a genuine logical endpoint call when this input has one.
13    fn endpoint_call(&self) -> Option<&crate::endpoint::EndpointCall> {
14        None
15    }
16    /// The original physical request, when the caller supplied one.
17    fn physical_request(&self) -> Option<&AuthRequest> {
18        None
19    }
20    fn session_headers(&self) -> &HashMap<String, String>;
21    fn session_method(&self) -> &HttpMethod;
22    fn session_query_truthy(&self, name: &str) -> bool;
23    fn extensions(&self) -> &RequestExtensions;
24    fn virtual_session<S: AuthSchema>(&self, context: &AuthContext<S>) -> Option<SessionView>;
25    fn authenticated_user<S: AuthSchema>(&self, _context: &AuthContext<S>) -> Option<S::User> {
26        None
27    }
28    fn take_response_headers(&self) -> crate::Headers;
29    fn queue_response_header(&self, name: impl Into<String>, value: impl Into<String>);
30    fn set_session_hook_snapshot(&self, user: UserView, session: SessionView);
31}
32
33impl SessionRequest for AuthRequest {
34    fn physical_request(&self) -> Option<&AuthRequest> {
35        Some(self)
36    }
37    fn session_headers(&self) -> &HashMap<String, String> {
38        &self.headers
39    }
40    fn session_method(&self) -> &HttpMethod {
41        self.method()
42    }
43    fn session_query_truthy(&self, name: &str) -> bool {
44        self.query.get(name).is_some_and(|value| !value.is_empty())
45    }
46    fn extensions(&self) -> &RequestExtensions {
47        self.extensions()
48    }
49    fn virtual_session<S: AuthSchema>(&self, _context: &AuthContext<S>) -> Option<SessionView> {
50        self.virtual_session().cloned()
51    }
52    fn take_response_headers(&self) -> crate::Headers {
53        self.take_response_headers()
54    }
55    fn queue_response_header(&self, name: impl Into<String>, value: impl Into<String>) {
56        self.queue_response_header(name, value);
57    }
58    fn set_session_hook_snapshot(&self, user: UserView, session: SessionView) {
59        self.set_session_hook_snapshot(user, session);
60    }
61}
62
63impl SessionRequest for crate::endpoint::EndpointCall {
64    fn physical_request(&self) -> Option<&AuthRequest> {
65        self.request()
66    }
67    fn endpoint_call(&self) -> Option<&crate::endpoint::EndpointCall> {
68        Some(self)
69    }
70    fn session_headers(&self) -> &HashMap<String, String> {
71        static EMPTY: std::sync::LazyLock<HashMap<String, String>> =
72            std::sync::LazyLock::new(HashMap::new);
73        self.headers().unwrap_or(&EMPTY)
74    }
75    fn session_method(&self) -> &HttpMethod {
76        self.method().unwrap_or_else(|| self.default_method())
77    }
78    fn session_query_truthy(&self, name: &str) -> bool {
79        self.query()
80            .and_then(|query| query.get(name))
81            .is_some_and(|value| match value {
82                JsValue::Null => false,
83                JsValue::Bool(value) => *value,
84                JsValue::Number(value) => *value != 0.0 && !value.is_nan(),
85                JsValue::String(value) => !value.is_empty(),
86                JsValue::Date(_) | JsValue::Array(_) | JsValue::Object(_) => true,
87            })
88    }
89    fn extensions(&self) -> &RequestExtensions {
90        self.extensions()
91    }
92    fn virtual_session<S: AuthSchema>(&self, context: &AuthContext<S>) -> Option<SessionView> {
93        self.authenticated_user(context)
94            .and_then(|_| self.virtual_session())
95    }
96    fn authenticated_user<S: AuthSchema>(&self, context: &AuthContext<S>) -> Option<S::User> {
97        self.authenticated_user::<S>(context)
98    }
99    fn take_response_headers(&self) -> crate::Headers {
100        self.take_response_headers()
101    }
102    fn queue_response_header(&self, name: impl Into<String>, value: impl Into<String>) {
103        self.queue_response_header(name, value);
104    }
105    fn set_session_hook_snapshot(&self, user: UserView, session: SessionView) {
106        self.set_session_hook_snapshot(user, session);
107    }
108}