webauthn.rs (35323B)
1 use crate::{ 2 api::{EmptyResult, JsonResult, PasswordOrOtpData}, 3 auth::{self, Headers}, 4 config, 5 db::{ 6 models::{WebAuthn, WebAuthnInfo}, 7 DbConn, 8 }, 9 error::Error, 10 }; 11 use data_encoding::{BASE64, BASE64URL_NOPAD}; 12 use rocket::serde::json::Json; 13 use rocket::Route; 14 use serde::de::{Deserialize, Deserializer, Error as SerdeErr, MapAccess, Unexpected, Visitor}; 15 use std::fmt::{self, Formatter}; 16 use uuid::Uuid; 17 use webauthn_rp::{ 18 request::{ 19 auth::PublicKeyCredentialRequestOptions, 20 register::{ 21 Nickname, PublicKeyCredentialCreationOptions, PublicKeyCredentialUserEntity, 22 UserHandle, Username, 23 }, 24 InsertResult, 25 }, 26 response::{ 27 auth::Authentication, 28 register::{AuthenticatorAttestation, Registration}, 29 AuthTransports, AuthenticatorAttachment, CollectedClientData, CredentialId, 30 }, 31 AggErr, 32 }; 33 34 pub fn routes() -> Vec<Route> { 35 routes![ 36 activate_webauthn, 37 activate_webauthn_put, 38 delete_webauthn, 39 generate_webauthn_challenge, 40 get_webauthn, 41 ] 42 } 43 #[post("/two-factor/get-webauthn", data = "<data>")] 44 async fn get_webauthn(data: Json<PasswordOrOtpData>, headers: Headers, conn: DbConn) -> JsonResult { 45 let data: PasswordOrOtpData = data.into_inner(); 46 let user = headers.user; 47 data.validate(&user)?; 48 let keys = WebAuthnInfo::get_all_by_user(&user.uuid, &conn).await?; 49 Ok(Json(json!({ 50 "enabled": !keys.is_empty(), 51 "keys": keys, 52 "object": "twoFactorWebAuthn" 53 }))) 54 } 55 #[post("/two-factor/get-webauthn-challenge", data = "<data>")] 56 async fn generate_webauthn_challenge( 57 data: Json<PasswordOrOtpData>, 58 headers: Headers, 59 conn: DbConn, 60 ) -> JsonResult { 61 let data: PasswordOrOtpData = data.into_inner(); 62 let user = headers.user; 63 data.validate(&user)?; 64 let name = Username::try_from(user.email.as_str()).map_err(AggErr::Username)?; 65 let uuid = Uuid::parse_str(user.uuid.as_str()) 66 .map_err(|e| Error::from(e.to_string()))? 67 .into_bytes(); 68 let id = UserHandle::try_from(uuid.as_slice()).map_err(AggErr::UserHandle)?; 69 let display_name = Some(Nickname::try_from(user.name.as_str()).map_err(AggErr::Nickname)?); 70 let (server, client) = PublicKeyCredentialCreationOptions::second_factor( 71 &config::get_config().rp_id, 72 PublicKeyCredentialUserEntity { 73 name, 74 id, 75 display_name, 76 }, 77 WebAuthn::get_registered_creds(user.uuid.as_str(), &conn).await?, 78 ) 79 .start_ceremony() 80 .map_err(AggErr::CreationOptions)?; 81 match auth::get_reg_ceremonies().insert_or_replace_all_expired(server) { 82 InsertResult::Success => { 83 let mut challenge_value = serde_json::to_value(client)?; 84 challenge_value["status"] = "ok".into(); 85 challenge_value["errorMessage"] = "".into(); 86 Ok(Json(challenge_value)) 87 } 88 InsertResult::CapacityFull => Err(Error::from(String::from( 89 "too many active ceremonies. try again later", 90 ))), 91 InsertResult::Duplicate => Err(Error::from(String::from("duplicate webauthn challenge"))), 92 } 93 } 94 struct Type; 95 impl<'e> Deserialize<'e> for Type { 96 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 97 where 98 D: Deserializer<'e>, 99 { 100 struct TypeVisitor; 101 impl<'f> Visitor<'f> for TypeVisitor { 102 type Value = Type; 103 fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { 104 formatter.write_str("public-key") 105 } 106 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> 107 where 108 E: SerdeErr, 109 { 110 if v == "public-key" { 111 Ok(Type) 112 } else { 113 Err(E::invalid_value(Unexpected::Str(v), &"public-key")) 114 } 115 } 116 } 117 deserializer.deserialize_str(TypeVisitor) 118 } 119 } 120 struct RegistrationWrapper(Registration); 121 impl<'de> Deserialize<'de> for RegistrationWrapper { 122 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 123 where 124 D: Deserializer<'de>, 125 { 126 struct RegistrationVisitor; 127 impl<'d> Visitor<'d> for RegistrationVisitor { 128 type Value = RegistrationWrapper; 129 fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { 130 formatter.write_str("RegistrationWrapper") 131 } 132 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error> 133 where 134 A: MapAccess<'d>, 135 { 136 enum Field { 137 Id, 138 RawId, 139 Response, 140 Extensions, 141 Type, 142 } 143 impl<'e> Deserialize<'e> for Field { 144 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 145 where 146 D: Deserializer<'e>, 147 { 148 struct FieldVisitor; 149 impl<'f> Visitor<'f> for FieldVisitor { 150 type Value = Field; 151 fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { 152 write!( 153 formatter, 154 "'{ID}', '{RAW_ID}', '{RESPONSE}', '{EXTENSIONS}', or '{TYPE}'" 155 ) 156 } 157 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> 158 where 159 E: SerdeErr, 160 { 161 match v { 162 ID => Ok(Field::Id), 163 RAW_ID => Ok(Field::RawId), 164 RESPONSE => Ok(Field::Response), 165 EXTENSIONS => Ok(Field::Extensions), 166 TYPE => Ok(Field::Type), 167 _ => Err(E::unknown_field(v, FIELDS)), 168 } 169 } 170 } 171 deserializer.deserialize_identifier(FieldVisitor) 172 } 173 } 174 struct RawId(CredentialId<Vec<u8>>); 175 impl<'e> Deserialize<'e> for RawId { 176 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 177 where 178 D: Deserializer<'e>, 179 { 180 struct RawIdVisitor; 181 impl<'f> Visitor<'f> for RawIdVisitor { 182 type Value = RawId; 183 fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { 184 formatter.write_str("RawId") 185 } 186 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> 187 where 188 E: SerdeErr, 189 { 190 BASE64.decode(v.as_bytes()).map_err(E::custom).and_then( 191 |base64url| { 192 BASE64URL_NOPAD 193 .decode(base64url.as_slice()) 194 .map_err(E::custom) 195 .and_then(|cred_id| { 196 CredentialId::try_from(cred_id) 197 .map_err(E::custom) 198 .map(RawId) 199 }) 200 }, 201 ) 202 } 203 } 204 deserializer.deserialize_str(RawIdVisitor) 205 } 206 } 207 struct AuthAttestWrapper(AuthenticatorAttestation); 208 impl<'e> Deserialize<'e> for AuthAttestWrapper { 209 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 210 where 211 D: Deserializer<'e>, 212 { 213 struct AuthAttestVisitor; 214 impl<'f> Visitor<'f> for AuthAttestVisitor { 215 type Value = AuthAttestWrapper; 216 fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { 217 formatter.write_str("AuthAttestWrapper") 218 } 219 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error> 220 where 221 A: MapAccess<'f>, 222 { 223 enum AuthField { 224 AttestationObject, 225 ClientDataJson, 226 } 227 impl<'g> Deserialize<'g> for AuthField { 228 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 229 where 230 D: Deserializer<'g>, 231 { 232 struct AuthFieldVisitor; 233 impl<'h> Visitor<'h> for AuthFieldVisitor { 234 type Value = AuthField; 235 fn expecting( 236 &self, 237 formatter: &mut Formatter<'_>, 238 ) -> fmt::Result 239 { 240 write!(formatter, "'{ATTESTATION_OBJECT}' or '{CLIENT_DATA_JSON}'") 241 } 242 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> 243 where 244 E: SerdeErr, 245 { 246 match v { 247 ATTESTATION_OBJECT => { 248 Ok(AuthField::AttestationObject) 249 } 250 CLIENT_DATA_JSON => { 251 Ok(AuthField::ClientDataJson) 252 } 253 _ => Err(E::unknown_field(v, AUTH_FIELDS)), 254 } 255 } 256 } 257 deserializer.deserialize_identifier(AuthFieldVisitor) 258 } 259 } 260 struct Base64(Vec<u8>); 261 impl<'g> Deserialize<'g> for Base64 { 262 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 263 where 264 D: Deserializer<'g>, 265 { 266 struct Base64Visitor; 267 impl<'h> Visitor<'h> for Base64Visitor { 268 type Value = Base64; 269 fn expecting( 270 &self, 271 formatter: &mut Formatter<'_>, 272 ) -> fmt::Result 273 { 274 formatter.write_str("base64-encoded value") 275 } 276 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> 277 where 278 E: SerdeErr, 279 { 280 BASE64 281 .decode(v.as_bytes()) 282 .map_err(E::custom) 283 .map(Base64) 284 } 285 } 286 deserializer.deserialize_str(Base64Visitor) 287 } 288 } 289 let mut att_obj = None; 290 let mut client_data = None; 291 while let Some(key) = map.next_key()? { 292 match key { 293 AuthField::AttestationObject => { 294 if att_obj.is_some() { 295 return Err(SerdeErr::duplicate_field( 296 ATTESTATION_OBJECT, 297 )); 298 } 299 att_obj = map 300 .next_value::<Base64>() 301 .map(|base64| Some(base64.0))?; 302 } 303 AuthField::ClientDataJson => { 304 if client_data.is_some() { 305 return Err(SerdeErr::duplicate_field( 306 CLIENT_DATA_JSON, 307 )); 308 } 309 client_data = map 310 .next_value::<Base64>() 311 .map(|base64| Some(base64.0))?; 312 } 313 } 314 } 315 att_obj 316 .ok_or_else(|| SerdeErr::missing_field(ATTESTATION_OBJECT)) 317 .and_then(|attestation_object| { 318 client_data 319 .ok_or_else(|| { 320 SerdeErr::missing_field(CLIENT_DATA_JSON) 321 }) 322 .map(|client_data_json| { 323 AuthAttestWrapper(AuthenticatorAttestation::new( 324 client_data_json, 325 attestation_object, 326 AuthTransports::NONE, 327 )) 328 }) 329 }) 330 } 331 } 332 const ATTESTATION_OBJECT: &str = "attestationObject"; 333 const CLIENT_DATA_JSON: &str = "clientDataJSON"; 334 const AUTH_FIELDS: &[&str; 2] = &[ATTESTATION_OBJECT, CLIENT_DATA_JSON]; 335 deserializer.deserialize_struct( 336 "AuthAttestWrapper", 337 AUTH_FIELDS, 338 AuthAttestVisitor, 339 ) 340 } 341 } 342 let mut id = None; 343 let mut raw_id = None; 344 let mut response = None; 345 let mut extensions = None; 346 let mut typ = false; 347 while let Some(key) = map.next_key()? { 348 match key { 349 Field::Id => { 350 if id.is_some() { 351 return Err(SerdeErr::duplicate_field(ID)); 352 } 353 id = map.next_value::<CredentialId<Vec<u8>>>().map(Some)?; 354 } 355 Field::RawId => { 356 if raw_id.is_some() { 357 return Err(SerdeErr::duplicate_field(RAW_ID)); 358 } 359 raw_id = map.next_value::<RawId>().map(Some)?; 360 } 361 Field::Response => { 362 if response.is_some() { 363 return Err(SerdeErr::duplicate_field(RESPONSE)); 364 } 365 response = map 366 .next_value::<AuthAttestWrapper>() 367 .map(|attest| Some(attest.0))?; 368 } 369 Field::Extensions => { 370 if extensions.is_some() { 371 return Err(SerdeErr::duplicate_field(EXTENSIONS)); 372 } 373 extensions = map.next_value().map(Some)?; 374 } 375 Field::Type => { 376 if typ { 377 return Err(SerdeErr::duplicate_field(TYPE)); 378 } 379 typ = map.next_value::<Type>().map(|_| true)?; 380 } 381 } 382 } 383 id.ok_or_else(|| SerdeErr::missing_field(ID)).and_then(|i| { 384 raw_id 385 .ok_or_else(|| SerdeErr::missing_field(RAW_ID)) 386 .and_then(|r| { 387 if i == r.0 { 388 response 389 .ok_or_else(|| SerdeErr::missing_field(RESPONSE)) 390 .and_then(|resp| { 391 extensions 392 .ok_or_else(|| SerdeErr::missing_field(EXTENSIONS)) 393 .and_then(|ext| { 394 if typ { 395 Ok(RegistrationWrapper(Registration::new( 396 resp, 397 AuthenticatorAttachment::None, 398 ext, 399 ))) 400 } else { 401 Err(SerdeErr::missing_field(TYPE)) 402 } 403 }) 404 }) 405 } else { 406 Err(SerdeErr::invalid_value( 407 Unexpected::Bytes(r.0.as_ref()), 408 &format!("id: {:?} to match rawId", i.as_ref()).as_str(), 409 )) 410 } 411 }) 412 }) 413 } 414 } 415 const ID: &str = "id"; 416 const RAW_ID: &str = "rawId"; 417 const RESPONSE: &str = "response"; 418 const EXTENSIONS: &str = "extensions"; 419 const TYPE: &str = "type"; 420 const FIELDS: &[&str; 5] = &[ID, RAW_ID, RESPONSE, EXTENSIONS, TYPE]; 421 deserializer.deserialize_struct("RegistrationWrapper", FIELDS, RegistrationVisitor) 422 } 423 } 424 425 #[derive(Deserialize)] 426 #[serde(rename_all = "camelCase")] 427 struct EnableWebauthnData { 428 id: i64, 429 name: String, 430 device_response: RegistrationWrapper, 431 master_password_hash: String, 432 } 433 434 #[post("/two-factor/webauthn", data = "<data>")] 435 async fn activate_webauthn( 436 data: Json<EnableWebauthnData>, 437 headers: Headers, 438 conn: DbConn, 439 ) -> JsonResult { 440 let data = data.into_inner(); 441 let user = headers.user; 442 PasswordOrOtpData { 443 master_password_hash: Some(data.master_password_hash), 444 otp: None, 445 } 446 .validate(&user)?; 447 let uuid = Uuid::parse_str(user.uuid.as_str()) 448 .map_err(|e| Error::from(e.to_string()))? 449 .into_bytes(); 450 let user_handle = UserHandle::try_from(uuid.as_slice()).map_err(AggErr::UserHandle)?; 451 let cred = auth::get_reg_ceremonies() 452 .take( 453 &CollectedClientData::from_client_data_json_relaxed::<true>( 454 data.device_response.0.response().client_data_json(), 455 ) 456 .map_err(AggErr::SerdeJson)? 457 .challenge, 458 ) 459 .ok_or_else(|| Error::from(String::from("missing registration challenge")))? 460 .verify( 461 &config::get_config().rp_id, 462 user_handle, 463 &data.device_response.0, 464 auth::get_reg_options(), 465 ) 466 .map_err(AggErr::RegCeremony)?; 467 WebAuthn::new(&cred, user.uuid.clone(), data.id, data.name)? 468 .insert(&conn) 469 .await?; 470 let keys = WebAuthnInfo::get_all_by_user(user.uuid.as_str(), &conn).await?; 471 Ok(Json(json!({ 472 "enabled": !keys.is_empty(), 473 "keys": keys, 474 "object": "twoFactorWebAuthn" 475 }))) 476 } 477 478 #[put("/two-factor/webauthn", data = "<data>")] 479 async fn activate_webauthn_put( 480 data: Json<EnableWebauthnData>, 481 headers: Headers, 482 conn: DbConn, 483 ) -> JsonResult { 484 activate_webauthn(data, headers, conn).await 485 } 486 487 #[derive(Deserialize)] 488 #[serde(rename_all = "camelCase")] 489 struct DeleteU2FData { 490 id: i64, 491 master_password_hash: String, 492 } 493 494 #[delete("/two-factor/webauthn", data = "<data>")] 495 async fn delete_webauthn(data: Json<DeleteU2FData>, headers: Headers, conn: DbConn) -> JsonResult { 496 if !headers 497 .user 498 .check_valid_password(&data.master_password_hash) 499 { 500 err!("Invalid password"); 501 } 502 WebAuthn::delete_by_user_uuid_and_id(&headers.user.uuid, data.id, &conn).await?; 503 let keys = WebAuthnInfo::get_all_by_user(&headers.user.uuid, &conn).await?; 504 Ok(Json(json!({ 505 "enabled": !keys.is_empty(), 506 "keys": keys, 507 "object": "twoFactorWebAuthn" 508 }))) 509 } 510 511 pub async fn generate_webauthn_login(user_uuid: &str, conn: &DbConn) -> JsonResult { 512 let creds = WebAuthn::get_allowed_creds(user_uuid, conn).await?; 513 let (server, client) = 514 PublicKeyCredentialRequestOptions::second_factor(&config::get_config().rp_id, creds) 515 .map_err(AggErr::SecondFactor)? 516 .start_ceremony() 517 .map_err(AggErr::RequestOptions)?; 518 match auth::get_auth_ceremonies().insert_or_replace_all_expired(server) { 519 InsertResult::Success => Ok(Json(serde_json::to_value(client)?)), 520 InsertResult::CapacityFull => Err(Error::from(String::from( 521 "too many active ceremonies. try again later", 522 ))), 523 InsertResult::Duplicate => Err(Error::from(String::from("duplicate webauthn challenge"))), 524 } 525 } 526 struct AuthenticationWrapper(Authentication); 527 impl<'de> Deserialize<'de> for AuthenticationWrapper { 528 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 529 where 530 D: Deserializer<'de>, 531 { 532 struct AuthenticationVisitor; 533 impl<'d> Visitor<'d> for AuthenticationVisitor { 534 type Value = AuthenticationWrapper; 535 fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { 536 formatter.write_str("AuthenticationWrapper") 537 } 538 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error> 539 where 540 A: MapAccess<'d>, 541 { 542 enum Field { 543 Id, 544 RawId, 545 Response, 546 Extensions, 547 Type, 548 } 549 impl<'e> Deserialize<'e> for Field { 550 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 551 where 552 D: Deserializer<'e>, 553 { 554 struct FieldVisitor; 555 impl<'f> Visitor<'f> for FieldVisitor { 556 type Value = Field; 557 fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { 558 write!( 559 formatter, 560 "'{ID}', '{RAW_ID}', '{RESPONSE}', '{EXTENSIONS}', or '{TYPE}'" 561 ) 562 } 563 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> 564 where 565 E: SerdeErr, 566 { 567 match v { 568 ID => Ok(Field::Id), 569 RAW_ID => Ok(Field::RawId), 570 RESPONSE => Ok(Field::Response), 571 EXTENSIONS => Ok(Field::Extensions), 572 TYPE => Ok(Field::Type), 573 _ => Err(E::unknown_field(v, FIELDS)), 574 } 575 } 576 } 577 deserializer.deserialize_identifier(FieldVisitor) 578 } 579 } 580 struct Extensions; 581 impl<'e> Deserialize<'e> for Extensions { 582 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 583 where 584 D: Deserializer<'e>, 585 { 586 struct ExtensionsVisitor; 587 impl<'f> Visitor<'f> for ExtensionsVisitor { 588 type Value = Extensions; 589 fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { 590 formatter.write_str("Extensions") 591 } 592 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error> 593 where 594 A: MapAccess<'f>, 595 { 596 struct Field; 597 impl<'g> Deserialize<'g> for Field { 598 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 599 where 600 D: Deserializer<'g>, 601 { 602 struct FieldVisitor; 603 impl<'h> Visitor<'h> for FieldVisitor { 604 type Value = Field; 605 fn expecting( 606 &self, 607 formatter: &mut Formatter<'_>, 608 ) -> fmt::Result 609 { 610 write!(formatter, "'{APPID}'") 611 } 612 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> 613 where 614 E: SerdeErr, 615 { 616 if v == APPID { 617 Ok(Field) 618 } else { 619 Err(E::unknown_field(v, FIELDS)) 620 } 621 } 622 } 623 deserializer.deserialize_identifier(FieldVisitor) 624 } 625 } 626 let mut appid = false; 627 while map.next_key::<Field>()?.is_some() { 628 if appid { 629 return Err(SerdeErr::duplicate_field(APPID)); 630 } 631 appid = map.next_value::<bool>().and_then(|v| { 632 if v { 633 Err(SerdeErr::invalid_value( 634 Unexpected::Bool(true), 635 &"appid to be false", 636 )) 637 } else { 638 Ok(true) 639 } 640 })?; 641 } 642 Ok(Extensions) 643 } 644 } 645 const APPID: &str = "appid"; 646 const FIELDS: &[&str; 1] = &[APPID]; 647 deserializer.deserialize_struct( 648 "EmptyExtensions", 649 FIELDS, 650 ExtensionsVisitor, 651 ) 652 } 653 } 654 let mut id = None; 655 let mut raw_id = None; 656 let mut response = None; 657 let mut extensions = false; 658 let mut typ = false; 659 while let Some(key) = map.next_key()? { 660 match key { 661 Field::Id => { 662 if id.is_some() { 663 return Err(SerdeErr::duplicate_field(ID)); 664 } 665 id = map.next_value::<CredentialId<Vec<u8>>>().map(Some)?; 666 } 667 Field::RawId => { 668 if raw_id.is_some() { 669 return Err(SerdeErr::duplicate_field(RAW_ID)); 670 } 671 raw_id = map.next_value::<CredentialId<Vec<u8>>>().map(Some)?; 672 } 673 Field::Response => { 674 if response.is_some() { 675 return Err(SerdeErr::duplicate_field(RESPONSE)); 676 } 677 response = map.next_value().map(Some)?; 678 } 679 Field::Extensions => { 680 if extensions { 681 return Err(SerdeErr::duplicate_field(EXTENSIONS)); 682 } 683 extensions = map.next_value::<Extensions>().map(|_| true)?; 684 } 685 Field::Type => { 686 if typ { 687 return Err(SerdeErr::duplicate_field(TYPE)); 688 } 689 typ = map.next_value::<Type>().map(|_| true)?; 690 } 691 } 692 } 693 id.ok_or_else(|| SerdeErr::missing_field(ID)).and_then(|i| { 694 raw_id 695 .ok_or_else(|| SerdeErr::missing_field(RAW_ID)) 696 .and_then(|r| { 697 if i == r { 698 response 699 .ok_or_else(|| SerdeErr::missing_field(RESPONSE)) 700 .and_then(|resp| { 701 if extensions { 702 if typ { 703 Ok(AuthenticationWrapper(Authentication::new( 704 r, 705 resp, 706 AuthenticatorAttachment::None, 707 ))) 708 } else { 709 Err(SerdeErr::missing_field(TYPE)) 710 } 711 } else { 712 Err(SerdeErr::missing_field(EXTENSIONS)) 713 } 714 }) 715 } else { 716 Err(SerdeErr::invalid_value( 717 Unexpected::Bytes(r.as_ref()), 718 &format!("id: {:?} to match rawId", i.as_ref()).as_str(), 719 )) 720 } 721 }) 722 }) 723 } 724 } 725 const ID: &str = "id"; 726 const RAW_ID: &str = "rawId"; 727 const RESPONSE: &str = "response"; 728 const EXTENSIONS: &str = "extensions"; 729 const TYPE: &str = "type"; 730 const FIELDS: &[&str; 5] = &[ID, RAW_ID, RESPONSE, EXTENSIONS, TYPE]; 731 deserializer.deserialize_struct("RegistrationWrapper", FIELDS, AuthenticationVisitor) 732 } 733 } 734 pub async fn validate_webauthn_login( 735 user_uuid: &str, 736 response: &str, 737 conn: &DbConn, 738 ) -> EmptyResult { 739 let auth = serde_json::from_str::<AuthenticationWrapper>(response)?.0; 740 let uuid = Uuid::parse_str(user_uuid) 741 .map_err(|e| Error::from(e.to_string()))? 742 .into_bytes(); 743 let user_handle = UserHandle::try_from(uuid.as_slice()).map_err(AggErr::UserHandle)?; 744 let mut cred = WebAuthn::get_credential(auth.raw_id(), user_uuid, user_handle, conn) 745 .await? 746 .ok_or_else(|| Error::from(String::from("credential does not exist")))?; 747 if auth::get_auth_ceremonies() 748 .take( 749 &CollectedClientData::from_client_data_json_relaxed::<false>( 750 auth.response().client_data_json(), 751 ) 752 .map_err(AggErr::SerdeJson)? 753 .challenge, 754 ) 755 .ok_or_else(|| Error::from(String::from("no authentication challenge")))? 756 .verify( 757 &config::get_config().rp_id, 758 &auth, 759 &mut cred, 760 &auth::get_auth_options(), 761 ) 762 .map_err(AggErr::AuthCeremony)? 763 { 764 WebAuthn::update(auth.raw_id(), cred.dynamic_state(), conn).await 765 } else { 766 Ok(()) 767 } 768 }