Support for webauthn and u2f->webauthn migrations

This commit is contained in:
Daniel García
2021-06-07 23:34:00 +02:00
parent cea7a30d82
commit c380d9c379
18 changed files with 655 additions and 127 deletions
Generated
+111 -66
View File
File diff suppressed because it is too large Load Diff
+13 -9
View File
@@ -28,8 +28,8 @@ syslog = "4.0.1"
[dependencies] [dependencies]
# Web framework for nightly with a focus on ease-of-use, expressibility, and speed. # Web framework for nightly with a focus on ease-of-use, expressibility, and speed.
rocket = { version = "0.5.0-dev", features = ["tls"], default-features = false } rocket = { version = "=0.5.0-dev", features = ["tls"], default-features = false }
rocket_contrib = "0.5.0-dev" rocket_contrib = "=0.5.0-dev"
# HTTP client # HTTP client
reqwest = { version = "0.11.3", features = ["blocking", "json", "gzip", "brotli", "socks", "cookies"] } reqwest = { version = "0.11.3", features = ["blocking", "json", "gzip", "brotli", "socks", "cookies"] }
@@ -41,7 +41,7 @@ bytes = "1.0.1"
url = "2.2.2" url = "2.2.2"
# multipart/form-data support # multipart/form-data support
multipart = { version = "0.17.1", features = ["server"], default-features = false } multipart = { version = "0.18.0", features = ["server"], default-features = false }
# WebSockets library # WebSockets library
ws = { version = "0.10.0", package = "parity-ws" } ws = { version = "0.10.0", package = "parity-ws" }
@@ -77,7 +77,7 @@ uuid = { version = "0.8.2", features = ["v4"] }
# Date and time libraries # Date and time libraries
chrono = { version = "0.4.19", features = ["serde"] } chrono = { version = "0.4.19", features = ["serde"] }
chrono-tz = "0.5.3" chrono-tz = "0.5.3"
time = "0.2.26" time = "0.2.27"
# Job scheduler # Job scheduler
job_scheduler = "1.2.1" job_scheduler = "1.2.1"
@@ -93,6 +93,7 @@ jsonwebtoken = "7.2.0"
# U2F library # U2F library
u2f = "0.2.0" u2f = "0.2.0"
webauthn-rs = "0.3.0-alpha.7"
# Yubico Library # Yubico Library
yubico = { version = "0.10.0", features = ["online-tokio"], default-features = false } yubico = { version = "0.10.0", features = ["online-tokio"], default-features = false }
@@ -101,7 +102,7 @@ yubico = { version = "0.10.0", features = ["online-tokio"], default-features = f
dotenv = { version = "0.15.0", default-features = false } dotenv = { version = "0.15.0", default-features = false }
# Lazy initialization # Lazy initialization
once_cell = "1.7.2" once_cell = "1.8.0"
# Numerical libraries # Numerical libraries
num-traits = "0.2.14" num-traits = "0.2.14"
@@ -109,10 +110,10 @@ num-derive = "0.3.3"
# Email libraries # Email libraries
tracing = { version = "0.1.26", features = ["log"] } # Needed to have lettre trace logging used when SMTP_DEBUG is enabled. tracing = { version = "0.1.26", features = ["log"] } # Needed to have lettre trace logging used when SMTP_DEBUG is enabled.
lettre = { version = "0.10.0-rc.1", features = ["smtp-transport", "builder", "serde", "native-tls", "hostname", "tracing"], default-features = false } lettre = { version = "0.10.0-rc.3", features = ["smtp-transport", "builder", "serde", "native-tls", "hostname", "tracing"], default-features = false }
# Template library # Template library
handlebars = { version = "3.5.5", features = ["dir_source"] } handlebars = { version = "4.0.0", features = ["dir_source"] }
# For favicon extraction from main website # For favicon extraction from main website
html5ever = "0.25.1" html5ever = "0.25.1"
@@ -129,10 +130,10 @@ percent-encoding = "2.1.0"
idna = "0.2.3" idna = "0.2.3"
# CLI argument parsing # CLI argument parsing
pico-args = "0.4.1" pico-args = "0.4.2"
# Logging panics to logfile instead stderr only # Logging panics to logfile instead stderr only
backtrace = "0.3.59" backtrace = "0.3.60"
# Macro ident concatenation # Macro ident concatenation
paste = "1.0.5" paste = "1.0.5"
@@ -151,3 +152,6 @@ data-url = { git = 'https://github.com/servo/rust-url', package="data-url", rev
# In particular, `cron` has since implemented parsing of some common syntax # In particular, `cron` has since implemented parsing of some common syntax
# that wasn't previously supported (https://github.com/zslayton/cron/pull/64). # that wasn't previously supported (https://github.com/zslayton/cron/pull/64).
job_scheduler = { git = 'https://github.com/jjlin/job_scheduler', rev = 'ee023418dbba2bfe1e30a5fd7d937f9e33739806' } job_scheduler = { git = 'https://github.com/jjlin/job_scheduler', rev = 'ee023418dbba2bfe1e30a5fd7d937f9e33739806' }
# Add support for U2F appid extension compatibility
webauthn-rs = { git = 'https://github.com/dani-garcia/webauthn-rs', rev = '70b458f246d207e5b6333ada9f1d5794c5e01da1' }
+2 -2
View File
@@ -44,8 +44,8 @@
# https://docs.docker.com/develop/develop-images/multistage-build/ # https://docs.docker.com/develop/develop-images/multistage-build/
# https://whitfin.io/speeding-up-rust-docker-builds/ # https://whitfin.io/speeding-up-rust-docker-builds/
####################### VAULT BUILD IMAGE ####################### ####################### VAULT BUILD IMAGE #######################
{% set vault_version = "2.19.0d" %} {% set vault_version = "2.20.4" %}
{% set vault_image_digest = "sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233" %} {% set vault_image_digest = "sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b" %}
# The web-vault digest specifies a particular web-vault build on Docker Hub. # The web-vault digest specifies a particular web-vault build on Docker Hub.
# Using the digest instead of the tag name provides better security, # Using the digest instead of the tag name provides better security,
# as the digest of an image is immutable, whereas a tag name can later # as the digest of an image is immutable, whereas a tag name can later
+6 -6
View File
@@ -14,15 +14,15 @@
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
# click the tag name to view the digest of the image it currently points to. # click the tag name to view the digest of the image it currently points to.
# - From the command line: # - From the command line:
# $ docker pull vaultwarden/web-vault:v2.19.0d # $ docker pull vaultwarden/web-vault:v2.20.4
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.19.0d # $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.20.4
# [vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233] # [vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b]
# #
# - Conversely, to get the tag name from the digest: # - Conversely, to get the tag name from the digest:
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233 # $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b
# [vaultwarden/web-vault:v2.19.0d] # [vaultwarden/web-vault:v2.20.4]
# #
FROM vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233 as vault FROM vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b as vault
########################## BUILD IMAGE ########################## ########################## BUILD IMAGE ##########################
FROM rust:1.51 as build FROM rust:1.51 as build
+6 -6
View File
@@ -14,15 +14,15 @@
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
# click the tag name to view the digest of the image it currently points to. # click the tag name to view the digest of the image it currently points to.
# - From the command line: # - From the command line:
# $ docker pull vaultwarden/web-vault:v2.19.0d # $ docker pull vaultwarden/web-vault:v2.20.4
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.19.0d # $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.20.4
# [vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233] # [vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b]
# #
# - Conversely, to get the tag name from the digest: # - Conversely, to get the tag name from the digest:
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233 # $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b
# [vaultwarden/web-vault:v2.19.0d] # [vaultwarden/web-vault:v2.20.4]
# #
FROM vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233 as vault FROM vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b as vault
########################## BUILD IMAGE ########################## ########################## BUILD IMAGE ##########################
FROM clux/muslrust:nightly-2021-04-14 as build FROM clux/muslrust:nightly-2021-04-14 as build
+6 -6
View File
@@ -14,15 +14,15 @@
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
# click the tag name to view the digest of the image it currently points to. # click the tag name to view the digest of the image it currently points to.
# - From the command line: # - From the command line:
# $ docker pull vaultwarden/web-vault:v2.19.0d # $ docker pull vaultwarden/web-vault:v2.20.4
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.19.0d # $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.20.4
# [vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233] # [vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b]
# #
# - Conversely, to get the tag name from the digest: # - Conversely, to get the tag name from the digest:
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233 # $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b
# [vaultwarden/web-vault:v2.19.0d] # [vaultwarden/web-vault:v2.20.4]
# #
FROM vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233 as vault FROM vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b as vault
########################## BUILD IMAGE ########################## ########################## BUILD IMAGE ##########################
FROM rust:1.51 as build FROM rust:1.51 as build
+6 -6
View File
@@ -14,15 +14,15 @@
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
# click the tag name to view the digest of the image it currently points to. # click the tag name to view the digest of the image it currently points to.
# - From the command line: # - From the command line:
# $ docker pull vaultwarden/web-vault:v2.19.0d # $ docker pull vaultwarden/web-vault:v2.20.4
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.19.0d # $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.20.4
# [vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233] # [vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b]
# #
# - Conversely, to get the tag name from the digest: # - Conversely, to get the tag name from the digest:
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233 # $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b
# [vaultwarden/web-vault:v2.19.0d] # [vaultwarden/web-vault:v2.20.4]
# #
FROM vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233 as vault FROM vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b as vault
########################## BUILD IMAGE ########################## ########################## BUILD IMAGE ##########################
FROM rust:1.51 as build FROM rust:1.51 as build
+6 -6
View File
@@ -14,15 +14,15 @@
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
# click the tag name to view the digest of the image it currently points to. # click the tag name to view the digest of the image it currently points to.
# - From the command line: # - From the command line:
# $ docker pull vaultwarden/web-vault:v2.19.0d # $ docker pull vaultwarden/web-vault:v2.20.4
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.19.0d # $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.20.4
# [vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233] # [vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b]
# #
# - Conversely, to get the tag name from the digest: # - Conversely, to get the tag name from the digest:
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233 # $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b
# [vaultwarden/web-vault:v2.19.0d] # [vaultwarden/web-vault:v2.20.4]
# #
FROM vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233 as vault FROM vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b as vault
########################## BUILD IMAGE ########################## ########################## BUILD IMAGE ##########################
FROM rust:1.51 as build FROM rust:1.51 as build
+6 -6
View File
@@ -14,15 +14,15 @@
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
# click the tag name to view the digest of the image it currently points to. # click the tag name to view the digest of the image it currently points to.
# - From the command line: # - From the command line:
# $ docker pull vaultwarden/web-vault:v2.19.0d # $ docker pull vaultwarden/web-vault:v2.20.4
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.19.0d # $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.20.4
# [vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233] # [vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b]
# #
# - Conversely, to get the tag name from the digest: # - Conversely, to get the tag name from the digest:
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233 # $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b
# [vaultwarden/web-vault:v2.19.0d] # [vaultwarden/web-vault:v2.20.4]
# #
FROM vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233 as vault FROM vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b as vault
########################## BUILD IMAGE ########################## ########################## BUILD IMAGE ##########################
FROM messense/rust-musl-cross:armv7-musleabihf as build FROM messense/rust-musl-cross:armv7-musleabihf as build
+2
View File
@@ -17,6 +17,7 @@ pub mod authenticator;
pub mod duo; pub mod duo;
pub mod email; pub mod email;
pub mod u2f; pub mod u2f;
pub mod webauthn;
pub mod yubikey; pub mod yubikey;
pub fn routes() -> Vec<Route> { pub fn routes() -> Vec<Route> {
@@ -26,6 +27,7 @@ pub fn routes() -> Vec<Route> {
routes.append(&mut duo::routes()); routes.append(&mut duo::routes());
routes.append(&mut email::routes()); routes.append(&mut email::routes());
routes.append(&mut u2f::routes()); routes.append(&mut u2f::routes());
routes.append(&mut webauthn::routes());
routes.append(&mut yubikey::routes()); routes.append(&mut yubikey::routes());
routes routes
+8 -5
View File
@@ -94,13 +94,14 @@ struct RegistrationDef {
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct U2FRegistration { pub struct U2FRegistration {
id: i32, pub id: i32,
name: String, pub name: String,
#[serde(with = "RegistrationDef")] #[serde(with = "RegistrationDef")]
reg: Registration, pub reg: Registration,
counter: u32, pub counter: u32,
compromised: bool, compromised: bool,
pub migrated: Option<bool>,
} }
impl U2FRegistration { impl U2FRegistration {
@@ -168,6 +169,7 @@ fn activate_u2f(data: JsonUpcase<EnableU2FData>, headers: Headers, conn: DbConn)
reg: registration, reg: registration,
compromised: false, compromised: false,
counter: 0, counter: 0,
migrated: None,
}; };
let mut regs = get_u2f_registrations(&user.uuid, &conn)?.1; let mut regs = get_u2f_registrations(&user.uuid, &conn)?.1;
@@ -273,6 +275,7 @@ fn get_u2f_registrations(user_uuid: &str, conn: &DbConn) -> Result<(bool, Vec<U2
reg: old_regs.remove(0), reg: old_regs.remove(0),
compromised: false, compromised: false,
counter: 0, counter: 0,
migrated: None,
}]; }];
// Save new format // Save new format
File diff suppressed because it is too large Load Diff
+6
View File
@@ -240,6 +240,7 @@ fn twofactor_auth(
_tf::authenticator::validate_totp_code_str(user_uuid, twofactor_code, &selected_data?, ip, conn)? _tf::authenticator::validate_totp_code_str(user_uuid, twofactor_code, &selected_data?, ip, conn)?
} }
Some(TwoFactorType::U2f) => _tf::u2f::validate_u2f_login(user_uuid, twofactor_code, conn)?, Some(TwoFactorType::U2f) => _tf::u2f::validate_u2f_login(user_uuid, twofactor_code, conn)?,
Some(TwoFactorType::Webauthn) => _tf::webauthn::validate_webauthn_login(user_uuid, twofactor_code, conn)?,
Some(TwoFactorType::YubiKey) => _tf::yubikey::validate_yubikey_login(twofactor_code, &selected_data?)?, Some(TwoFactorType::YubiKey) => _tf::yubikey::validate_yubikey_login(twofactor_code, &selected_data?)?,
Some(TwoFactorType::Duo) => { Some(TwoFactorType::Duo) => {
_tf::duo::validate_duo_login(data.username.as_ref().unwrap(), twofactor_code, conn)? _tf::duo::validate_duo_login(data.username.as_ref().unwrap(), twofactor_code, conn)?
@@ -309,6 +310,11 @@ fn _json_err_twofactor(providers: &[i32], user_uuid: &str, conn: &DbConn) -> Api
}); });
} }
Some(TwoFactorType::Webauthn) if CONFIG.domain_set() => {
let request = two_factor::webauthn::generate_webauthn_login(user_uuid, conn)?;
result["TwoFactorProviders2"][provider.to_string()] = request.0;
}
Some(TwoFactorType::Duo) => { Some(TwoFactorType::Duo) => {
let email = match User::find_by_uuid(user_uuid, &conn) { let email = match User::find_by_uuid(user_uuid, &conn) {
Some(u) => u.email, Some(u) => u.email,
+2 -2
View File
@@ -51,10 +51,10 @@ impl NumberOrString {
} }
} }
fn into_i32(self) -> ApiResult<i32> { fn into_i32(&self) -> ApiResult<i32> {
use std::num::ParseIntError as PIE; use std::num::ParseIntError as PIE;
match self { match self {
NumberOrString::Number(n) => Ok(n), NumberOrString::Number(n) => Ok(*n),
NumberOrString::String(s) => { NumberOrString::String(s) => {
s.parse().map_err(|e: PIE| crate::Error::new("Can't convert to number", e.to_string())) s.parse().map_err(|e: PIE| crate::Error::new("Can't convert to number", e.to_string()))
} }
+2 -2
View File
@@ -114,7 +114,7 @@ macro_rules! db_run {
}; };
// Different code for each db // Different code for each db
( $conn:ident: $( $($db:ident),+ $body:block )+ ) => { ( $conn:ident: $( $($db:ident),+ $body:block )+ ) => {{
#[allow(unused)] use diesel::prelude::*; #[allow(unused)] use diesel::prelude::*;
match $conn { match $conn {
$($( $($(
@@ -128,7 +128,7 @@ macro_rules! db_run {
$body $body
}, },
)+)+ )+)+
} }}
}; };
// Same for all dbs // Same for all dbs
+72
View File
@@ -31,11 +31,14 @@ pub enum TwoFactorType {
U2f = 4, U2f = 4,
Remember = 5, Remember = 5,
OrganizationDuo = 6, OrganizationDuo = 6,
Webauthn = 7,
// These are implementation details // These are implementation details
U2fRegisterChallenge = 1000, U2fRegisterChallenge = 1000,
U2fLoginChallenge = 1001, U2fLoginChallenge = 1001,
EmailVerificationChallenge = 1002, EmailVerificationChallenge = 1002,
WebauthnRegisterChallenge = 1003,
WebauthnLoginChallenge = 1004,
} }
/// Local methods /// Local methods
@@ -146,4 +149,73 @@ impl TwoFactor {
.map_res("Error deleting twofactors") .map_res("Error deleting twofactors")
}} }}
} }
pub fn migrate_u2f_to_webauthn(conn: &DbConn) -> EmptyResult {
let u2f_factors = db_run! { conn: {
twofactor::table
.filter(twofactor::atype.eq(TwoFactorType::U2f as i32))
.load::<TwoFactorDb>(conn)
.expect("Error loading twofactor")
.from_db()
}};
use crate::api::core::two_factor::u2f::U2FRegistration;
use crate::api::core::two_factor::webauthn::{get_webauthn_registrations, WebauthnRegistration};
use std::convert::TryInto;
use webauthn_rs::proto::*;
for mut u2f in u2f_factors {
let mut regs: Vec<U2FRegistration> = serde_json::from_str(&u2f.data)?;
// If there are no registrations or they are migrated (we do the migration in batch so we can consider them all migrated when the first one is)
if regs.is_empty() || regs[0].migrated == Some(true) {
continue;
}
let (_, mut webauthn_regs) = get_webauthn_registrations(&u2f.user_uuid, &conn)?;
// If the user already has webauthn registrations saved, don't overwrite them
if !webauthn_regs.is_empty() {
continue;
}
for reg in &mut regs {
let x: [u8; 32] = reg.reg.pub_key[1..33].try_into().unwrap();
let y: [u8; 32] = reg.reg.pub_key[33..65].try_into().unwrap();
let key = COSEKey {
type_: COSEAlgorithm::ES256,
key: COSEKeyType::EC_EC2(COSEEC2Key {
curve: ECDSACurve::SECP256R1,
x,
y,
}),
};
let new_reg = WebauthnRegistration {
id: reg.id,
migrated: true,
name: reg.name.clone(),
credential: Credential {
counter: reg.counter,
verified: false,
cred: key,
cred_id: reg.reg.key_handle.clone(),
registration_policy: UserVerificationPolicy::Discouraged,
},
};
webauthn_regs.push(new_reg);
reg.migrated = Some(true);
}
u2f.data = serde_json::to_string(&regs)?;
u2f.save(&conn)?;
TwoFactor::new(u2f.user_uuid.clone(), TwoFactorType::Webauthn, serde_json::to_string(&webauthn_regs)?)
.save(&conn)?;
}
Ok(())
}
} }
+5 -5
View File
@@ -39,19 +39,18 @@ use diesel::ConnectionError as DieselConErr;
use diesel_migrations::RunMigrationsError as DieselMigErr; use diesel_migrations::RunMigrationsError as DieselMigErr;
use handlebars::RenderError as HbErr; use handlebars::RenderError as HbErr;
use jsonwebtoken::errors::Error as JwtErr; use jsonwebtoken::errors::Error as JwtErr;
use lettre::address::AddressError as AddrErr;
use lettre::error::Error as LettreErr;
use lettre::transport::smtp::Error as SmtpErr;
use regex::Error as RegexErr; use regex::Error as RegexErr;
use reqwest::Error as ReqErr; use reqwest::Error as ReqErr;
use serde_json::{Error as SerdeErr, Value}; use serde_json::{Error as SerdeErr, Value};
use std::io::Error as IoErr; use std::io::Error as IoErr;
use std::time::SystemTimeError as TimeErr; use std::time::SystemTimeError as TimeErr;
use u2f::u2ferror::U2fError as U2fErr; use u2f::u2ferror::U2fError as U2fErr;
use webauthn_rs::error::WebauthnError as WebauthnErr;
use yubico::yubicoerror::YubicoError as YubiErr; use yubico::yubicoerror::YubicoError as YubiErr;
use lettre::address::AddressError as AddrErr;
use lettre::error::Error as LettreErr;
use lettre::transport::smtp::Error as SmtpErr;
#[derive(Serialize)] #[derive(Serialize)]
pub struct Empty {} pub struct Empty {}
@@ -86,6 +85,7 @@ make_error! {
DieselConError(DieselConErr): _has_source, _api_error, DieselConError(DieselConErr): _has_source, _api_error,
DieselMigError(DieselMigErr): _has_source, _api_error, DieselMigError(DieselMigErr): _has_source, _api_error,
WebauthnError(WebauthnErr): _has_source, _api_error,
} }
impl std::fmt::Debug for Error { impl std::fmt::Debug for Error {
+2
View File
@@ -60,6 +60,8 @@ fn main() {
let pool = create_db_pool(); let pool = create_db_pool();
schedule_jobs(pool.clone()); schedule_jobs(pool.clone());
crate::db::models::TwoFactor::migrate_u2f_to_webauthn(&pool.get().unwrap()).unwrap();
launch_rocket(pool, extra_debug); // Blocks until program termination. launch_rocket(pool, extra_debug); // Blocks until program termination.
} }