diff --git a/src/api/core/two_factor.rs b/src/api/core/two_factor.rs index 94cbc1e..1849f03 100644 --- a/src/api/core/two_factor.rs +++ b/src/api/core/two_factor.rs @@ -821,12 +821,19 @@ const APP_PREFIX: &str = "APP"; use chrono::Utc; +// let (ik, sk, ak) = get_duo_keys(); +fn get_duo_keys() -> (String, String, String) { + ( + CONFIG.duo_ikey().unwrap(), + CONFIG.duo_skey().unwrap(), + CONFIG.get_duo_akey(), + ) +} + pub fn generate_duo_signature(email: &str) -> String { let now = Utc::now().timestamp(); - let ik = CONFIG.duo_ikey().unwrap(); - let sk = CONFIG.duo_skey().unwrap(); - let ak = CONFIG.duo_akey().unwrap(); + let (ik, sk, ak) = get_duo_keys(); let duo_sign = sign_duo_values(&sk, email, &ik, DUO_PREFIX, now + DUO_EXPIRE); let app_sign = sign_duo_values(&ak, email, &ik, APP_PREFIX, now + APP_EXPIRE); @@ -852,9 +859,7 @@ pub fn validate_duo_login(email: &str, response: &str) -> EmptyResult { let now = Utc::now().timestamp(); - let ik = CONFIG.duo_ikey().unwrap(); - let sk = CONFIG.duo_skey().unwrap(); - let ak = CONFIG.duo_akey().unwrap(); + let (ik, sk, ak) = get_duo_keys(); let auth_user = parse_duo_values(&sk, auth_sig, &ik, AUTH_PREFIX, now)?; let app_user = parse_duo_values(&ak, app_sig, &ik, APP_PREFIX, now)?; diff --git a/src/config.rs b/src/config.rs index 309b65a..d40eeca 100644 --- a/src/config.rs +++ b/src/config.rs @@ -9,7 +9,7 @@ lazy_static! { println!("Error loading config:\n\t{:?}\n", e); exit(12) }); - pub static ref CONFIG_FILE: String = { + pub static ref CONFIG_FILE: String = { let data_folder = get_env("DATA_FOLDER").unwrap_or_else(|| String::from("data")); get_env("CONFIG_FILE").unwrap_or_else(|| format!("{}/config.json", data_folder)) }; @@ -64,7 +64,7 @@ macro_rules! make_config { /// Merges the values of both builders into a new builder. /// If both have the same element, `other` wins. - fn merge(&self, other: &Self) -> Self { + fn merge(&self, other: &Self, show_overrides: bool) -> Self { let mut overrides = Vec::new(); let mut builder = self.clone(); $($( @@ -77,7 +77,7 @@ macro_rules! make_config { } )+)+ - if !overrides.is_empty() { + if show_overrides && !overrides.is_empty() { // We can't use warn! here because logging isn't setup yet. println!("[WARNING] The following environment variables are being overriden by the config file,"); println!("[WARNING] please use the admin panel to make changes to them:"); @@ -315,8 +315,8 @@ make_config! { duo_skey: Pass, true, option; /// Host duo_host: String, true, option; - /// Application Key - duo_akey: Pass, true, option; + /// Application Key (generated automatically) + _duo_akey: Pass, false, option; }, /// SMTP Email Settings @@ -349,10 +349,10 @@ fn validate_config(cfg: &ConfigItems) -> Result<(), Error> { } } - if (cfg.duo_host.is_some() || cfg.duo_ikey.is_some() || cfg.duo_skey.is_some() || cfg.duo_akey.is_some()) - && !(cfg.duo_host.is_some() && cfg.duo_ikey.is_some() && cfg.duo_skey.is_some() && cfg.duo_akey.is_some()) + if (cfg.duo_host.is_some() || cfg.duo_ikey.is_some() || cfg.duo_skey.is_some()) + && !(cfg.duo_host.is_some() && cfg.duo_ikey.is_some() && cfg.duo_skey.is_some()) { - err!("All Duo options need to be set for Duo support") + err!("All Duo options need to be set for global Duo support") } if cfg.yubico_client_id.is_some() != cfg.yubico_secret_key.is_some() { @@ -377,7 +377,7 @@ impl Config { let _usr = ConfigBuilder::from_file(&CONFIG_FILE).unwrap_or_default(); // Create merged config, config file overwrites env - let builder = _env.merge(&_usr); + let builder = _env.merge(&_usr, true); // Fill any missing with defaults let config = builder.build(); @@ -406,7 +406,7 @@ impl Config { // Prepare the combined config let config = { let env = &self.inner.read().unwrap()._env; - env.merge(&builder).build() + env.merge(&builder, false).build() }; validate_config(&config)?; @@ -425,6 +425,14 @@ impl Config { Ok(()) } + pub fn update_config_partial(&self, other: ConfigBuilder) -> Result<(), Error> { + let builder = { + let usr = &self.inner.read().unwrap()._usr; + usr.merge(&other, false) + }; + self.update_config(builder) + } + pub fn delete_user_config(&self) -> Result<(), Error> { crate::util::delete_file(&CONFIG_FILE)?; @@ -460,9 +468,21 @@ impl Config { let inner = &self.inner.read().unwrap().config; inner._enable_smtp && inner.smtp_host.is_some() } - pub fn yubico_enabled(&self) -> bool { - let inner = &self.inner.read().unwrap().config; - inner._enable_yubico && inner.yubico_client_id.is_some() && inner.yubico_secret_key.is_some() + + pub fn get_duo_akey(&self) -> String { + if let Some(akey) = self._duo_akey() { + akey + } else { + let akey = crate::crypto::get_random_64(); + let akey_s = data_encoding::BASE64.encode(&akey); + + // Save the new value + let mut builder = ConfigBuilder::default(); + builder._duo_akey = Some(akey_s.clone()); + self.update_config_partial(builder).ok(); + + akey_s + } } pub fn render_template(