BasicOIDC/src/data/webauthn_manager.rs

100 lines
2.9 KiB
Rust
Raw Normal View History

2022-04-21 17:24:26 +00:00
use std::io::ErrorKind;
use std::sync::Arc;
use actix_web::web;
use webauthn_rs::{RegistrationState, Webauthn, WebauthnConfig};
2022-04-21 17:24:26 +00:00
use webauthn_rs::proto::{CreationChallengeResponse, Credential, RegisterPublicKeyCredential};
use crate::constants::APP_NAME;
use crate::data::app_config::AppConfig;
use crate::data::crypto_wrapper::CryptoWrapper;
use crate::data::user::{User, UserID};
use crate::utils::err::Res;
#[derive(Debug)]
struct WebAuthnAppConfig {
origin: url::Url,
relying_party_id: String,
}
impl WebauthnConfig for WebAuthnAppConfig {
fn get_relying_party_name(&self) -> &str {
APP_NAME
}
fn get_origin(&self) -> &url::Url {
&self.origin
}
fn get_relying_party_id(&self) -> &str {
&self.relying_party_id
}
}
pub struct RegisterKeyRequest {
pub opaque_state: String,
pub creation_challenge: CreationChallengeResponse,
}
2022-04-21 17:24:26 +00:00
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct WebauthnPubKey {
creds: Credential,
}
#[derive(Debug, serde::Serialize, serde::Deserialize)]
struct RegisterKeyOpaqueData {
registration_state: RegistrationState,
user_id: UserID,
}
pub type WebAuthManagerReq = web::Data<Arc<WebAuthManager>>;
pub struct WebAuthManager {
core: Webauthn<WebAuthnAppConfig>,
crypto_wrapper: CryptoWrapper,
}
impl WebAuthManager {
pub fn init(conf: &AppConfig) -> Self {
Self {
core: Webauthn::new(WebAuthnAppConfig {
origin: url::Url::parse(&conf.website_origin)
.expect("Failed to parse configuration origin!"),
2022-04-21 17:24:26 +00:00
relying_party_id: conf.domain_name().split_once(':')
.map(|s| s.0)
.unwrap_or(conf.domain_name())
.to_string(),
}),
crypto_wrapper: CryptoWrapper::new_random(),
}
}
pub fn start_register(&self, user: &User) -> Res<RegisterKeyRequest> {
let (creation_challenge, registration_state) = self.core.generate_challenge_register(
&user.username,
2022-04-21 17:24:26 +00:00
false,
)?;
Ok(RegisterKeyRequest {
opaque_state: self.crypto_wrapper.encrypt(&RegisterKeyOpaqueData {
registration_state,
user_id: user.uid.clone(),
})?,
creation_challenge,
})
}
2022-04-21 17:24:26 +00:00
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!")));
}
let res = self.core
.register_credential(&pub_cred, &state.registration_state, |_| Ok(false))?;
Ok(WebauthnPubKey { creds: res.0 })
}
}