From 8ce3e81123d7421701dbc14e8a94093ed3c5fe93 Mon Sep 17 00:00:00 2001 From: Firstyear Date: Mon, 20 Feb 2023 17:50:49 +1000 Subject: [PATCH] 20230220 passkey cleanup (#1396) * Migrate from cred to passkey * Start to cleanup for removal of the legacy passkey type --- kanidmd/lib/src/constants/entries.rs | 2 +- kanidmd/lib/src/credential/mod.rs | 10 ------ kanidmd/lib/src/idm/authsession.rs | 3 +- kanidmd/lib/src/server/migrations.rs | 53 ++++++++++++++++++++++++++++ profiles/src/lib.rs | 4 ++- 5 files changed, 58 insertions(+), 14 deletions(-) diff --git a/kanidmd/lib/src/constants/entries.rs b/kanidmd/lib/src/constants/entries.rs index 10de463ee..e6785f695 100644 --- a/kanidmd/lib/src/constants/entries.rs +++ b/kanidmd/lib/src/constants/entries.rs @@ -565,7 +565,7 @@ pub const JSON_SYSTEM_INFO_V1: &str = r#"{ "class": ["object", "system_info", "system"], "uuid": ["00000000-0000-0000-0000-ffffff000001"], "description": ["System (local) info and metadata object."], - "version": ["10"] + "version": ["11"] } }"#; diff --git a/kanidmd/lib/src/credential/mod.rs b/kanidmd/lib/src/credential/mod.rs index 20311717a..4b97d4a77 100644 --- a/kanidmd/lib/src/credential/mod.rs +++ b/kanidmd/lib/src/credential/mod.rs @@ -918,16 +918,6 @@ impl Credential { Password::new(policy, cleartext).map(Self::new_from_generatedpassword) } - /// Create a new credential that contains a CredentialType::Webauthn - pub fn new_passkey_only(label: String, cred: Passkey) -> Self { - let mut webauthn_map = Map::new(); - webauthn_map.insert(label, cred); - Credential { - type_: CredentialType::Webauthn(webauthn_map), - uuid: Uuid::new_v4(), - } - } - /// Update the state of the Password on this credential, if a password is present. If possible /// this will convert the credential to a PasswordMFA in some cases, or fail in others. pub fn set_password( diff --git a/kanidmd/lib/src/idm/authsession.rs b/kanidmd/lib/src/idm/authsession.rs index 4b78f55a2..5cc6deb51 100644 --- a/kanidmd/lib/src/idm/authsession.rs +++ b/kanidmd/lib/src/idm/authsession.rs @@ -1584,8 +1584,7 @@ mod tests { let jws_signer = create_jwt_signer(); // Now create the credential for the account. - let cred = Credential::new_passkey_only("soft".to_string(), wan_cred); - account.primary = Some(cred); + account.passkeys = btreemap![(Uuid::new_v4(), ("soft".to_string(), wan_cred))]; // now check correct mech was offered. diff --git a/kanidmd/lib/src/server/migrations.rs b/kanidmd/lib/src/server/migrations.rs index 8f4edf48b..b8852c688 100644 --- a/kanidmd/lib/src/server/migrations.rs +++ b/kanidmd/lib/src/server/migrations.rs @@ -92,6 +92,10 @@ impl QueryServer { if system_info_version < 10 { migrate_txn.migrate_9_to_10()?; } + + if system_info_version < 11 { + migrate_txn.migrate_10_to_11()?; + } } migrate_txn.commit()?; @@ -279,6 +283,55 @@ impl<'a> QueryServerWriteTransaction<'a> { // Complete } + /// Migrate 10 to 11 + /// + /// This forces a load of all credentials, and then examines if any are "passkey" capable. If they + /// are, they are migrated to the passkey type, allowing us to deprecate and remove the older + /// credential behaviour. + /// + #[instrument(level = "debug", skip_all)] + pub fn migrate_10_to_11(&mut self) -> Result<(), OperationError> { + admin_warn!("starting 9 to 10 migration."); + let filter = filter!(f_pres("primary_credential")); + + let pre_candidates = self.internal_search(filter).map_err(|e| { + admin_error!(err = ?e, "migrate_10_to_11 internal search failure"); + e + })?; + + // First, filter based on if any credentials present actually are the legacy + // webauthn type. + let modset: Vec<_> = pre_candidates + .into_iter() + .filter_map(|ent| { + ent.get_ava_single_credential("primary_credential") + .and_then(|cred| cred.passkey_ref().ok()) + .map(|pk_map| { + let modlist = pk_map + .iter() + .map(|(t, k)| { + Modify::Present( + "passkeys".into(), + Value::Passkey(Uuid::new_v4(), t.clone(), k.clone()), + ) + }) + .chain(std::iter::once(m_purge("primary_credential"))) + .collect(); + (ent.get_uuid(), ModifyList::new_list(modlist)) + }) + }) + .collect(); + + // If there is nothing, we don't need to do anything. + if modset.is_empty() { + admin_info!("migrate_10_to_11 no entries to migrate, complete"); + return Ok(()); + } + + // Apply the batch mod. + self.internal_batch_modify(modset.into_iter()) + } + #[instrument(level = "info", skip_all)] pub fn initialise_schema_core(&mut self) -> Result<(), OperationError> { admin_debug!("initialise_schema_core -> start ..."); diff --git a/profiles/src/lib.rs b/profiles/src/lib.rs index 9584b1dd2..ed8d30405 100644 --- a/profiles/src/lib.rs +++ b/profiles/src/lib.rs @@ -61,7 +61,9 @@ pub fn apply_profile() { match profile_cfg.cpu_flags { CpuOptLevel::none => {} CpuOptLevel::native => println!("cargo:rustc-env=RUSTFLAGS=-Ctarget-cpu=native"), - CpuOptLevel::neon_v8 => println!("cargo:rustc-env=RUSTFLAGS=-Ctarget-features=+neon,+fp-armv8"), + CpuOptLevel::neon_v8 => { + println!("cargo:rustc-env=RUSTFLAGS=-Ctarget-features=+neon,+fp-armv8") + } CpuOptLevel::x86_64_v2 => println!("cargo:rustc-env=RUSTFLAGS=-Ctarget-cpu=x86-64-v2"), CpuOptLevel::x86_64_v3 => println!("cargo:rustc-env=RUSTFLAGS=-Ctarget-cpu=x86-64-v3"), }