From 4e5c2d93d42d1d856e429707c408c936f3a3474a Mon Sep 17 00:00:00 2001 From: Rene Leveille Date: Mon, 8 Jul 2024 11:58:37 -0400 Subject: [PATCH] feat: Add quirky rps workaround This adds functionality to the client to prevent sending valid responses that would otherwise fail validation or serialization on the RP's server. --- CHANGELOG.md | 2 ++ passkey-client/src/lib.rs | 7 +++- passkey-client/src/quirks.rs | 64 ++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 passkey-client/src/quirks.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 49cb38d..696756d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ - Changed: The `Client` no longer hardcodes the UV value sent to the `Authenticator` ([#22](https://github.com/1Password/passkey-rs/pull/22)). - Changed: The `Client` no longer hardcodes the RK value sent to the `Authenticator` ([#27](https://github.com/1Password/passkey-rs/pull/27)). +- Added: The `Client` now has the ability to adjust the response for quirky relying parties + when a fully featured response would break their server side validation. ([#31](https://github.com/1Password/passkey-rs/pull/31)) ## Passkey v0.2.0 ### passkey-types v0.2.0 diff --git a/passkey-client/src/lib.rs b/passkey-client/src/lib.rs index 42d7640..5aba99e 100644 --- a/passkey-client/src/lib.rs +++ b/passkey-client/src/lib.rs @@ -31,6 +31,9 @@ use passkey_types::{ use typeshare::typeshare; use url::Url; +mod quirks; +use quirks::QuirkyRp; + #[cfg(test)] mod tests; @@ -287,7 +290,9 @@ where client_extension_results: AuthenticatorExtensionsClientOutputs { cred_props }, }; - Ok(response) + // Sanitize output before sending it back to the RP + let maybe_quirky_rp = QuirkyRp::from_rp_id(rp_id); + Ok(maybe_quirky_rp.map_create_credential(response)) } /// Authenticate a Webauthn request. diff --git a/passkey-client/src/quirks.rs b/passkey-client/src/quirks.rs new file mode 100644 index 0000000..2950263 --- /dev/null +++ b/passkey-client/src/quirks.rs @@ -0,0 +1,64 @@ +//! The goal of this module is to address quirks with RP's different implementations. +//! We don't want to limit this library's functionality for all RPs because of only +//! a few RPs misbehave. + +use passkey_types::webauthn::CreatedPublicKeyCredential; + +/// List of quirky RPs, the default is [`Self::NotQuirky`] which maps to being a no-op +#[derive(Default)] +pub(crate) enum QuirkyRp { + /// The RP is not known to be quirky, thus the mapping methods will be no-ops. + #[default] + NotQuirky, + + /// Adobe crashes on their server when they encounter the key + /// [credProps.authenticatorDisplayName][adn] during key creation. + /// + /// RP_IDs: + /// * `adobe.com` + /// + /// [adn]: https://w3c.github.io/webauthn/#dom-credentialpropertiesoutput-authenticatordisplayname + Adobe, + + /// Hyatt returns an "invalid request" error when they encounter the key + /// [credProps.authenticatorDisplayName][adn] during key creation. + /// + /// RP_IDs: + /// * `hyatt.com` + /// + /// [adn]: https://w3c.github.io/webauthn/#dom-credentialpropertiesoutput-authenticatordisplayname + Hyatt, +} + +impl QuirkyRp { + pub fn from_rp_id(rp_id: &str) -> Self { + match rp_id { + "adobe.com" => QuirkyRp::Adobe, + "hyatt.com" => QuirkyRp::Hyatt, + _ => QuirkyRp::NotQuirky, + } + } + + /// Use this after creating the response but before returning it to the function caller + #[inline] + pub fn map_create_credential( + &self, + response: CreatedPublicKeyCredential, + ) -> CreatedPublicKeyCredential { + match self { + // no-op + Self::NotQuirky => response, + Self::Adobe | Self::Hyatt => remove_authenticator_display_name(response), + } + } +} + +#[inline] +fn remove_authenticator_display_name( + mut response: CreatedPublicKeyCredential, +) -> CreatedPublicKeyCredential { + if let Some(cp) = response.client_extension_results.cred_props.as_mut() { + cp.authenticator_display_name = None; + } + response +}