1pub mod request_state;
4
5mod builder;
6mod origins;
7mod plugins;
8mod secrets;
9
10use crate::auth::trusted_origins::{matches_origin_pattern, OriginMatchSettings};
11use crate::cookies::AuthCookies;
12use crate::db::{DbAdapter, DbSchema};
13use crate::env::logger::Logger;
14use crate::error::OpenAuthError;
15use crate::options::{
16 DynamicRateLimitPathRule, HybridRateLimitOptions, OpenAuthOptions, RateLimitPathRule,
17 RateLimitStorageOption, RateLimitStore,
18};
19use crate::plugin::{AuthPlugin, PluginErrorCode};
20use crate::rate_limit::GovernorMemoryRateLimitStore;
21use http::Request;
22use openauth_oauth::oauth2::SocialOAuthProvider;
23use std::collections::BTreeMap;
24use std::fmt;
25use std::sync::Arc;
26use std::time::Duration;
27
28pub use builder::{
29 create_auth_context, create_auth_context_with_adapter, create_auth_context_with_environment,
30 create_auth_context_with_environment_and_adapter,
31};
32pub use secrets::SecretMaterial;
33
34use origins::push_trusted_origin;
35
36#[derive(Clone)]
37pub struct AuthContext {
38 pub app_name: String,
39 pub base_url: String,
40 pub base_path: String,
41 pub options: OpenAuthOptions,
42 pub auth_cookies: AuthCookies,
43 pub session_config: SessionConfig,
44 pub secret: String,
45 pub secret_config: SecretMaterial,
46 pub password: PasswordContext,
47 pub rate_limit: RateLimitContext,
48 pub trusted_origins: Vec<String>,
49 pub disabled_paths: Vec<String>,
50 pub plugins: Vec<AuthPlugin>,
51 pub adapter: Option<Arc<dyn DbAdapter>>,
52 pub social_providers: BTreeMap<String, Arc<dyn SocialOAuthProvider>>,
53 pub db_schema: DbSchema,
54 pub plugin_error_codes: BTreeMap<String, PluginErrorCode>,
55 pub plugin_database_hooks: Vec<crate::plugin::PluginDatabaseHook>,
56 pub plugin_migrations: Vec<crate::plugin::PluginMigration>,
57 pub logger: Logger,
58}
59
60#[derive(Clone, Default, PartialEq, Eq)]
62pub struct AuthEnvironment {
63 pub openauth_secret: Option<String>,
64 pub openauth_secrets: Option<String>,
65}
66
67impl fmt::Debug for AuthEnvironment {
68 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
69 formatter
70 .debug_struct("AuthEnvironment")
71 .field(
72 "openauth_secret",
73 &self.openauth_secret.as_ref().map(|_| "<redacted>"),
74 )
75 .field(
76 "openauth_secrets",
77 &self.openauth_secrets.as_ref().map(|_| "<redacted>"),
78 )
79 .finish()
80 }
81}
82
83impl AuthEnvironment {
84 pub fn from_process() -> Self {
85 Self {
86 openauth_secret: std::env::var("OPENAUTH_SECRET").ok(),
87 openauth_secrets: std::env::var("OPENAUTH_SECRETS").ok(),
88 }
89 }
90}
91
92#[derive(Debug, Clone, PartialEq, Eq)]
93pub struct SessionConfig {
94 pub update_age: u64,
95 pub expires_in: u64,
96 pub fresh_age: u64,
97 pub cookie_refresh_cache: bool,
98}
99
100#[derive(Clone)]
101pub struct PasswordContext {
102 pub config: PasswordPolicy,
103 pub hash: fn(&str) -> Result<String, OpenAuthError>,
104 pub verify: fn(&str, &str) -> Result<bool, OpenAuthError>,
105}
106
107#[derive(Debug, Clone, PartialEq, Eq)]
108pub struct PasswordPolicy {
109 pub min_password_length: usize,
110 pub max_password_length: usize,
111}
112
113#[derive(Clone)]
114pub struct RateLimitContext {
115 pub enabled: bool,
116 pub window: u64,
117 pub max: u64,
118 pub storage: RateLimitStorageOption,
119 pub custom_rules: Vec<RateLimitPathRule>,
120 pub dynamic_rules: Vec<DynamicRateLimitPathRule>,
121 pub plugin_rules: Vec<crate::plugin::PluginRateLimitRule>,
122 pub custom_store: Option<Arc<dyn RateLimitStore>>,
123 pub hybrid: HybridRateLimitOptions,
124 pub memory_cleanup_interval: Option<Duration>,
125 pub memory_store: Arc<GovernorMemoryRateLimitStore>,
126}
127
128impl AuthContext {
129 pub fn adapter(&self) -> Option<Arc<dyn DbAdapter>> {
130 self.adapter.clone()
131 }
132
133 pub fn social_provider(&self, id: &str) -> Option<Arc<dyn SocialOAuthProvider>> {
134 self.social_providers.get(id).cloned()
135 }
136
137 pub fn has_plugin(&self, id: &str) -> bool {
138 self.plugins.iter().any(|plugin| plugin.id == id)
139 }
140
141 pub fn is_trusted_origin(&self, url: &str, settings: Option<OriginMatchSettings>) -> bool {
142 self.trusted_origins
143 .iter()
144 .any(|origin| matches_origin_pattern(url, origin, settings))
145 }
146
147 pub fn trusted_origins_for_request(
148 &self,
149 request: Option<&Request<Vec<u8>>>,
150 ) -> Result<Vec<String>, OpenAuthError> {
151 let mut origins = self.trusted_origins.clone();
152 if let Some(provider) = self.options.trusted_origins.provider() {
153 for origin in provider.trusted_origins(request)? {
154 push_trusted_origin(&mut origins, origin);
155 }
156 }
157 Ok(origins)
158 }
159
160 pub fn is_trusted_origin_for_request(
161 &self,
162 url: &str,
163 settings: Option<OriginMatchSettings>,
164 request: Option<&Request<Vec<u8>>>,
165 ) -> Result<bool, OpenAuthError> {
166 Ok(self
167 .trusted_origins_for_request(request)?
168 .iter()
169 .any(|origin| matches_origin_pattern(url, origin, settings)))
170 }
171}