Merge factors type for authentication
This commit is contained in:
@@ -3,10 +3,15 @@ use std::sync::Arc;
|
||||
|
||||
use actix_web::web;
|
||||
use uuid::Uuid;
|
||||
use webauthn_rs::prelude::{
|
||||
CreationChallengeResponse, Passkey, PublicKeyCredential, RegisterPublicKeyCredential,
|
||||
RequestChallengeResponse,
|
||||
};
|
||||
use webauthn_rs::{Webauthn, WebauthnBuilder};
|
||||
use webauthn_rs::prelude::{CreationChallengeResponse, Passkey, PublicKeyCredential, RegisterPublicKeyCredential, RequestChallengeResponse};
|
||||
|
||||
use crate::constants::{APP_NAME, WEBAUTHN_LOGIN_CHALLENGE_EXPIRE, WEBAUTHN_REGISTER_CHALLENGE_EXPIRE};
|
||||
use crate::constants::{
|
||||
APP_NAME, WEBAUTHN_LOGIN_CHALLENGE_EXPIRE, WEBAUTHN_REGISTER_CHALLENGE_EXPIRE,
|
||||
};
|
||||
use crate::data::app_config::AppConfig;
|
||||
use crate::data::crypto_wrapper::CryptoWrapper;
|
||||
use crate::data::user::{User, UserID};
|
||||
@@ -42,7 +47,6 @@ struct AuthStateOpaqueData {
|
||||
expire: u64,
|
||||
}
|
||||
|
||||
|
||||
pub type WebAuthManagerReq = web::Data<Arc<WebAuthManager>>;
|
||||
|
||||
pub struct WebAuthManager {
|
||||
@@ -54,24 +58,23 @@ impl WebAuthManager {
|
||||
pub fn init(conf: &AppConfig) -> Self {
|
||||
Self {
|
||||
core: WebauthnBuilder::new(
|
||||
conf.domain_name().split_once(':')
|
||||
conf.domain_name()
|
||||
.split_once(':')
|
||||
.map(|s| s.0)
|
||||
.unwrap_or_else(|| conf.domain_name()),
|
||||
&url::Url::parse(&conf.website_origin)
|
||||
.expect("Failed to parse configuration origin!"))
|
||||
.expect("Invalid Webauthn configuration")
|
||||
.rp_name(APP_NAME)
|
||||
.build()
|
||||
.expect("Failed to build webauthn")
|
||||
|
||||
,
|
||||
.expect("Failed to parse configuration origin!"),
|
||||
)
|
||||
.expect("Invalid Webauthn configuration")
|
||||
.rp_name(APP_NAME)
|
||||
.build()
|
||||
.expect("Failed to build webauthn"),
|
||||
crypto_wrapper: CryptoWrapper::new_random(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_register(&self, user: &User) -> Res<RegisterKeyRequest> {
|
||||
let (creation_challenge, registration_state)
|
||||
= self.core.start_passkey_registration(
|
||||
let (creation_challenge, registration_state) = self.core.start_passkey_registration(
|
||||
Uuid::parse_str(&user.uid.0).expect("Failed to parse user id"),
|
||||
&user.username,
|
||||
&user.full_name(),
|
||||
@@ -88,29 +91,43 @@ impl WebAuthManager {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn finish_registration(&self, user: &User, opaque_state: &str,
|
||||
pub_cred: RegisterPublicKeyCredential) -> Res<WebauthnPubKey> {
|
||||
pub fn finish_registration(
|
||||
&self,
|
||||
user: &User,
|
||||
opaque_state: &str,
|
||||
pub_cred: RegisterPublicKeyCredential,
|
||||
) -> Res<WebauthnPubKey> {
|
||||
let state: RegisterKeyOpaqueData = self.crypto_wrapper.decrypt(opaque_state)?;
|
||||
if state.user_id != user.uid {
|
||||
return Err(Box::new(
|
||||
std::io::Error::new(ErrorKind::Other, "Invalid user for pubkey!")));
|
||||
return Err(Box::new(std::io::Error::new(
|
||||
ErrorKind::Other,
|
||||
"Invalid user for pubkey!",
|
||||
)));
|
||||
}
|
||||
|
||||
if state.expire < time() {
|
||||
return Err(Box::new(
|
||||
std::io::Error::new(ErrorKind::Other, "Challenge has expired!")));
|
||||
return Err(Box::new(std::io::Error::new(
|
||||
ErrorKind::Other,
|
||||
"Challenge has expired!",
|
||||
)));
|
||||
}
|
||||
|
||||
let res = self.core
|
||||
.finish_passkey_registration(&pub_cred, &serde_json::from_str(&state.registration_state)?)?;
|
||||
let res = self.core.finish_passkey_registration(
|
||||
&pub_cred,
|
||||
&serde_json::from_str(&state.registration_state)?,
|
||||
)?;
|
||||
|
||||
Ok(WebauthnPubKey { creds: res })
|
||||
}
|
||||
|
||||
pub fn start_authentication(&self, user_id: &UserID, key: &WebauthnPubKey) -> Res<AuthRequest> {
|
||||
let (login_challenge, authentication_state) = self.core.start_passkey_authentication(&vec![
|
||||
key.creds.clone()
|
||||
])?;
|
||||
pub fn start_authentication(
|
||||
&self,
|
||||
user_id: &UserID,
|
||||
keys: &[WebauthnPubKey],
|
||||
) -> Res<AuthRequest> {
|
||||
let (login_challenge, authentication_state) = self.core.start_passkey_authentication(
|
||||
&keys.iter().map(|k| k.creds.clone()).collect::<Vec<_>>(),
|
||||
)?;
|
||||
|
||||
Ok(AuthRequest {
|
||||
opaque_state: self.crypto_wrapper.encrypt(&AuthStateOpaqueData {
|
||||
@@ -122,22 +139,32 @@ impl WebAuthManager {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn finish_authentication(&self, user_id: &UserID, opaque_state: &str,
|
||||
pub_cred: &PublicKeyCredential) -> Res {
|
||||
pub fn finish_authentication(
|
||||
&self,
|
||||
user_id: &UserID,
|
||||
opaque_state: &str,
|
||||
pub_cred: &PublicKeyCredential,
|
||||
) -> Res {
|
||||
let state: AuthStateOpaqueData = self.crypto_wrapper.decrypt(opaque_state)?;
|
||||
if &state.user_id != user_id {
|
||||
return Err(Box::new(
|
||||
std::io::Error::new(ErrorKind::Other, "Invalid user for pubkey!")));
|
||||
return Err(Box::new(std::io::Error::new(
|
||||
ErrorKind::Other,
|
||||
"Invalid user for pubkey!",
|
||||
)));
|
||||
}
|
||||
|
||||
if state.expire < time() {
|
||||
return Err(Box::new(
|
||||
std::io::Error::new(ErrorKind::Other, "Challenge has expired!")));
|
||||
return Err(Box::new(std::io::Error::new(
|
||||
ErrorKind::Other,
|
||||
"Challenge has expired!",
|
||||
)));
|
||||
}
|
||||
|
||||
self.core.finish_passkey_authentication(pub_cred,
|
||||
&serde_json::from_str(&state.authentication_state)?)?;
|
||||
self.core.finish_passkey_authentication(
|
||||
pub_cred,
|
||||
&serde_json::from_str(&state.authentication_state)?,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user