update proxmox-tfa to 2.0

and fix still-very-bad updater usage in config api call...

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2021-11-29 11:19:49 +01:00
parent 0fee4ff2a4
commit e6e2927e72
4 changed files with 58 additions and 17 deletions

View File

@ -100,7 +100,7 @@ proxmox-lang = "1"
proxmox-router = { version = "1.1", features = [ "cli" ] } proxmox-router = { version = "1.1", features = [ "cli" ] }
proxmox-schema = { version = "1", features = [ "api-macro" ] } proxmox-schema = { version = "1", features = [ "api-macro" ] }
proxmox-section-config = "1" proxmox-section-config = "1"
proxmox-tfa = { version = "1.3", features = [ "api", "api-types" ] } proxmox-tfa = { version = "2", features = [ "api", "api-types" ] }
proxmox-time = "1" proxmox-time = "1"
proxmox-uuid = "1" proxmox-uuid = "1"
proxmox-serde = "0.1" proxmox-serde = "0.1"

View File

@ -228,6 +228,7 @@ fn add_tfa_entry(
value, value,
challenge, challenge,
r#type, r#type,
None,
)?; )?;
crate::config::tfa::write(&data)?; crate::config::tfa::write(&data)?;
Ok(out) Ok(out)

View File

@ -1,12 +1,13 @@
//! For now this only has the TFA subdir, which is in this file. //! For now this only has the TFA subdir, which is in this file.
//! If we add more, it should be moved into a sub module. //! If we add more, it should be moved into a sub module.
use anyhow::Error; use anyhow::{format_err, Error};
use hex::FromHex; use hex::FromHex;
use serde::{Deserialize, Serialize};
use proxmox_router::{Router, RpcEnvironment, Permission, SubdirMap};
use proxmox_schema::api;
use proxmox_router::list_subdirs_api_method; use proxmox_router::list_subdirs_api_method;
use proxmox_router::{Permission, Router, RpcEnvironment, SubdirMap};
use proxmox_schema::api;
use pbs_api_types::PROXMOX_CONFIG_DIGEST_SCHEMA; use pbs_api_types::PROXMOX_CONFIG_DIGEST_SCHEMA;
@ -47,6 +48,15 @@ pub fn get_webauthn_config(
Ok(Some(config)) Ok(Some(config))
} }
#[api()]
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
/// Deletable property name
pub enum DeletableProperty {
/// Delete the origin property.
Origin,
}
#[api( #[api(
protected: true, protected: true,
input: { input: {
@ -55,6 +65,14 @@ pub fn get_webauthn_config(
flatten: true, flatten: true,
type: WebauthnConfigUpdater, type: WebauthnConfigUpdater,
}, },
delete: {
description: "List of properties to delete.",
type: Array,
optional: true,
items: {
type: DeletableProperty,
}
},
digest: { digest: {
optional: true, optional: true,
schema: PROXMOX_CONFIG_DIGEST_SCHEMA, schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
@ -65,6 +83,7 @@ pub fn get_webauthn_config(
/// Update the TFA configuration. /// Update the TFA configuration.
pub fn update_webauthn_config( pub fn update_webauthn_config(
webauthn: WebauthnConfigUpdater, webauthn: WebauthnConfigUpdater,
delete: Option<Vec<DeletableProperty>>,
digest: Option<String>, digest: Option<String>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let _lock = tfa::write_lock(); let _lock = tfa::write_lock();
@ -79,13 +98,34 @@ pub fn update_webauthn_config(
&crate::config::tfa::webauthn_config_digest(&wa)?, &crate::config::tfa::webauthn_config_digest(&wa)?,
)?; )?;
} }
if let Some(ref rp) = webauthn.rp { wa.rp = rp.clone(); }
if let Some(ref origin) = webauthn.origin { wa.origin = origin.clone(); } if let Some(delete) = delete {
if let Some(ref id) = webauthn.id { wa.id = id.clone(); } for delete in delete {
match delete {
DeletableProperty::Origin => {
wa.origin = None;
}
}
}
}
if let Some(rp) = webauthn.rp {
wa.rp = rp;
}
if webauthn.origin.is_some() {
wa.origin = webauthn.origin;
}
if let Some(id) = webauthn.id {
wa.id = id;
}
} else { } else {
let rp = webauthn.rp.unwrap(); let rp = webauthn
let origin = webauthn.origin.unwrap(); .rp
let id = webauthn.id.unwrap(); .ok_or_else(|| format_err!("missing proeprty: 'rp'"))?;
let origin = webauthn.origin;
let id = webauthn
.id
.ok_or_else(|| format_err!("missing property: 'id'"))?;
tfa.webauthn = Some(WebauthnConfig { rp, origin, id }); tfa.webauthn = Some(WebauthnConfig { rp, origin, id });
} }

View File

@ -127,7 +127,7 @@ impl TfaUserChallengeData {
/// Get an optional TFA challenge for a user. /// Get an optional TFA challenge for a user.
pub fn login_challenge(userid: &Userid) -> Result<Option<TfaChallenge>, Error> { pub fn login_challenge(userid: &Userid) -> Result<Option<TfaChallenge>, Error> {
let _lock = write_lock()?; let _lock = write_lock()?;
read()?.authentication_challenge(UserAccess, userid.as_str()) read()?.authentication_challenge(UserAccess, userid.as_str(), None)
} }
/// Add a TOTP entry for a user. Returns the ID. /// Add a TOTP entry for a user. Returns the ID.
@ -176,7 +176,7 @@ pub fn add_webauthn_registration(userid: &Userid, description: String) -> Result
let _lock = crate::config::tfa::write_lock(); let _lock = crate::config::tfa::write_lock();
let mut data = read()?; let mut data = read()?;
let challenge = let challenge =
data.webauthn_registration_challenge(UserAccess, userid.as_str(), description)?; data.webauthn_registration_challenge(UserAccess, userid.as_str(), description, None)?;
write(&data)?; write(&data)?;
Ok(challenge) Ok(challenge)
} }
@ -189,7 +189,8 @@ pub fn finish_webauthn_registration(
) -> Result<String, Error> { ) -> Result<String, Error> {
let _lock = crate::config::tfa::write_lock(); let _lock = crate::config::tfa::write_lock();
let mut data = read()?; let mut data = read()?;
let id = data.webauthn_registration_finish(UserAccess, userid.as_str(), challenge, response)?; let id =
data.webauthn_registration_finish(UserAccess, userid.as_str(), challenge, response, None)?;
write(&data)?; write(&data)?;
Ok(id) Ok(id)
} }
@ -203,7 +204,7 @@ pub fn verify_challenge(
let _lock = crate::config::tfa::write_lock(); let _lock = crate::config::tfa::write_lock();
let mut data = read()?; let mut data = read()?;
if data if data
.verify(UserAccess, userid.as_str(), challenge, response)? .verify(UserAccess, userid.as_str(), challenge, response, None)?
.needs_saving() .needs_saving()
{ {
write(&data)?; write(&data)?;
@ -261,11 +262,10 @@ impl proxmox_tfa::api::OpenUserChallengeData for UserAccess {
Err(err) => { Err(err) => {
eprintln!( eprintln!(
"failed to parse challenge data for user {}: {}", "failed to parse challenge data for user {}: {}",
userid, userid, err
err
); );
Default::default() Default::default()
}, }
} }
}; };