dependencies: update opaque_ke to v2

This is a breaking change: it changes the way the password data is
serialized in the DB, so any saved password is no longer readable (all
passwords have to get reset).
This commit is contained in:
Valentin Tolmer 2022-11-21 11:56:32 +01:00
parent ffc59af345
commit 5cb07b9780
18 changed files with 545 additions and 339 deletions

View File

@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Breaking
- The password storage mechanism has changed, the passwords cannot be ported over from the old version. All passwords have to be reset.
## [0.4.1] - 2022-10-10
### Added

462
Cargo.lock generated
View File

@ -102,7 +102,7 @@ dependencies = [
"rand 0.8.5",
"regex",
"serde",
"sha-1",
"sha-1 0.9.8",
"smallvec",
"time 0.2.27",
"tokio",
@ -364,10 +364,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33954243bd79057c2de7338850b85983a44588021f8a5fee574a8888c6de4344"
[[package]]
name = "arrayref"
version = "0.3.6"
name = "argon2"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
checksum = "db4ce4441f99dbd377ca8a8f57b698c44d0d6e712d8329b5040da5a64aa1ce73"
dependencies = [
"base64ct",
"blake2",
"password-hash",
]
[[package]]
name = "arrayvec"
@ -395,7 +400,7 @@ checksum = "30ff05a702273012438132f449575dbc804e27b2f3cbe3069aa237d26c98fa33"
dependencies = [
"asn1-rs-derive",
"asn1-rs-impl",
"displaydoc 0.2.3",
"displaydoc",
"nom 7.1.1",
"num-traits",
"rusticata-macros",
@ -452,7 +457,7 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b88d82667eca772c4aa12f0f1348b3ae643424c8876448f3f7bd5787032e234c"
dependencies = [
"autocfg 1.1.0",
"autocfg",
]
[[package]]
@ -466,15 +471,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "autocfg"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78"
dependencies = [
"autocfg 1.1.0",
]
[[package]]
name = "autocfg"
version = "1.1.0"
@ -502,6 +498,12 @@ version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270"
[[package]]
name = "base16ct"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce"
[[package]]
name = "base64"
version = "0.13.0"
@ -530,14 +532,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "blake2b_simd"
version = "0.5.11"
name = "blake2"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587"
checksum = "b12e5fd123190ce1c2e559308a94c9bacad77907d4c6005d9e58fe1a0689e55e"
dependencies = [
"arrayref",
"arrayvec",
"constant_time_eq",
"digest 0.10.6",
]
[[package]]
@ -549,6 +549,15 @@ dependencies = [
"generic-array",
]
[[package]]
name = "block-buffer"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e"
dependencies = [
"generic-array",
]
[[package]]
name = "boolinator"
version = "2.4.0"
@ -732,9 +741,15 @@ dependencies = [
[[package]]
name = "const-oid"
version = "0.6.2"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b"
checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3"
[[package]]
name = "const-oid"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b"
[[package]]
name = "const_fn"
@ -742,12 +757,6 @@ version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935"
[[package]]
name = "constant_time_eq"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
[[package]]
name = "convert_case"
version = "0.4.0"
@ -882,13 +891,34 @@ dependencies = [
[[package]]
name = "crypto-bigint"
version = "0.2.11"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f83bd3bb4314701c568e340cd8cf78c975aa0ca79e03d3f6d1677d5b0c9c0c03"
checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21"
dependencies = [
"generic-array",
"subtle",
]
[[package]]
name = "crypto-bigint"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef"
dependencies = [
"generic-array",
"rand_core 0.6.3",
"subtle",
"zeroize",
]
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
@ -901,16 +931,6 @@ dependencies = [
"subtle",
]
[[package]]
name = "crypto-mac"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714"
dependencies = [
"generic-array",
"subtle",
]
[[package]]
name = "ct-codecs"
version = "1.1.1"
@ -919,14 +939,26 @@ checksum = "f3b7eb4404b8195a9abb6356f4ac07d8ba267045c8d6d220ac4dc992e6cc75df"
[[package]]
name = "curve25519-dalek"
version = "3.2.1"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0"
checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61"
dependencies = [
"byteorder",
"digest",
"digest 0.9.0",
"rand_core 0.5.1",
"serde",
"subtle",
"zeroize",
]
[[package]]
name = "curve25519-dalek"
version = "4.0.0-pre.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4033478fbf70d6acf2655ac70da91ee65852d69daf7a67bf7a2f518fb47aafcf"
dependencies = [
"byteorder",
"digest 0.9.0",
"rand_core 0.6.3",
"subtle",
"zeroize",
]
@ -974,12 +1006,22 @@ checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57"
[[package]]
name = "der"
version = "0.4.5"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79b71cca7d95d7681a4b3b9cdf63c8dbc3730d0584c2c74e31416d64a90493f4"
checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c"
dependencies = [
"const-oid",
"crypto-bigint",
"const-oid 0.7.1",
"crypto-bigint 0.3.2",
"pem-rfc7468",
]
[[package]]
name = "der"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dd2ae565c0a381dde7fade45fce95984c568bdcb4700a4fdbe3175e0380b2f"
dependencies = [
"const-oid 0.9.1",
]
[[package]]
@ -989,13 +1031,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe398ac75057914d7d07307bf67dc7f3f574a26783b4fc7805a20ffa9f506e82"
dependencies = [
"asn1-rs",
"displaydoc 0.2.3",
"displaydoc",
"nom 7.1.1",
"num-bigint 0.4.3",
"num-traits",
"rusticata-macros",
]
[[package]]
name = "derive-where"
version = "1.0.0-rc.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d322f2907b2abad3117790c1a54d8f2d64574ba0fbea54cb6c6e66a0e50d99a4"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "derive_builder"
version = "0.10.2"
@ -1066,6 +1119,17 @@ dependencies = [
"generic-array",
]
[[package]]
name = "digest"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
dependencies = [
"block-buffer 0.10.3",
"crypto-common",
"subtle",
]
[[package]]
name = "dirs"
version = "4.0.0"
@ -1092,17 +1156,6 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
[[package]]
name = "displaydoc"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adc2ab4d5a16117f9029e9a6b5e4e79f4c67f6519bc134210d4d4a04ba31f41b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "displaydoc"
version = "0.2.3"
@ -1132,6 +1185,25 @@ version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be"
[[package]]
name = "elliptic-curve"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3"
dependencies = [
"base16ct",
"crypto-bigint 0.4.9",
"der 0.6.0",
"digest 0.10.6",
"ff",
"generic-array",
"group",
"rand_core 0.6.3",
"sec1",
"subtle",
"zeroize",
]
[[package]]
name = "email-encoding"
version = "0.1.3"
@ -1157,6 +1229,12 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "event-listener"
version = "2.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
[[package]]
name = "failure"
version = "0.1.8"
@ -1188,6 +1266,16 @@ dependencies = [
"instant",
]
[[package]]
name = "ff"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160"
dependencies = [
"rand_core 0.6.3",
"subtle",
]
[[package]]
name = "figment"
version = "0.10.6"
@ -1392,15 +1480,6 @@ dependencies = [
"version_check",
]
[[package]]
name = "generic-bytes"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6638d839bbd1cea640d8c5348dd82e0d545dbd364f3c2a251646eaf2ef0773b"
dependencies = [
"generic-array",
]
[[package]]
name = "getrandom"
version = "0.1.16"
@ -1602,6 +1681,17 @@ dependencies = [
"syn",
]
[[package]]
name = "group"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7"
dependencies = [
"ff",
"rand_core 0.6.3",
"subtle",
]
[[package]]
name = "h2"
version = "0.3.13"
@ -1677,12 +1767,11 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hkdf"
version = "0.11.0"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01706d578d5c281058480e673ae4086a9f4710d8df1ad80a5b03e39ece5f886b"
checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437"
dependencies = [
"digest",
"hmac 0.11.0",
"hmac 0.12.1",
]
[[package]]
@ -1691,18 +1780,17 @@ version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15"
dependencies = [
"crypto-mac 0.10.1",
"digest",
"crypto-mac",
"digest 0.9.0",
]
[[package]]
name = "hmac"
version = "0.11.0"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b"
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
dependencies = [
"crypto-mac 0.11.1",
"digest",
"digest 0.10.6",
]
[[package]]
@ -1825,7 +1913,7 @@ version = "1.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3"
dependencies = [
"autocfg 1.1.0",
"autocfg",
"hashbrown 0.9.1",
"serde",
]
@ -1956,12 +2044,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86e46349d67dc03bdbdb28da0337a355a53ca1d5156452722c36fe21d0e6389b"
dependencies = [
"base64",
"crypto-mac 0.10.1",
"digest",
"crypto-mac",
"digest 0.9.0",
"hmac 0.10.1",
"serde",
"serde_json",
"sha2",
"sha2 0.9.9",
]
[[package]]
@ -2083,9 +2171,9 @@ checksum = "33a33a362ce288760ec6a508b94caaec573ae7d3bbbd91b87aa0bad4456839db"
[[package]]
name = "libsqlite3-sys"
version = "0.23.2"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cafc7c74096c336d9d27145f7ebd4f4b6f95ba16aa5a282387267e6925cb58"
checksum = "898745e570c7d0453cc1fbc4a701eb6c662ed54e8fec8b7d14be137ebeeb9d14"
dependencies = [
"cc",
"pkg-config",
@ -2147,7 +2235,7 @@ dependencies = [
"serde",
"serde_bytes",
"serde_json",
"sha2",
"sha2 0.9.9",
"sqlx",
"sqlx-core",
"thiserror",
@ -2198,16 +2286,16 @@ dependencies = [
name = "lldap_auth"
version = "0.3.0-alpha.1"
dependencies = [
"argon2",
"chrono",
"curve25519-dalek",
"digest",
"curve25519-dalek 3.2.0",
"digest 0.9.0",
"generic-array",
"getrandom 0.2.7",
"opaque-ke",
"rand 0.8.5",
"rust-argon2",
"serde",
"sha2",
"sha2 0.9.9",
"thiserror",
]
@ -2235,7 +2323,7 @@ version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53"
dependencies = [
"autocfg 1.1.0",
"autocfg",
"scopeguard",
]
@ -2265,13 +2353,11 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]]
name = "md-5"
version = "0.9.1"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15"
checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca"
dependencies = [
"block-buffer",
"digest",
"opaque-debug",
"digest 0.10.6",
]
[[package]]
@ -2443,7 +2529,7 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3"
dependencies = [
"autocfg 1.1.0",
"autocfg",
"num-integer",
"num-traits",
]
@ -2454,18 +2540,17 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
dependencies = [
"autocfg 1.1.0",
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-bigint-dig"
version = "0.7.0"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4547ee5541c18742396ae2c895d0717d0f886d8823b8399cdaf7b07d63ad0480"
checksum = "2399c9463abc5f909349d8aa9ba080e0b88b3ce2885389b60b993f39b1a56905"
dependencies = [
"autocfg 0.1.8",
"byteorder",
"lazy_static",
"libm",
@ -2483,7 +2568,7 @@ version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg 1.1.0",
"autocfg",
"num-traits",
]
@ -2493,7 +2578,7 @@ version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
dependencies = [
"autocfg 1.1.0",
"autocfg",
"num-integer",
"num-traits",
]
@ -2504,7 +2589,7 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
dependencies = [
"autocfg 1.1.0",
"autocfg",
"num-integer",
"num-traits",
]
@ -2515,7 +2600,7 @@ version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg 1.1.0",
"autocfg",
"libm",
]
@ -2570,22 +2655,23 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "opaque-ke"
version = "0.6.1"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "507fdf0b89eabfde58445f88807f57f253f72236e44960ebf690d897803cd18d"
checksum = "76d410412d23781909d90c3900c5783e830586765f2277bccc78167da8af81a5"
dependencies = [
"base64",
"curve25519-dalek",
"digest",
"displaydoc 0.1.7",
"curve25519-dalek 4.0.0-pre.1",
"derive-where",
"digest 0.10.6",
"displaydoc",
"elliptic-curve",
"generic-array",
"generic-bytes",
"getrandom 0.2.7",
"hkdf",
"hmac 0.11.0",
"hmac 0.12.1",
"rand 0.8.5",
"serde",
"subtle",
"thiserror",
"voprf",
"zeroize",
]
@ -2661,6 +2747,17 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "password-hash"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700"
dependencies = [
"base64ct",
"rand_core 0.6.3",
"subtle",
]
[[package]]
name = "paste"
version = "1.0.7"
@ -2692,9 +2789,9 @@ dependencies = [
[[package]]
name = "pem-rfc7468"
version = "0.2.4"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84e93a3b1cc0510b03020f33f21e62acdde3dcaef432edc95bea377fbd4c2cd4"
checksum = "01de5d978f34aa4b2296576379fcc416034702fd94117c56ffd8a1a767cefb30"
dependencies = [
"base64ct",
]
@ -2739,24 +2836,22 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkcs1"
version = "0.2.4"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "116bee8279d783c0cf370efa1a94632f2108e5ef0bb32df31f051647810a4e2c"
checksum = "a78f66c04ccc83dd4486fd46c33896f4e17b24a7a3a6400dedc48ed0ddd72320"
dependencies = [
"der",
"pem-rfc7468",
"der 0.5.1",
"pkcs8",
"zeroize",
]
[[package]]
name = "pkcs8"
version = "0.7.6"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee3ef9b64d26bad0536099c816c6734379e45bbd5f14798def6809e5cc350447"
checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0"
dependencies = [
"der",
"pem-rfc7468",
"pkcs1",
"der 0.5.1",
"spki",
"zeroize",
]
@ -3075,36 +3170,24 @@ dependencies = [
[[package]]
name = "rsa"
version = "0.5.0"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e05c2603e2823634ab331437001b411b9ed11660fbc4066f3908c84a9439260d"
checksum = "4cf22754c49613d2b3b119f0e5d46e34a2c628a937e3024b8762de4e7d8c710b"
dependencies = [
"byteorder",
"digest",
"lazy_static",
"digest 0.10.6",
"num-bigint-dig",
"num-integer",
"num-iter",
"num-traits",
"pkcs1",
"pkcs8",
"rand 0.8.5",
"rand_core 0.6.3",
"smallvec",
"subtle",
"zeroize",
]
[[package]]
name = "rust-argon2"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb"
dependencies = [
"base64",
"blake2b_simd",
"constant_time_eq",
"crossbeam-utils",
]
[[package]]
name = "rustc-demangle"
version = "0.1.21"
@ -3271,6 +3354,19 @@ dependencies = [
"syn",
]
[[package]]
name = "sec1"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928"
dependencies = [
"base16ct",
"der 0.6.0",
"generic-array",
"subtle",
"zeroize",
]
[[package]]
name = "secstr"
version = "0.5.0"
@ -3384,13 +3480,24 @@ version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6"
dependencies = [
"block-buffer",
"block-buffer 0.9.0",
"cfg-if",
"cpufeatures",
"digest",
"digest 0.9.0",
"opaque-debug",
]
[[package]]
name = "sha-1"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f"
dependencies = [
"cfg-if",
"cpufeatures",
"digest 0.10.6",
]
[[package]]
name = "sha1"
version = "0.6.1"
@ -3412,13 +3519,24 @@ version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
dependencies = [
"block-buffer",
"block-buffer 0.9.0",
"cfg-if",
"cpufeatures",
"digest",
"digest 0.9.0",
"opaque-debug",
]
[[package]]
name = "sha2"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
dependencies = [
"cfg-if",
"cpufeatures",
"digest 0.10.6",
]
[[package]]
name = "sharded-slab"
version = "0.1.4"
@ -3466,9 +3584,9 @@ checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32"
[[package]]
name = "smallvec"
version = "1.9.0"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]]
name = "smartstring"
@ -3512,11 +3630,12 @@ dependencies = [
[[package]]
name = "spki"
version = "0.4.1"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c01a0c15da1b0b0e1494112e7af814a678fec9bd157881b49beac661e9b6f32"
checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27"
dependencies = [
"der",
"base64ct",
"der 0.5.1",
]
[[package]]
@ -3542,9 +3661,9 @@ dependencies = [
[[package]]
name = "sqlx-core"
version = "0.5.11"
version = "0.5.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "195183bf6ff8328bb82c0511a83faf60aacf75840103388851db61d7a9854ae3"
checksum = "e48c61941ccf5ddcada342cd59e3e5173b007c509e1e8e990dafc830294d9dc5"
dependencies = [
"ahash",
"atoi",
@ -3555,9 +3674,10 @@ dependencies = [
"chrono",
"crc",
"crossbeam-queue",
"digest",
"digest 0.10.6",
"dirs",
"either",
"event-listener",
"flume",
"futures-channel",
"futures-core",
@ -3567,7 +3687,8 @@ dependencies = [
"generic-array",
"hashlink",
"hex",
"hmac 0.11.0",
"hkdf",
"hmac 0.12.1",
"indexmap",
"itoa 1.0.2",
"libc",
@ -3584,8 +3705,8 @@ dependencies = [
"rustls 0.19.1",
"serde",
"serde_json",
"sha-1",
"sha2",
"sha-1 0.10.0",
"sha2 0.10.6",
"smallvec",
"sqlformat",
"sqlx-rt",
@ -3610,7 +3731,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"sha2",
"sha2 0.9.9",
"sqlx-core",
"sqlx-rt",
"syn",
@ -4291,6 +4412,25 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]]
name = "voprf"
version = "0.4.0-pre.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "081acbe8fcf05d5e8e2aad8ef3d40e02eddeaec07c75a9770d862a0fc0874322"
dependencies = [
"curve25519-dalek 4.0.0-pre.1",
"derive-where",
"digest 0.10.6",
"displaydoc",
"elliptic-curve",
"generic-array",
"rand_core 0.6.3",
"serde",
"sha2 0.10.6",
"subtle",
"zeroize",
]
[[package]]
name = "want"
version = "0.3.0"
@ -4671,9 +4811,9 @@ dependencies = [
[[package]]
name = "zeroize"
version = "1.1.1"
version = "1.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f33972566adbd2d3588b0491eb94b98b43695c4ef897903470ede4f3f5a28a"
checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f"
dependencies = [
"zeroize_derive",
]

View File

@ -73,9 +73,12 @@ pub struct Props {
pub enum Msg {
FormUpdate,
Submit,
AuthenticationStartResponse(Result<Box<login::ServerLoginStartResponse>>),
AuthenticationStartResponse(String, Result<Box<login::ServerLoginStartResponse>>),
SubmitNewPassword,
RegistrationStartResponse(Result<Box<registration::ServerRegistrationStartResponse>>),
RegistrationStartResponse(
String,
Result<Box<registration::ServerRegistrationStartResponse>>,
),
RegistrationFinishResponse(Result<()>),
}
@ -103,29 +106,28 @@ impl CommonComponent<ChangePasswordForm> for ChangePasswordForm {
username: self.common.username.clone(),
login_start_request: login_start_request.message,
};
self.common.call_backend(
HostService::login_start,
req,
Msg::AuthenticationStartResponse,
)?;
self.common
.call_backend(HostService::login_start, req, |r| {
Msg::AuthenticationStartResponse(old_password, r)
})?;
Ok(true)
}
}
Msg::AuthenticationStartResponse(res) => {
Msg::AuthenticationStartResponse(old_password, res) => {
let res = res.context("Could not initiate login")?;
match self.opaque_data.take() {
OpaqueData::Login(l) => {
opaque::client::login::finish_login(l, res.credential_response).map_err(
|e| {
// Common error, we want to print a full error to the console but only a
// simple one to the user.
ConsoleService::error(&format!(
"Invalid username or password: {}",
e
));
anyhow!("Invalid username or password")
},
)?;
opaque::client::login::finish_login(
&old_password,
l,
res.credential_response,
)
.map_err(|e| {
// Common error, we want to print a full error to the console but only a
// simple one to the user.
ConsoleService::error(&format!("Invalid username or password: {}", e));
anyhow!("Invalid username or password")
})?;
}
_ => panic!("Unexpected data in opaque_data field"),
};
@ -142,20 +144,20 @@ impl CommonComponent<ChangePasswordForm> for ChangePasswordForm {
registration_start_request: registration_start_request.message,
};
self.opaque_data = OpaqueData::Registration(registration_start_request.state);
self.common.call_backend(
HostService::register_start,
req,
Msg::RegistrationStartResponse,
)?;
self.common
.call_backend(HostService::register_start, req, |r| {
Msg::RegistrationStartResponse(new_password, r)
})?;
Ok(true)
}
Msg::RegistrationStartResponse(res) => {
Msg::RegistrationStartResponse(new_password, res) => {
let res = res.context("Could not initiate password change")?;
match self.opaque_data.take() {
OpaqueData::Registration(registration) => {
let mut rng = rand::rngs::OsRng;
let registration_finish =
opaque::client::registration::finish_registration(
&new_password,
registration,
res.registration_response,
&mut rng,

View File

@ -65,10 +65,9 @@ pub enum Msg {
CreateUserResponse(Result<create_user::ResponseData>),
SuccessfulCreation,
RegistrationStartResponse(
(
opaque::client::registration::ClientRegistration,
Result<Box<registration::ServerRegistrationStartResponse>>,
),
String,
opaque::client::registration::ClientRegistration,
Result<Box<registration::ServerRegistrationStartResponse>>,
),
RegistrationFinishResponse(Result<()>),
}
@ -124,7 +123,7 @@ impl CommonComponent<CreateUserForm> for CreateUserForm {
};
self.common
.call_backend(HostService::register_start, req, move |r| {
Msg::RegistrationStartResponse((state, r))
Msg::RegistrationStartResponse(password, state, r)
})
.context("Error trying to create user")?;
} else {
@ -132,10 +131,11 @@ impl CommonComponent<CreateUserForm> for CreateUserForm {
}
Ok(false)
}
Msg::RegistrationStartResponse((registration_start, response)) => {
Msg::RegistrationStartResponse(password, registration_start, response) => {
let response = response?;
let mut rng = rand::rngs::OsRng;
let registration_upload = opaque::client::registration::finish_registration(
&password,
registration_start,
response.registration_response,
&mut rng,

View File

@ -32,15 +32,15 @@ pub struct Props {
pub on_logged_in: Callback<(String, bool)>,
}
#[allow(clippy::large_enum_variant)]
pub enum Msg {
Update,
Submit,
AuthenticationRefreshResponse(Result<(String, bool)>),
AuthenticationStartResponse(
(
opaque::client::login::ClientLogin,
Result<Box<login::ServerLoginStartResponse>>,
),
opaque::client::login::ClientLogin,
String,
Result<Box<login::ServerLoginStartResponse>>,
),
AuthenticationFinishResponse(Result<(String, bool)>),
}
@ -64,25 +64,27 @@ impl CommonComponent<LoginForm> for LoginForm {
};
self.common
.call_backend(HostService::login_start, req, move |r| {
Msg::AuthenticationStartResponse((state, r))
Msg::AuthenticationStartResponse(state, password, r)
})?;
Ok(true)
}
Msg::AuthenticationStartResponse((login_start, res)) => {
Msg::AuthenticationStartResponse(login_start, password, res) => {
let res = res.context("Could not log in (invalid response to login start)")?;
let login_finish =
match opaque::client::login::finish_login(login_start, res.credential_response)
{
Err(e) => {
// Common error, we want to print a full error to the console but only a
// simple one to the user.
ConsoleService::error(&format!("Invalid username or password: {}", e));
self.common.error = Some(anyhow!("Invalid username or password"));
self.common.cancel_task();
return Ok(true);
}
Ok(l) => l,
};
let login_finish = match opaque::client::login::finish_login(
&password,
login_start,
res.credential_response,
) {
Err(e) => {
// Common error, we want to print a full error to the console but only a
// simple one to the user.
ConsoleService::error(&format!("Invalid username or password: {}", e));
self.common.error = Some(anyhow!("Invalid username or password"));
self.common.cancel_task();
return Ok(true);
}
Ok(l) => l,
};
let req = login::ClientLoginFinishRequest {
server_data: res.server_data,
credential_finalization: login_finish.message,

View File

@ -45,7 +45,10 @@ pub enum Msg {
ValidateTokenResponse(Result<ServerPasswordResetResponse>),
FormUpdate,
Submit,
RegistrationStartResponse(Result<Box<registration::ServerRegistrationStartResponse>>),
RegistrationStartResponse(
String,
Result<Box<registration::ServerRegistrationStartResponse>>,
),
RegistrationFinishResponse(Result<()>),
}
@ -72,18 +75,18 @@ impl CommonComponent<ResetPasswordStep2Form> for ResetPasswordStep2Form {
registration_start_request: registration_start_request.message,
};
self.opaque_data = Some(registration_start_request.state);
self.common.call_backend(
HostService::register_start,
req,
Msg::RegistrationStartResponse,
)?;
self.common
.call_backend(HostService::register_start, req, |r| {
Msg::RegistrationStartResponse(new_password, r)
})?;
Ok(true)
}
Msg::RegistrationStartResponse(res) => {
Msg::RegistrationStartResponse(new_password, res) => {
let res = res.context("Could not initiate password change")?;
let registration = self.opaque_data.take().expect("Missing registration data");
let mut rng = rand::rngs::OsRng;
let registration_finish = opaque_registration::finish_registration(
&new_password,
registration,
res.registration_response,
&mut rng,

View File

@ -11,7 +11,7 @@ opaque_client = []
js = []
[dependencies]
rust-argon2 = "0.8"
argon2 = "*"
curve25519-dalek = "3"
digest = "0.9"
generic-array = "*"
@ -21,7 +21,8 @@ sha2 = "0.9"
thiserror = "*"
[dependencies.opaque-ke]
version = "0.6"
version = "2"
features = ["std"]
[dependencies.chrono]
version = "*"

View File

@ -10,40 +10,46 @@ pub enum AuthenticationError {
pub type AuthenticationResult<T> = std::result::Result<T, AuthenticationError>;
pub use opaque_ke::keypair::{PrivateKey, PublicKey};
pub type KeyPair = opaque_ke::keypair::KeyPair<<DefaultSuite as CipherSuite>::Group>;
pub type KeyPair = opaque_ke::keypair::KeyPair<<DefaultSuite as CipherSuite>::KeGroup>;
/// A wrapper around argon2 to provide the [`opaque_ke::slow_hash::SlowHash`] trait.
pub struct ArgonHasher;
pub struct ArgonHasher {
hasher: argon2::Argon2<'static>,
}
/// The Argon hasher used for bruteforce protection.
///
/// Note that it isn't used to "hash the passwords", so it doesn't need a variable salt. Instead,
/// it's used as part of the OPAQUE protocol to add a slow hashing method, making bruteforce
/// attacks prohibitively more expensive.
impl ArgonHasher {
/// Fixed salt, doesn't affect the security. It is only used to make attacks more
/// computationally intensive, it doesn't serve any security purpose.
const SALT: &'static [u8] = b"lldap_opaque_salt";
/// Config for the argon hasher. Security enthusiasts may want to tweak this for their system.
const CONFIG: &'static argon2::Config<'static> = &argon2::Config {
ad: &[],
hash_length: 128,
lanes: 1,
mem_cost: 50 * 1024, // 50 MB, in KB
secret: &[],
thread_mode: argon2::ThreadMode::Sequential,
time_cost: 1,
variant: argon2::Variant::Argon2id,
version: argon2::Version::Version13,
};
impl Default for ArgonHasher {
fn default() -> Self {
ArgonHasher {
hasher: argon2::Argon2::new(
argon2::Algorithm::Argon2id,
argon2::Version::default(),
argon2::Params::new(
50 * 1024, // 50 MB, in KB
1,
1,
Some(64),
)
.unwrap(),
),
}
}
}
impl<D: opaque_ke::hash::Hash> opaque_ke::slow_hash::SlowHash<D> for ArgonHasher {
fn hash(
input: generic_array::GenericArray<u8, <D as digest::Digest>::OutputSize>,
) -> Result<Vec<u8>, opaque_ke::errors::InternalPakeError> {
argon2::hash_raw(&input, Self::SALT, Self::CONFIG)
.map_err(|_| opaque_ke::errors::InternalPakeError::HashingFailure)
impl opaque_ke::ksf::Ksf for ArgonHasher {
fn hash<L: generic_array::ArrayLength<u8>>(
&self,
input: generic_array::GenericArray<u8, L>,
) -> Result<generic_array::GenericArray<u8, L>, opaque_ke::errors::InternalError> {
let mut output = generic_array::GenericArray::<u8, L>::default();
self.hasher
.hash_password_into(&input, &[0; 16], &mut output)
.map_err(|_| opaque_ke::errors::InternalError::KsfError)?;
Ok(output)
}
}
@ -52,11 +58,11 @@ impl<D: opaque_ke::hash::Hash> opaque_ke::slow_hash::SlowHash<D> for ArgonHasher
#[allow(dead_code)]
pub struct DefaultSuite;
impl CipherSuite for DefaultSuite {
type Group = curve25519_dalek::ristretto::RistrettoPoint;
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
type Hash = sha2::Sha512;
/// Use argon2 as the slow hashing algorithm for our CipherSuite.
type SlowHash = ArgonHasher;
type OprfCs = opaque_ke::Ristretto255;
type KeGroup = opaque_ke::Ristretto255;
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
type Ksf = ArgonHasher;
}
/// Client-side code for OPAQUE protocol handling, to register a new user and login. All methods'
@ -85,12 +91,14 @@ pub mod client {
/// Finalize the registration negotiation.
pub fn finish_registration<R: RngCore + CryptoRng>(
password: &str,
registration_start: ClientRegistration,
registration_response: RegistrationResponse,
rng: &mut R,
) -> AuthenticationResult<ClientRegistrationFinishResult> {
Ok(registration_start.finish(
rng,
password.as_bytes(),
registration_response,
ClientRegistrationFinishParameters::default(),
)?)
@ -117,10 +125,15 @@ pub mod client {
/// Finalize the client login negotiation.
pub fn finish_login(
password: &str,
login_start: ClientLogin,
login_response: CredentialResponse,
) -> AuthenticationResult<ClientLoginFinishResult> {
Ok(login_start.finish(login_response, ClientLoginFinishParameters::default())?)
Ok(login_start.finish(
password.as_bytes(),
login_response,
ClientLoginFinishParameters::default(),
)?)
}
}
}

View File

@ -151,7 +151,7 @@ fn try_login(
);
}
let login_start_response = response.json::<lldap_auth::login::ServerLoginStartResponse>()?;
let login_finish = finish_login(state, login_start_response.credential_response)?;
let login_finish = finish_login(password, state, login_start_response.credential_response)?;
let req = ClientLoginFinishRequest {
server_data: login_start_response.server_data,
credential_finalization: login_finish.message,

View File

@ -94,7 +94,8 @@ version = "0.1"
features = ["with-chrono", "sqlx-sqlite", "sqlx-any"]
[dependencies.opaque-ke]
version = "0.6"
version = "2"
features = ["std"]
[dependencies.rand]
features = ["small_rng", "getrandom"]

View File

@ -261,6 +261,7 @@ pub struct UpdateGroupRequest {
#[async_trait]
pub trait LoginHandler: Clone + Send {
async fn bind(&self, request: BindRequest) -> Result<()>;
async fn set_password(&self, request: BindRequest) -> Result<()>;
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, sqlx::Type)]
@ -339,6 +340,7 @@ mockall::mock! {
#[async_trait]
impl LoginHandler for TestBackendHandler {
async fn bind(&self, request: BindRequest) -> Result<()>;
async fn set_password(&self, request: BindRequest) -> Result<()>;
}
}

View File

@ -34,7 +34,7 @@ pub mod tests {
pub async fn get_initialized_db() -> Pool {
let sql_pool = get_in_memory_db().await;
init_table(&sql_pool).await.unwrap();
init_table(&sql_pool, &get_default_config()).await.unwrap();
sql_pool
}
@ -52,6 +52,7 @@ pub mod tests {
.await
.unwrap();
let registration_upload = opaque::client::registration::finish_registration(
pass,
client_registration_start.state,
response.registration_response,
&mut rng,

View File

@ -1,5 +1,8 @@
use crate::infra::configuration::Configuration;
use super::{
handler::{GroupId, UserId, Uuid},
handler::{GroupId, LoginHandler, UserId, Uuid},
sql_backend_handler::SqlBackendHandler,
sql_tables::{
DbQueryBuilder, DbRow, Groups, Memberships, Metadata, Pool, SchemaVersion, Users,
},
@ -7,7 +10,7 @@ use super::{
use sea_query::*;
use sea_query_binder::SqlxBinder;
use sqlx::Row;
use tracing::{debug, warn};
use tracing::{debug, info, warn};
pub async fn create_group(group_name: &str, pool: &Pool) -> sqlx::Result<()> {
let now = chrono::Utc::now();
@ -45,6 +48,7 @@ pub async fn get_schema_version(pool: &Pool) -> Option<SchemaVersion> {
}
pub async fn upgrade_to_v1(pool: &Pool) -> sqlx::Result<()> {
info!("Upgrading DB schema from version 0->1");
// SQLite needs this pragma to be turned on. Other DB might not understand this, so ignore the
// error.
let _ = sqlx::query("PRAGMA foreign_keys = ON").execute(pool).await;
@ -296,8 +300,39 @@ pub async fn upgrade_to_v1(pool: &Pool) -> sqlx::Result<()> {
Ok(())
}
pub async fn migrate_from_version(_pool: &Pool, version: SchemaVersion) -> anyhow::Result<()> {
if version.0 > 1 {
pub async fn migrate_from_version(
pool: &Pool,
version: SchemaVersion,
config: &Configuration,
) -> anyhow::Result<()> {
if version.0 < 2 {
info!("Upgrading DB schema from version 1->2");
sqlx::query(
&Table::alter()
.table(Users::Table)
.add_column(ColumnDef::new(Users::PasswordHashV2).binary())
.to_string(DbQueryBuilder {}),
)
.execute(pool)
.await?;
let backend_handler = SqlBackendHandler::new(config.clone(), pool.clone());
backend_handler
.set_password(super::handler::BindRequest {
name: config.ldap_user_dn.clone(),
password: config.ldap_user_pass.unsecure().to_owned(),
})
.await?;
}
sqlx::query(
&Query::update()
.table(Metadata::Table)
.values(vec![(Metadata::Version, SchemaVersion(2).into())])
.to_string(DbQueryBuilder {}),
)
.execute(pool)
.await?;
info!("Successfully upgraded DB to schema version 2");
if version.0 > 2 {
anyhow::bail!("DB version downgrading is not supported");
}
Ok(())

View File

@ -36,6 +36,7 @@ fn passwords_match(
username.as_str(),
)?;
client::login::finish_login(
clear_password,
client_login_start_result.state,
server_login_start_result.message,
)?;
@ -44,8 +45,13 @@ fn passwords_match(
impl SqlBackendHandler {
fn get_orion_secret_key(&self) -> Result<orion::aead::SecretKey> {
use opaque_ke::keypair::SecretKey;
Ok(orion::aead::SecretKey::from_slice(
self.config.get_server_keys().private(),
self.config
.get_server_keys()
.private()
.serialize()
.as_slice(),
)?)
}
@ -57,7 +63,7 @@ impl SqlBackendHandler {
// Fetch the previously registered password file from the DB.
let password_file_bytes = {
let (query, values) = Query::select()
.column(Users::PasswordHash)
.column(Users::PasswordHashV2)
.from(Users::Table)
.cond_where(Expr::col(Users::UserId).eq(username))
.build_sqlx(DbQueryBuilder {});
@ -66,7 +72,7 @@ impl SqlBackendHandler {
.await?
{
if let Some(bytes) =
row.get::<Option<Vec<u8>>, _>(&*Users::PasswordHash.to_string())
row.get::<Option<Vec<u8>>, _>(&*Users::PasswordHashV2.to_string())
{
bytes
} else {
@ -91,7 +97,7 @@ impl LoginHandler for SqlBackendHandler {
#[instrument(skip_all, level = "debug", err)]
async fn bind(&self, request: BindRequest) -> Result<()> {
let (query, values) = Query::select()
.column(Users::PasswordHash)
.column(Users::PasswordHashV2)
.from(Users::Table)
.cond_where(Expr::col(Users::UserId).eq(&request.name))
.build_sqlx(DbQueryBuilder {});
@ -100,7 +106,7 @@ impl LoginHandler for SqlBackendHandler {
.await
{
if let Some(password_hash) =
row.get::<Option<Vec<u8>>, _>(&*Users::PasswordHash.to_string())
row.get::<Option<Vec<u8>>, _>(&*Users::PasswordHashV2.to_string())
{
if let Err(e) = passwords_match(
&password_hash,
@ -123,6 +129,31 @@ impl LoginHandler for SqlBackendHandler {
request.name
)))
}
#[instrument(skip_all, level = "debug", err)]
async fn set_password(&self, request: BindRequest) -> Result<()> {
use lldap_auth::*;
let mut rng = rand::rngs::OsRng;
let registration_start_request =
opaque::client::registration::start_registration(&request.password, &mut rng)?;
let req = registration::ClientRegistrationStartRequest {
username: request.name.to_string(),
registration_start_request: registration_start_request.message,
};
let registration_start_response = self.registration_start(req).await?;
let registration_finish = opaque::client::registration::finish_registration(
&request.password,
registration_start_request.state,
registration_start_response.registration_response,
&mut rng,
)?;
let req = registration::ClientRegistrationFinishRequest {
server_data: registration_start_response.server_data,
registration_upload: registration_finish.message,
};
self.registration_finish(req).await?;
Ok(())
}
}
#[async_trait]
@ -214,7 +245,10 @@ impl OpaqueHandler for SqlOpaqueHandler {
// Set the user password to the new password.
let (update_query, values) = Query::update()
.table(Users::Table)
.value(Users::PasswordHash, password_file.serialize().into())
.value(
Users::PasswordHashV2,
password_file.serialize().as_slice().into(),
)
.cond_where(Expr::col(Users::UserId).eq(username))
.build_sqlx(DbQueryBuilder {});
sqlx::query_with(update_query.as_str(), values)
@ -243,6 +277,7 @@ pub(crate) async fn register_password(
})
.await?;
let registration_finish = opaque::client::registration::finish_registration(
password.unsecure(),
registration_start.state,
start_response.registration_response,
&mut rng,
@ -275,6 +310,7 @@ mod tests {
})
.await?;
let login_finish = opaque::client::login::finish_login(
password,
login_start.state,
start_response.credential_response,
)?;

View File

@ -1,3 +1,5 @@
use crate::infra::configuration::Configuration;
use super::{
handler::{GroupId, UserId, Uuid},
sql_migrations::{get_schema_version, migrate_from_version, upgrade_to_v1},
@ -62,7 +64,9 @@ pub enum Users {
LastName,
Avatar,
CreationDate,
// Deprecated
PasswordHash,
PasswordHashV2,
TotpSecret,
MfaType,
Uuid,
@ -96,7 +100,7 @@ pub enum Metadata {
Version,
}
pub async fn init_table(pool: &Pool) -> anyhow::Result<()> {
pub async fn init_table(pool: &Pool, config: &Configuration) -> anyhow::Result<()> {
let version = {
if let Some(version) = get_schema_version(pool).await {
version
@ -105,20 +109,27 @@ pub async fn init_table(pool: &Pool) -> anyhow::Result<()> {
SchemaVersion(1)
}
};
migrate_from_version(pool, version).await?;
migrate_from_version(pool, version, config).await?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::infra::configuration::ConfigurationBuilder;
use chrono::prelude::*;
use sqlx::{Column, Row};
async fn init_tables_for_test(pool: &Pool) {
init_table(&pool, &ConfigurationBuilder::for_tests())
.await
.unwrap();
}
#[tokio::test]
async fn test_init_table() {
let sql_pool = PoolOptions::new().connect("sqlite::memory:").await.unwrap();
init_table(&sql_pool).await.unwrap();
init_tables_for_test(&sql_pool).await;
sqlx::query(r#"INSERT INTO users
(user_id, email, display_name, first_name, last_name, creation_date, password_hash, uuid)
VALUES ("bôb", "böb@bob.bob", "Bob Bobbersön", "Bob", "Bobberson", "1970-01-01 00:00:00", "bob00", "abc")"#).execute(&sql_pool).await.unwrap();
@ -138,8 +149,8 @@ mod tests {
#[tokio::test]
async fn test_already_init_table() {
let sql_pool = PoolOptions::new().connect("sqlite::memory:").await.unwrap();
init_table(&sql_pool).await.unwrap();
init_table(&sql_pool).await.unwrap();
init_tables_for_test(&sql_pool).await;
init_tables_for_test(&sql_pool).await;
}
#[tokio::test]
@ -168,7 +179,7 @@ mod tests {
.execute(&sql_pool)
.await
.unwrap();
init_table(&sql_pool).await.unwrap();
init_tables_for_test(&sql_pool).await;
sqlx::query(
r#"INSERT INTO groups (display_name, creation_date, uuid)
VALUES ("test", "1970-01-01 00:00:00", "abc")"#,
@ -210,7 +221,7 @@ mod tests {
.fetch_one(&sql_pool)
.await
.unwrap(),
SchemaVersion(1)
SchemaVersion(2)
);
}
@ -228,6 +239,8 @@ mod tests {
.execute(&sql_pool)
.await
.unwrap();
assert!(init_table(&sql_pool).await.is_err());
assert!(init_table(&sql_pool, &ConfigurationBuilder::for_tests())
.await
.is_err());
}
}

View File

@ -17,7 +17,6 @@ use crate::{
},
infra::auth_service::{Permission, ValidationResults},
};
use anyhow::Result;
use ldap3_proto::proto::{
LdapAddRequest, LdapBindCred, LdapBindRequest, LdapBindResponse, LdapExtendedRequest,
LdapExtendedResponse, LdapFilter, LdapOp, LdapPartialAttribute, LdapPasswordModifyRequest,
@ -238,29 +237,6 @@ impl<Backend: BackendHandler + LoginHandler + OpaqueHandler> LdapHandler<Backend
}
}
async fn change_password(&mut self, user: &UserId, password: &str) -> Result<()> {
use lldap_auth::*;
let mut rng = rand::rngs::OsRng;
let registration_start_request =
opaque::client::registration::start_registration(password, &mut rng)?;
let req = registration::ClientRegistrationStartRequest {
username: user.to_string(),
registration_start_request: registration_start_request.message,
};
let registration_start_response = self.backend_handler.registration_start(req).await?;
let registration_finish = opaque::client::registration::finish_registration(
registration_start_request.state,
registration_start_response.registration_response,
&mut rng,
)?;
let req = registration::ClientRegistrationFinishRequest {
server_data: registration_start_response.server_data,
registration_upload: registration_finish.message,
};
self.backend_handler.registration_finish(req).await?;
Ok(())
}
async fn do_password_modification(
&mut self,
request: &LdapPasswordModifyRequest,
@ -298,7 +274,14 @@ impl<Backend: BackendHandler + LoginHandler + OpaqueHandler> LdapHandler<Backend
&credentials.user, &uid
),
})
} else if let Err(e) = self.change_password(&uid, password).await {
} else if let Err(e) = self
.backend_handler
.set_password(BindRequest {
name: uid,
password: password.to_owned(),
})
.await
{
Err(LdapError {
code: LdapResultCode::Other,
message: format!("Error while changing the password: {:#?}", e),
@ -587,6 +570,7 @@ mod tests {
#[async_trait]
impl LoginHandler for TestBackendHandler {
async fn bind(&self, request: BindRequest) -> Result<()>;
async fn set_password(&self, request: BindRequest) -> Result<()>;
}
#[async_trait]
impl GroupBackendHandler for TestBackendHandler {
@ -1815,28 +1799,12 @@ mod tests {
mock.expect_get_user_groups()
.with(eq(UserId::new("bob")))
.returning(|_| Ok(HashSet::new()));
use lldap_auth::*;
let mut rng = rand::rngs::OsRng;
let registration_start_request =
opaque::client::registration::start_registration("password", &mut rng).unwrap();
let request = registration::ClientRegistrationStartRequest {
username: "bob".to_string(),
registration_start_request: registration_start_request.message,
};
let start_response = opaque::server::registration::start_registration(
&opaque::server::ServerSetup::new(&mut rng),
request.registration_start_request,
&request.username,
)
.unwrap();
mock.expect_registration_start().times(1).return_once(|_| {
Ok(registration::ServerRegistrationStartResponse {
server_data: "".to_string(),
registration_response: start_response.message,
})
});
mock.expect_registration_finish()
mock.expect_set_password()
.times(1)
.with(eq(BindRequest {
name: UserId::new("bob"),
password: "password".to_owned(),
}))
.return_once(|_| Ok(()));
let mut ldap_handler = setup_bound_admin_handler(mock).await;
let request = LdapOp::ExtendedRequest(
@ -1862,28 +1830,12 @@ mod tests {
mock.expect_get_user_groups()
.with(eq(UserId::new("bob")))
.returning(|_| Ok(HashSet::new()));
use lldap_auth::*;
let mut rng = rand::rngs::OsRng;
let registration_start_request =
opaque::client::registration::start_registration("password", &mut rng).unwrap();
let request = registration::ClientRegistrationStartRequest {
username: "bob".to_string(),
registration_start_request: registration_start_request.message,
};
let start_response = opaque::server::registration::start_registration(
&opaque::server::ServerSetup::new(&mut rng),
request.registration_start_request,
&request.username,
)
.unwrap();
mock.expect_registration_start().times(1).return_once(|_| {
Ok(registration::ServerRegistrationStartResponse {
server_data: "".to_string(),
registration_response: start_response.message,
})
});
mock.expect_registration_finish()
mock.expect_set_password()
.times(1)
.with(eq(BindRequest {
name: UserId::new("bob"),
password: "password".to_owned(),
}))
.return_once(|_| Ok(()));
let mut ldap_handler = setup_bound_password_manager_handler(mock).await;
let request = LdapOp::ExtendedRequest(

View File

@ -32,6 +32,7 @@ mockall::mock! {
#[async_trait]
impl LoginHandler for TestTcpBackendHandler {
async fn bind(&self, request: BindRequest) -> Result<()>;
async fn set_password(&self, request: BindRequest) -> Result<()>;
}
#[async_trait]
impl GroupBackendHandler for TestTcpBackendHandler {

View File

@ -58,7 +58,7 @@ async fn set_up_server(config: Configuration) -> Result<ServerBuilder> {
.connect(&config.database_url)
.await
.context("while connecting to the DB")?;
domain::sql_tables::init_table(&sql_pool)
domain::sql_tables::init_table(&sql_pool, &config)
.await
.context("while creating the tables")?;
let backend_handler = SqlBackendHandler::new(config.clone(), sql_pool.clone());