1use crate::auth::jwt::JWTAuthConfig;
2use crate::auth::oidc::OIDCAuthConfig;
3use crate::auth::token::SimpleTokenAuthConfig;
4use crate::session_storage::RedisOptions;
5use std::env;
6use std::time::Duration;
7
8#[allow(clippy::upper_case_acronyms)]
9pub enum AuthTypeConfig {
10 SimpleToken,
11 JWT,
12 OIDC,
13}
14pub struct ServerConfig {
15 pub access_rules_path: String,
16 pub auth_type: AuthTypeConfig,
17 pub simple_token_config: Option<SimpleTokenAuthConfig>,
18 pub jwt_config: Option<JWTAuthConfig>,
19 pub oidc_config: Option<OIDCAuthConfig>,
20 pub pep_crypto_server_config_path: String,
21 pub public_paas_config_path: String,
22 pub server_listen_address: String,
23 pub request_timeout: Duration,
24 pub redis_url: Option<String>,
25 pub redis_options: Option<RedisOptions>,
26 pub pep_session_lifetime: Duration,
27 pub pep_session_length: usize,
28 pub workers: Option<usize>,
29}
30
31impl Default for ServerConfig {
32 fn default() -> Self {
33 Self {
34 access_rules_path: "resources/access_rules.yml".to_string(),
35 auth_type: AuthTypeConfig::SimpleToken,
36 simple_token_config: Some(SimpleTokenAuthConfig {
37 token_users_path: "resources/token_users.yml".to_string(),
38 }),
39 jwt_config: Some(JWTAuthConfig {
40 jwt_key_path: "resources/public.pem".to_string(),
41 jwt_audience: String::new(),
42 }),
43 oidc_config: None,
44 pep_crypto_server_config_path: "resources/server_config.yml".to_string(),
45 public_paas_config_path: "resources/paas_config.json".to_string(),
46 server_listen_address: "0.0.0.0:8080".to_string(),
47 request_timeout: Duration::from_secs(60),
48 redis_url: None,
49 redis_options: Some(RedisOptions {
50 max_pool_size: 15,
51 min_idle: Some(2),
52 max_lifetime: Some(Duration::from_secs(300)),
53 connection_timeout: Some(Duration::from_secs(60)),
54 }),
55 pep_session_lifetime: Duration::from_secs(3600),
56 pep_session_length: 10,
57 workers: None,
58 }
59 }
60}
61
62impl ServerConfig {
63 pub fn from_env() -> Self {
64 let auth_type = match env::var("AUTH_TYPE")
66 .unwrap_or_else(|_| "token".to_string())
67 .to_lowercase()
68 .as_str()
69 {
70 "jwt" => AuthTypeConfig::JWT,
71 "oidc" => AuthTypeConfig::OIDC,
72 _ => AuthTypeConfig::SimpleToken, };
74
75 let simple_token_config = match auth_type {
77 AuthTypeConfig::SimpleToken => Some(SimpleTokenAuthConfig {
78 token_users_path: env::var("TOKEN_USERS_PATH")
79 .unwrap_or_else(|_| "resources/token_users.yml".to_string()),
80 }),
81 _ => None,
82 };
83
84 let jwt_config = match auth_type {
85 AuthTypeConfig::JWT => Some(JWTAuthConfig {
86 jwt_key_path: env::var("JWT_KEY_PATH")
87 .unwrap_or_else(|_| "resources/public.pem".to_string()),
88 jwt_audience: env::var("JWT_AUDIENCE")
89 .expect("JWT_AUDIENCE must be set when AUTH_TYPE=jwt"),
90 }),
91 _ => None,
92 };
93
94 let oidc_config = match auth_type {
95 AuthTypeConfig::OIDC => {
96 let audiences = env::var("OIDC_AUDIENCES")
97 .map(|v| parse_comma_separated(v, vec![]))
98 .expect("OIDC_AUDIENCES must be set when AUTH_TYPE=oidc");
99
100 if audiences.is_empty() {
101 panic!("OIDC_AUDIENCES cannot be empty when AUTH_TYPE=oidc");
102 }
103
104 Some(OIDCAuthConfig {
105 provider_url: env::var("OIDC_PROVIDER_URL")
106 .expect("OIDC_PROVIDER_URL must be set when AUTH_TYPE=oidc"),
107 audiences,
108 discovery_timeout: parse_duration(
109 env::var("OIDC_DISCOVERY_TIMEOUT").ok(),
110 Duration::from_secs(10),
111 ),
112 })
113 }
114 _ => None,
115 };
116 let redis_options = match env::var("REDIS_URL").is_ok() {
117 true => Some(RedisOptions {
118 max_pool_size: env::var("REDIS_MAX_POOL_SIZE")
119 .ok()
120 .and_then(|v| v.parse::<u32>().ok())
121 .unwrap_or_else(|| RedisOptions::default().max_pool_size),
122 min_idle: env::var("REDIS_MIN_IDLE")
123 .ok()
124 .and_then(|v| v.parse::<u32>().ok())
125 .or_else(|| RedisOptions::default().min_idle),
126 max_lifetime: env::var("REDIS_MAX_LIFETIME")
127 .ok()
128 .and_then(|v| v.parse::<u64>().ok())
129 .map(Duration::from_secs)
130 .or_else(|| RedisOptions::default().max_lifetime),
131 connection_timeout: env::var("REDIS_CONNECTION_TIMEOUT")
132 .ok()
133 .and_then(|v| v.parse::<u64>().ok())
134 .map(Duration::from_secs)
135 .or_else(|| RedisOptions::default().connection_timeout),
136 }),
137 false => None,
138 };
139
140 Self {
141 access_rules_path: env::var("ACCESS_RULES_PATH")
142 .unwrap_or_else(|_| "resources/access_rules.yml".to_string()),
143 auth_type,
144 simple_token_config,
145 jwt_config,
146 oidc_config,
147 pep_crypto_server_config_path: env::var("PEP_CRYPTO_SERVER_CONFIG_PATH")
148 .unwrap_or_else(|_| "resources/server_config.yml".to_string()),
149 public_paas_config_path: env::var("PUBLIC_PAAS_CONFIG_PATH")
150 .unwrap_or_else(|_| "resources/paas_config.json".to_string()),
151 server_listen_address: env::var("SERVER_LISTEN_ADDRESS")
152 .unwrap_or_else(|_| "0.0.0.0:8080".to_string()),
153 request_timeout: parse_duration(
154 env::var("REQUEST_TIMEOUT").ok(),
155 Duration::from_secs(60),
156 ),
157 redis_url: env::var("REDIS_URL").ok(),
158 redis_options,
159 pep_session_lifetime: parse_duration(
160 env::var("PEP_SESSION_LIFETIME").ok(),
161 Duration::from_secs(3600),
162 ),
163 pep_session_length: env::var("PEP_SESSION_LENGTH")
164 .ok()
165 .and_then(|v| v.parse::<usize>().ok())
166 .unwrap_or(10),
167 workers: env::var("WORKERS")
168 .ok()
169 .and_then(|w| w.parse::<usize>().ok()),
170 }
171 }
172}
173
174fn parse_comma_separated(value: String, default: Vec<String>) -> Vec<String> {
175 if value.trim().is_empty() {
176 default
177 } else {
178 value
179 .split(',')
180 .map(|s| s.trim().to_string())
181 .filter(|s| !s.is_empty())
182 .collect()
183 }
184}
185
186fn parse_duration(env_var: Option<String>, default: Duration) -> Duration {
187 match env_var {
188 Some(value) => match value.parse::<u64>() {
189 Ok(seconds) => Duration::from_secs(seconds),
190 Err(_) => {
191 eprintln!("Invalid duration value '{}', using default", value);
192 default
193 }
194 },
195 None => default,
196 }
197}