#![allow(unused_imports)]
use std::collections::{HashMap, HashSet};
use std::env;
use std::fmt::Display;
use std::fs;
use std::num::NonZeroUsize;
use std::path::Path;
use std::str::FromStr;
use std::time::Duration;
use super::authorization_config::AuthorizationConfig;
use super::raw_config::LoggerType;
use super::{
BootstrapConfig, BootstrapConfigLoadingError, JwtConfig, LogConfig, LogTypeConfig,
MemoryLogConfig, PolicyStoreConfig, PolicyStoreSource,
};
use super::{BootstrapConfigRaw, LockServiceConfig};
use crate::HttpClientConfig;
use crate::context_data_api::DataStoreConfig;
use crate::jwt_config::{TrustedIssuerLoaderConfig, TrustedIssuerLoaderTypeRaw, WorkersCount};
use crate::log::{LogLevel, StdOutLoggerMode};
use jsonwebtoken::Algorithm;
use serde::{Deserialize, Deserializer, Serialize};
impl BootstrapConfig {
#[cfg(not(target_arch = "wasm32"))]
pub fn from_raw_config_and_env(
raw: Option<BootstrapConfigRaw>,
) -> Result<Self, BootstrapConfigLoadingError> {
let config_raw = BootstrapConfigRaw::from_raw_config_and_env(raw)?;
Self::from_raw_config(&config_raw)
}
pub fn from_raw_config(raw: &BootstrapConfigRaw) -> Result<Self, BootstrapConfigLoadingError> {
let lock_config = raw.lock.is_enabled().then(|| raw.try_into()).transpose()?;
let log_config = LogConfig {
log_type: resolve_log_type(raw)?,
log_level: raw.log_level,
};
let policy_store_config = build_policy_store_config(raw)?;
let jwks = raw
.local_jwks
.as_ref()
.map(|path| {
fs::read_to_string(path).map_err(|e| {
BootstrapConfigLoadingError::LoadLocalJwks(path.clone(), e.to_string())
})
})
.transpose()?;
let jwt_config = JwtConfig {
jwks,
jwt_sig_validation: raw.jwt_sig_validation.into(),
jwt_status_validation: raw.jwt_status_validation.into(),
signature_algorithms_supported: raw.jwt_signature_algorithms_supported.clone(),
token_cache_max_ttl_secs: raw.token_cache_max_ttl,
token_cache_capacity: raw.token_cache_capacity,
token_cache_earliest_expiration_eviction: raw.token_cache_earliest_expiration_eviction,
trusted_issuer_loader: raw
.trusted_issuer_loader_type
.to_config(raw.trusted_issuer_loader_workers),
jwks_refresh_interval: raw.jwks_refresh_interval,
jwks_refresh_min_interval: raw.jwks_refresh_min_interval,
status_list_refresh_interval_max: raw.status_list_refresh_interval_max,
};
let authorization_config = AuthorizationConfig {
decision_log_default_jwt_id: raw.decision_log_default_jwt_id.clone(),
strict_schema_validation: raw.strict_schema_validation.into(),
};
let data_store_config = build_data_store_config(raw);
let http_client_config = HttpClientConfig {
max_retries: raw.http_client_request_max_retries,
retry_delay: Duration::from_secs(raw.http_client_request_retry_delay),
#[cfg(not(target_arch = "wasm32"))]
request_timeout: Duration::from_secs(raw.http_client_request_timeout),
max_response_size_bytes: match raw.http_client_max_response_size_bytes {
0 => None,
n => Some(n),
},
};
Ok(Self {
application_name: raw.application_name.clone(),
log_config,
policy_store_config,
jwt_config,
authorization_config,
lock_config,
max_default_entities: raw.max_default_entities,
max_base64_size: raw.max_base64_size,
data_store_config,
http_client_config,
})
}
}
fn build_policy_store_config(
raw: &BootstrapConfigRaw,
) -> Result<PolicyStoreConfig, BootstrapConfigLoadingError> {
match (
raw.local_policy_store.clone(),
raw.policy_store_uri.clone(),
raw.policy_store_local_fn.clone(),
raw.policy_store_cjar_url.clone(),
) {
(None, None, None, None) => Err(BootstrapConfigLoadingError::MissingPolicyStore),
(Some(policy_store), None, None, None) => Ok(PolicyStoreConfig {
source: PolicyStoreSource::Json(policy_store),
refresh_interval_secs: raw.policy_store_refresh_interval_secs,
}),
(None, Some(policy_store_uri), None, None) => Ok(PolicyStoreConfig {
source: PolicyStoreSource::Uri(policy_store_uri),
refresh_interval_secs: raw.policy_store_refresh_interval_secs,
}),
(None, None, None, Some(policy_store_cjar_url)) => Ok(PolicyStoreConfig {
source: PolicyStoreSource::CjarUrl(policy_store_cjar_url),
refresh_interval_secs: raw.policy_store_refresh_interval_secs,
}),
(None, None, Some(raw_path), None) => {
let path = Path::new(&raw_path);
let source = if path.is_dir() {
PolicyStoreSource::Directory(path.into())
} else {
let file_ext = path
.extension()
.and_then(|ext| ext.to_str())
.map(str::to_lowercase);
match file_ext.as_deref() {
Some("json") => PolicyStoreSource::FileJson(path.into()),
Some("yaml" | "yml") => PolicyStoreSource::FileYaml(path.into()),
Some("cjar") => PolicyStoreSource::CjarFile(path.into()),
_ => {
return Err(
BootstrapConfigLoadingError::UnsupportedPolicyStoreFileFormat(raw_path),
);
},
}
};
Ok(PolicyStoreConfig {
source,
refresh_interval_secs: raw.policy_store_refresh_interval_secs,
})
},
_ => Err(BootstrapConfigLoadingError::ConflictingPolicyStores),
}
}
fn build_data_store_config(raw: &BootstrapConfigRaw) -> DataStoreConfig {
let defaults = DataStoreConfig::default();
DataStoreConfig {
max_entries: raw.data_store_max_entries.unwrap_or(defaults.max_entries),
max_entry_size: raw
.data_store_max_entry_size
.unwrap_or(defaults.max_entry_size),
default_ttl: raw
.data_store_default_ttl
.map(std::time::Duration::from_secs)
.or(defaults.default_ttl),
max_ttl: raw
.data_store_max_ttl
.map(std::time::Duration::from_secs)
.or(defaults.max_ttl),
enable_metrics: raw
.data_store_enable_metrics
.unwrap_or(defaults.enable_metrics),
memory_alert_threshold: raw
.data_store_memory_alert_threshold
.unwrap_or(defaults.memory_alert_threshold),
}
}
fn resolve_log_type(
raw_config: &BootstrapConfigRaw,
) -> Result<LogTypeConfig, BootstrapConfigLoadingError> {
let log_type_config = match raw_config.log_type {
LoggerType::Off => LogTypeConfig::Off,
LoggerType::Memory => LogTypeConfig::Memory(MemoryLogConfig {
log_ttl: raw_config
.log_ttl
.ok_or(BootstrapConfigLoadingError::MissingLogTTL)?,
max_item_size: raw_config.log_max_item_size,
max_items: raw_config.log_max_items,
}),
LoggerType::StdOut => {
let std_out_logger_conf = match raw_config.stdout_mode {
#[cfg(not(target_arch = "wasm32"))]
super::log_config::StdOutMode::Async => StdOutLoggerMode::Async {
timeout_millis: raw_config.stdout_timeout_millis,
buffer_limit: raw_config.stdout_buffer_limit,
},
super::log_config::StdOutMode::Immediate => StdOutLoggerMode::Immediate,
};
LogTypeConfig::StdOut(std_out_logger_conf)
},
};
Ok(log_type_config)
}