Skip to main content

paas_server/
config.rs

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        // Determine auth type from environment
65        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, // Default to token auth
73        };
74
75        // Create appropriate auth config based on auth type
76        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}