Compare commits
5 Commits
818cfc94c2
...
be40c05b56
Author | SHA1 | Date |
---|---|---|
|
be40c05b56 | |
|
b945d0f142 | |
|
cd7a7272ef | |
|
94ae6f727e | |
|
839d756a28 |
|
@ -61,6 +61,21 @@ dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "android-tzdata"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "android_system_properties"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "argh"
|
name = "argh"
|
||||||
version = "0.1.12"
|
version = "0.1.12"
|
||||||
|
@ -324,6 +339,21 @@ dependencies = [
|
||||||
"cpufeatures",
|
"cpufeatures",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.31"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
|
||||||
|
dependencies = [
|
||||||
|
"android-tzdata",
|
||||||
|
"iana-time-zone",
|
||||||
|
"js-sys",
|
||||||
|
"num-traits",
|
||||||
|
"serde",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cipher"
|
name = "cipher"
|
||||||
version = "0.4.4"
|
version = "0.4.4"
|
||||||
|
@ -340,6 +370,22 @@ version = "0.9.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f"
|
checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation"
|
||||||
|
version = "0.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation-sys"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpufeatures"
|
name = "cpufeatures"
|
||||||
version = "0.2.11"
|
version = "0.2.11"
|
||||||
|
@ -394,6 +440,7 @@ dependencies = [
|
||||||
"platforms",
|
"platforms",
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
"subtle",
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -407,6 +454,41 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling"
|
||||||
|
version = "0.20.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"darling_macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_core"
|
||||||
|
version = "0.20.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621"
|
||||||
|
dependencies = [
|
||||||
|
"fnv",
|
||||||
|
"ident_case",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"strsim",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_macro"
|
||||||
|
version = "0.20.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dashmap"
|
name = "dashmap"
|
||||||
version = "5.5.3"
|
version = "5.5.3"
|
||||||
|
@ -414,7 +496,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
|
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"hashbrown",
|
"hashbrown 0.14.2",
|
||||||
"lock_api",
|
"lock_api",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"parking_lot_core",
|
"parking_lot_core",
|
||||||
|
@ -427,9 +509,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c"
|
checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"const-oid",
|
"const-oid",
|
||||||
|
"pem-rfc7468",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "deranged"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3"
|
||||||
|
dependencies = [
|
||||||
|
"powerfmt",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
version = "0.10.7"
|
version = "0.10.7"
|
||||||
|
@ -463,6 +556,12 @@ dependencies = [
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dyn-clone"
|
||||||
|
version = "1.0.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ecdsa"
|
name = "ecdsa"
|
||||||
version = "0.16.8"
|
version = "0.16.8"
|
||||||
|
@ -483,6 +582,7 @@ version = "2.2.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53"
|
checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"pkcs8",
|
||||||
"signature",
|
"signature",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -494,9 +594,17 @@ checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"curve25519-dalek",
|
"curve25519-dalek",
|
||||||
"ed25519",
|
"ed25519",
|
||||||
|
"serde",
|
||||||
"sha2",
|
"sha2",
|
||||||
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "elliptic-curve"
|
name = "elliptic-curve"
|
||||||
version = "0.13.6"
|
version = "0.13.6"
|
||||||
|
@ -509,6 +617,8 @@ dependencies = [
|
||||||
"ff",
|
"ff",
|
||||||
"generic-array",
|
"generic-array",
|
||||||
"group",
|
"group",
|
||||||
|
"hkdf",
|
||||||
|
"pem-rfc7468",
|
||||||
"pkcs8",
|
"pkcs8",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
"sec1",
|
"sec1",
|
||||||
|
@ -569,6 +679,21 @@ version = "1.0.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||||
|
dependencies = [
|
||||||
|
"foreign-types-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types-shared"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "form-data-builder"
|
name = "form-data-builder"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
|
@ -683,8 +808,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
"js-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi",
|
||||||
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -714,6 +841,31 @@ dependencies = [
|
||||||
"subtle",
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "h2"
|
||||||
|
version = "0.3.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"fnv",
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"indexmap 2.1.0",
|
||||||
|
"slab",
|
||||||
|
"tokio",
|
||||||
|
"tokio-util",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.14.2"
|
version = "0.14.2"
|
||||||
|
@ -744,6 +896,27 @@ dependencies = [
|
||||||
"http",
|
"http",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hkdf"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437"
|
||||||
|
dependencies = [
|
||||||
|
"hmac",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hmac"
|
name = "hmac"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
|
@ -797,6 +970,7 @@ dependencies = [
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
|
"h2",
|
||||||
"http",
|
"http",
|
||||||
"http-body",
|
"http-body",
|
||||||
"httparse",
|
"httparse",
|
||||||
|
@ -810,6 +984,69 @@ dependencies = [
|
||||||
"want",
|
"want",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper-tls"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"hyper",
|
||||||
|
"native-tls",
|
||||||
|
"tokio",
|
||||||
|
"tokio-native-tls",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone"
|
||||||
|
version = "0.1.58"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20"
|
||||||
|
dependencies = [
|
||||||
|
"android_system_properties",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"iana-time-zone-haiku",
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"windows-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone-haiku"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ident_case"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "idna"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-bidi",
|
||||||
|
"unicode-normalization",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "1.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"hashbrown 0.12.3",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
|
@ -817,7 +1054,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown",
|
"hashbrown 0.14.2",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -830,6 +1068,21 @@ dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ipnet"
|
||||||
|
version = "2.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.10.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.9"
|
version = "1.0.9"
|
||||||
|
@ -976,6 +1229,24 @@ dependencies = [
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "native-tls"
|
||||||
|
version = "0.2.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"openssl",
|
||||||
|
"openssl-probe",
|
||||||
|
"openssl-sys",
|
||||||
|
"schannel",
|
||||||
|
"security-framework",
|
||||||
|
"security-framework-sys",
|
||||||
|
"tempfile",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-ansi-term"
|
name = "nu-ansi-term"
|
||||||
version = "0.46.0"
|
version = "0.46.0"
|
||||||
|
@ -1034,6 +1305,36 @@ dependencies = [
|
||||||
"libm",
|
"libm",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_cpus"
|
||||||
|
version = "1.16.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "oauth2"
|
||||||
|
version = "4.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c38841cdd844847e3e7c8d29cef9dcfed8877f8f56f9071f77843ecf3baf937f"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.13.1",
|
||||||
|
"chrono",
|
||||||
|
"getrandom",
|
||||||
|
"http",
|
||||||
|
"rand",
|
||||||
|
"reqwest",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_path_to_error",
|
||||||
|
"sha2",
|
||||||
|
"thiserror",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "object"
|
name = "object"
|
||||||
version = "0.32.1"
|
version = "0.32.1"
|
||||||
|
@ -1055,12 +1356,97 @@ version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openidconnect"
|
||||||
|
version = "3.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62d6050f6a84b81f23c569f5607ad883293e57491036e318fafe6fc4895fadb1"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.13.1",
|
||||||
|
"chrono",
|
||||||
|
"dyn-clone",
|
||||||
|
"ed25519-dalek",
|
||||||
|
"hmac",
|
||||||
|
"http",
|
||||||
|
"itertools",
|
||||||
|
"log",
|
||||||
|
"oauth2",
|
||||||
|
"p256",
|
||||||
|
"p384",
|
||||||
|
"rand",
|
||||||
|
"rsa",
|
||||||
|
"serde",
|
||||||
|
"serde-value",
|
||||||
|
"serde_derive",
|
||||||
|
"serde_json",
|
||||||
|
"serde_path_to_error",
|
||||||
|
"serde_plain",
|
||||||
|
"serde_with",
|
||||||
|
"sha2",
|
||||||
|
"subtle",
|
||||||
|
"thiserror",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl"
|
||||||
|
version = "0.10.59"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a257ad03cd8fb16ad4172fedf8094451e1af1c4b70097636ef2eac9a5f0cc33"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.4.1",
|
||||||
|
"cfg-if",
|
||||||
|
"foreign-types",
|
||||||
|
"libc",
|
||||||
|
"once_cell",
|
||||||
|
"openssl-macros",
|
||||||
|
"openssl-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-macros"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-probe"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-sys"
|
||||||
|
version = "0.9.95"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
"vcpkg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "option-ext"
|
name = "option-ext"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ordered-float"
|
||||||
|
version = "2.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "overload"
|
name = "overload"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
@ -1237,6 +1623,12 @@ dependencies = [
|
||||||
"universal-hash",
|
"universal-hash",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "powerfmt"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.17"
|
version = "0.2.17"
|
||||||
|
@ -1364,6 +1756,44 @@ version = "0.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "reqwest"
|
||||||
|
version = "0.11.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.21.5",
|
||||||
|
"bytes",
|
||||||
|
"encoding_rs",
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"h2",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"hyper",
|
||||||
|
"hyper-tls",
|
||||||
|
"ipnet",
|
||||||
|
"js-sys",
|
||||||
|
"log",
|
||||||
|
"mime",
|
||||||
|
"native-tls",
|
||||||
|
"once_cell",
|
||||||
|
"percent-encoding",
|
||||||
|
"pin-project-lite",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_urlencoded",
|
||||||
|
"system-configuration",
|
||||||
|
"tokio",
|
||||||
|
"tokio-native-tls",
|
||||||
|
"tower-service",
|
||||||
|
"url",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"wasm-bindgen-futures",
|
||||||
|
"web-sys",
|
||||||
|
"winreg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rfc6979"
|
name = "rfc6979"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
@ -1450,6 +1880,15 @@ version = "1.0.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "schannel"
|
||||||
|
version = "0.1.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
|
@ -1470,6 +1909,29 @@ dependencies = [
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "security-framework"
|
||||||
|
version = "2.9.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"core-foundation",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
"security-framework-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "security-framework-sys"
|
||||||
|
version = "2.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "1.0.20"
|
version = "1.0.20"
|
||||||
|
@ -1485,6 +1947,16 @@ dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde-value"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c"
|
||||||
|
dependencies = [
|
||||||
|
"ordered-float",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.190"
|
version = "1.0.190"
|
||||||
|
@ -1517,6 +1989,15 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_plain"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ce1fc6db65a611022b23a0dec6975d63fb80a302cb3388835ff02c097258d50"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_spanned"
|
name = "serde_spanned"
|
||||||
version = "0.6.4"
|
version = "0.6.4"
|
||||||
|
@ -1538,6 +2019,35 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_with"
|
||||||
|
version = "3.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.21.5",
|
||||||
|
"chrono",
|
||||||
|
"hex",
|
||||||
|
"indexmap 1.9.3",
|
||||||
|
"indexmap 2.1.0",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_with_macros",
|
||||||
|
"time",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_with_macros"
|
||||||
|
version = "3.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788"
|
||||||
|
dependencies = [
|
||||||
|
"darling",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serial_test"
|
name = "serial_test"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
|
@ -1731,6 +2241,7 @@ dependencies = [
|
||||||
"form-data-builder",
|
"form-data-builder",
|
||||||
"hyper",
|
"hyper",
|
||||||
"jsonwebtoken",
|
"jsonwebtoken",
|
||||||
|
"openidconnect",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
@ -1746,6 +2257,12 @@ dependencies = [
|
||||||
"virt",
|
"virt",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "subtle"
|
name = "subtle"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
|
@ -1769,6 +2286,27 @@ version = "0.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
|
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "system-configuration"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"core-foundation",
|
||||||
|
"system-configuration-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "system-configuration-sys"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.8.1"
|
version = "3.8.1"
|
||||||
|
@ -1812,6 +2350,50 @@ dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5"
|
||||||
|
dependencies = [
|
||||||
|
"deranged",
|
||||||
|
"itoa",
|
||||||
|
"powerfmt",
|
||||||
|
"serde",
|
||||||
|
"time-core",
|
||||||
|
"time-macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time-core"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time-macros"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20"
|
||||||
|
dependencies = [
|
||||||
|
"time-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyvec"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
|
||||||
|
dependencies = [
|
||||||
|
"tinyvec_macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyvec_macros"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.33.0"
|
version = "1.33.0"
|
||||||
|
@ -1822,6 +2404,7 @@ dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"libc",
|
"libc",
|
||||||
"mio",
|
"mio",
|
||||||
|
"num_cpus",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
"socket2 0.5.5",
|
"socket2 0.5.5",
|
||||||
|
@ -1840,6 +2423,30 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-native-tls"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
|
||||||
|
dependencies = [
|
||||||
|
"native-tls",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-util"
|
||||||
|
version = "0.7.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tokio",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.8.6"
|
version = "0.8.6"
|
||||||
|
@ -1867,7 +2474,7 @@ version = "0.20.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81"
|
checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap 2.1.0",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
|
@ -1976,12 +2583,27 @@ version = "1.17.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-bidi"
|
||||||
|
version = "0.3.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.12"
|
version = "1.0.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-normalization"
|
||||||
|
version = "0.1.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
|
||||||
|
dependencies = [
|
||||||
|
"tinyvec",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "universal-hash"
|
name = "universal-hash"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
@ -1998,6 +2620,18 @@ version = "0.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "url"
|
||||||
|
version = "2.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5"
|
||||||
|
dependencies = [
|
||||||
|
"form_urlencoded",
|
||||||
|
"idna",
|
||||||
|
"percent-encoding",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
|
@ -2010,6 +2644,12 @@ version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vcpkg"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
|
@ -2076,6 +2716,18 @@ dependencies = [
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-futures"
|
||||||
|
version = "0.4.38"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"web-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.88"
|
version = "0.2.88"
|
||||||
|
@ -2137,6 +2789,15 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-core"
|
||||||
|
version = "0.51.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
|
@ -2212,6 +2873,16 @@ dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winreg"
|
||||||
|
version = "0.50.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zeroize"
|
name = "zeroize"
|
||||||
version = "1.6.0"
|
version = "1.6.0"
|
||||||
|
|
|
@ -9,6 +9,7 @@ argon2 = { version = "0.5.2", default-features = false, features = ["alloc"] }
|
||||||
axum = { version = "0.6.20", features = ["multipart", "headers", "json"] }
|
axum = { version = "0.6.20", features = ["multipart", "headers", "json"] }
|
||||||
dirs = "5.0.1"
|
dirs = "5.0.1"
|
||||||
jsonwebtoken = { version = "8.3.0", default-features = false }
|
jsonwebtoken = { version = "8.3.0", default-features = false }
|
||||||
|
openidconnect = { version = "3.4.0", default-features = false, features = ["native-tls", "reqwest"] }
|
||||||
rand_core = { version = "0.6.4", features = ["getrandom"] }
|
rand_core = { version = "0.6.4", features = ["getrandom"] }
|
||||||
serde = { version = "1.0.190", features = ["derive"] }
|
serde = { version = "1.0.190", features = ["derive"] }
|
||||||
serde_json = "1.0.108"
|
serde_json = "1.0.108"
|
||||||
|
|
17
src/auth.rs
17
src/auth.rs
|
@ -19,7 +19,7 @@ use uuid::Uuid;
|
||||||
|
|
||||||
/// JWT Token Claims
|
/// JWT Token Claims
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct Claims {
|
pub struct HostClaims {
|
||||||
/// Token subject (machine hostname)
|
/// Token subject (machine hostname)
|
||||||
pub sub: String,
|
pub sub: String,
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ pub fn get_token_subject(token: &str) -> Result<String> {
|
||||||
v.insecure_disable_signature_validation();
|
v.insecure_disable_signature_validation();
|
||||||
v.set_required_spec_claims(&["sub"]);
|
v.set_required_spec_claims(&["sub"]);
|
||||||
let k = DecodingKey::from_secret(b"");
|
let k = DecodingKey::from_secret(b"");
|
||||||
let data: TokenData<Claims> = decode(token, &k, &v)?;
|
let data: TokenData<HostClaims> = decode(token, &k, &v)?;
|
||||||
Ok(data.claims.sub)
|
Ok(data.claims.sub)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,12 +46,12 @@ pub fn get_token_subject(token: &str) -> Result<String> {
|
||||||
/// `service` argument, and is within its validity period (not before/expires).
|
/// `service` argument, and is within its validity period (not before/expires).
|
||||||
/// The token must be signed with HMAC-SHA256 using the host's machine ID as
|
/// The token must be signed with HMAC-SHA256 using the host's machine ID as
|
||||||
/// the secret key.
|
/// the secret key.
|
||||||
pub fn validate_token(
|
pub fn validate_host_token(
|
||||||
token: &str,
|
token: &str,
|
||||||
hostname: &str,
|
hostname: &str,
|
||||||
machine_id: &Uuid,
|
machine_id: &Uuid,
|
||||||
service: &str,
|
service: &str,
|
||||||
) -> Result<Claims> {
|
) -> Result<HostClaims> {
|
||||||
let mut v = Validation::new(Algorithm::HS256);
|
let mut v = Validation::new(Algorithm::HS256);
|
||||||
v.validate_nbf = true;
|
v.validate_nbf = true;
|
||||||
v.set_issuer(&[hostname]);
|
v.set_issuer(&[hostname]);
|
||||||
|
@ -66,7 +66,7 @@ pub fn validate_token(
|
||||||
OsRng.fill_bytes(&mut secret);
|
OsRng.fill_bytes(&mut secret);
|
||||||
}
|
}
|
||||||
let k = DecodingKey::from_secret(&secret);
|
let k = DecodingKey::from_secret(&secret);
|
||||||
let data: TokenData<Claims> = decode(token, &k, &v)?;
|
let data: TokenData<HostClaims> = decode(token, &k, &v)?;
|
||||||
Ok(data.claims)
|
Ok(data.claims)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +130,12 @@ pub(crate) mod test {
|
||||||
|
|
||||||
let machine_id = uuid!("9afd42e5-4ac3-4530-90c4-191869063ef9");
|
let machine_id = uuid!("9afd42e5-4ac3-4530-90c4-191869063ef9");
|
||||||
let token = make_token(hostname, machine_id);
|
let token = make_token(hostname, machine_id);
|
||||||
validate_token(&token, hostname, &machine_id, "sshca.example.org")
|
validate_host_token(
|
||||||
|
&token,
|
||||||
|
hostname,
|
||||||
|
&machine_id,
|
||||||
|
"sshca.example.org",
|
||||||
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
32
src/ca.rs
32
src/ca.rs
|
@ -137,12 +137,38 @@ pub fn parse_public_key(data: &[u8]) -> Result<PublicKey, LoadKeyError> {
|
||||||
/// This function creates a signed certificate for an SSH host public
|
/// This function creates a signed certificate for an SSH host public
|
||||||
/// key. The certificate will be valid for the specified hostname and
|
/// key. The certificate will be valid for the specified hostname and
|
||||||
/// any alias names provided.
|
/// any alias names provided.
|
||||||
pub fn sign_cert(
|
pub fn sign_host_cert(
|
||||||
hostname: &str,
|
hostname: &str,
|
||||||
pubkey: &PublicKey,
|
pubkey: &PublicKey,
|
||||||
duration: Duration,
|
duration: Duration,
|
||||||
privkey: &PrivateKey,
|
privkey: &PrivateKey,
|
||||||
alias: &[&str],
|
alias: &[&str],
|
||||||
|
) -> Result<Certificate, CertError> {
|
||||||
|
sign_cert(hostname, pubkey, duration, privkey, alias, CertType::Host)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a signed SSH certificate for a user public key
|
||||||
|
///
|
||||||
|
/// This function creates a signed certificate for an SSH user public
|
||||||
|
/// key. The certificate will be valid for the specified username and
|
||||||
|
/// any alias names provided.
|
||||||
|
pub fn sign_user_cert(
|
||||||
|
username: &str,
|
||||||
|
pubkey: &PublicKey,
|
||||||
|
duration: Duration,
|
||||||
|
privkey: &PrivateKey,
|
||||||
|
alias: &[&str],
|
||||||
|
) -> Result<Certificate, CertError> {
|
||||||
|
sign_cert(username, pubkey, duration, privkey, alias, CertType::User)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sign_cert(
|
||||||
|
principal: &str,
|
||||||
|
pubkey: &PublicKey,
|
||||||
|
duration: Duration,
|
||||||
|
privkey: &PrivateKey,
|
||||||
|
alias: &[&str],
|
||||||
|
cert_type: CertType,
|
||||||
) -> Result<Certificate, CertError> {
|
) -> Result<Certificate, CertError> {
|
||||||
let now = SystemTime::now();
|
let now = SystemTime::now();
|
||||||
let not_before = now.duration_since(UNIX_EPOCH)?.as_secs();
|
let not_before = now.duration_since(UNIX_EPOCH)?.as_secs();
|
||||||
|
@ -151,8 +177,8 @@ pub fn sign_cert(
|
||||||
let mut builder = Builder::new_with_random_nonce(
|
let mut builder = Builder::new_with_random_nonce(
|
||||||
&mut OsRng, pubkey, not_before, not_after,
|
&mut OsRng, pubkey, not_before, not_after,
|
||||||
)?;
|
)?;
|
||||||
builder.cert_type(CertType::Host)?;
|
builder.cert_type(cert_type)?;
|
||||||
builder.valid_principal(hostname)?;
|
builder.valid_principal(principal)?;
|
||||||
for a in alias {
|
for a in alias {
|
||||||
builder.valid_principal(*a)?;
|
builder.valid_principal(*a)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,11 +65,47 @@ impl Default for HostCaConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct UserCaConfig {
|
||||||
|
/// Path to the User CA private key file
|
||||||
|
#[serde(default = "default_user_ca_key")]
|
||||||
|
pub private_key_file: PathBuf,
|
||||||
|
pub private_key_passphrase_file: Option<PathBuf>,
|
||||||
|
|
||||||
|
/// Duration of issued user certificates
|
||||||
|
#[serde(default = "default_user_cert_duration")]
|
||||||
|
pub cert_duration: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for UserCaConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
private_key_file: default_user_ca_key(),
|
||||||
|
private_key_passphrase_file: None,
|
||||||
|
cert_duration: default_user_cert_duration(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// CA configuration
|
/// CA configuration
|
||||||
#[derive(Debug, Default, Deserialize)]
|
#[derive(Debug, Default, Deserialize)]
|
||||||
pub struct CaConfig {
|
pub struct CaConfig {
|
||||||
/// Host CA configuration
|
/// Host CA configuration
|
||||||
pub host: HostCaConfig,
|
pub host: HostCaConfig,
|
||||||
|
/// User CA configuration
|
||||||
|
pub user: UserCaConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// OpenID Connect configuration
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct OidcConfig {
|
||||||
|
/// OIDC Discovery base URL (without /.well-known/...)
|
||||||
|
pub discovery_url: String,
|
||||||
|
/// OAuth2 client ID
|
||||||
|
pub client_id: String,
|
||||||
|
/// OAuth2 client secret
|
||||||
|
#[serde(default)]
|
||||||
|
pub client_secret: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Defines a connection to a libvirt VM host
|
/// Defines a connection to a libvirt VM host
|
||||||
|
@ -91,6 +127,9 @@ pub struct Configuration {
|
||||||
/// CA configuration
|
/// CA configuration
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub ca: CaConfig,
|
pub ca: CaConfig,
|
||||||
|
/// OpenID Connect configuration for user authorization
|
||||||
|
#[serde(default)]
|
||||||
|
pub oidc: Option<OidcConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Configuration {
|
impl Default for Configuration {
|
||||||
|
@ -99,6 +138,7 @@ impl Default for Configuration {
|
||||||
libvirt: vec![],
|
libvirt: vec![],
|
||||||
machine_ids: default_machine_ids(),
|
machine_ids: default_machine_ids(),
|
||||||
ca: Default::default(),
|
ca: Default::default(),
|
||||||
|
oidc: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,6 +163,14 @@ fn default_host_cert_duration() -> u64 {
|
||||||
86400 * 30
|
86400 * 30
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_user_ca_key() -> PathBuf {
|
||||||
|
default_config_path("user-ca.key")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_user_cert_duration() -> u64 {
|
||||||
|
3600
|
||||||
|
}
|
||||||
|
|
||||||
/// Load configuration from a TOML file
|
/// Load configuration from a TOML file
|
||||||
///
|
///
|
||||||
/// If `path` is provided, the configuration will be loaded from the
|
/// If `path` is provided, the configuration will be loaded from the
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
//! SSHCA HTTP server errors
|
||||||
|
use axum::extract::multipart::MultipartError;
|
||||||
|
use axum::http::StatusCode;
|
||||||
|
use axum::response::{IntoResponse, Response};
|
||||||
|
use tracing::{debug, error};
|
||||||
|
|
||||||
|
use crate::ca;
|
||||||
|
|
||||||
|
/// Error encountered while signing a key
|
||||||
|
pub enum SignKeyError {
|
||||||
|
/// Failed to parse HTTP multipart form request
|
||||||
|
Multipart(MultipartError),
|
||||||
|
/// Error handing SSH certificate
|
||||||
|
Cert(ca::CertError),
|
||||||
|
/// Error loading SSH private key file
|
||||||
|
LoadPrivateKey(ca::LoadKeyError),
|
||||||
|
/// Error parsing SSH public key
|
||||||
|
ParsePublicKey(ca::LoadKeyError),
|
||||||
|
/// Unsupported SSH key algorithm
|
||||||
|
UnsupportedAlgorithm(String),
|
||||||
|
/// No SSH public key included in request
|
||||||
|
NoKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<MultipartError> for SignKeyError {
|
||||||
|
fn from(e: MultipartError) -> Self {
|
||||||
|
Self::Multipart(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ca::CertError> for SignKeyError {
|
||||||
|
fn from(e: ca::CertError) -> Self {
|
||||||
|
Self::Cert(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoResponse for SignKeyError {
|
||||||
|
fn into_response(self) -> Response {
|
||||||
|
match self {
|
||||||
|
Self::Multipart(e) => {
|
||||||
|
debug!("Error reading request: {}", e);
|
||||||
|
let body = e.to_string();
|
||||||
|
(StatusCode::BAD_REQUEST, body).into_response()
|
||||||
|
}
|
||||||
|
Self::Cert(e) => {
|
||||||
|
error!("Failed to sign certificate: {}", e);
|
||||||
|
let body = "Service Unavailable";
|
||||||
|
(StatusCode::SERVICE_UNAVAILABLE, body).into_response()
|
||||||
|
}
|
||||||
|
Self::LoadPrivateKey(e) => {
|
||||||
|
error!("Error loading CA private key: {}", e);
|
||||||
|
let body = "Service Unavailable";
|
||||||
|
(StatusCode::SERVICE_UNAVAILABLE, body).into_response()
|
||||||
|
}
|
||||||
|
Self::ParsePublicKey(e) => {
|
||||||
|
error!("Error parsing public keykey: {}", e);
|
||||||
|
let body = e.to_string();
|
||||||
|
(StatusCode::BAD_REQUEST, body).into_response()
|
||||||
|
}
|
||||||
|
Self::UnsupportedAlgorithm(a) => {
|
||||||
|
debug!("Requested certificate for unsupported key algorithm \"{}\"", a);
|
||||||
|
let body = format!("Unsupported key algorithm: {}", a);
|
||||||
|
(StatusCode::BAD_REQUEST, body).into_response()
|
||||||
|
}
|
||||||
|
Self::NoKey => {
|
||||||
|
debug!("No SSH public key provided in request");
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
"No SSH public key provided in request",
|
||||||
|
)
|
||||||
|
.into_response()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,16 +1,25 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::time::Duration;
|
use std::sync::Arc;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use axum::extract::multipart::{Multipart, MultipartError};
|
use axum::async_trait;
|
||||||
|
use axum::extract::multipart::Multipart;
|
||||||
|
use axum::extract::FromRequestParts;
|
||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use axum::http::StatusCode;
|
use axum::headers::authorization::Bearer;
|
||||||
use axum::response::{IntoResponse, Response};
|
use axum::headers::{Authorization, Host};
|
||||||
|
use axum::http::request::Parts;
|
||||||
|
use axum::{RequestPartsExt, TypedHeader};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use ssh_key::Algorithm;
|
use ssh_key::Algorithm;
|
||||||
use tracing::{debug, error, info, warn};
|
use tracing::{debug, info, warn};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::auth::Claims;
|
use super::error::SignKeyError;
|
||||||
|
use super::{AuthError, Context};
|
||||||
|
use crate::auth::{self, HostClaims};
|
||||||
use crate::ca;
|
use crate::ca;
|
||||||
|
use crate::machine_id;
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct SignKeyResponse {
|
pub struct SignKeyResponse {
|
||||||
|
@ -19,65 +28,68 @@ pub struct SignKeyResponse {
|
||||||
certificates: HashMap<String, String>,
|
certificates: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum SignKeyError {
|
#[async_trait]
|
||||||
Multipart(MultipartError),
|
impl FromRequestParts<Arc<Context>> for HostClaims {
|
||||||
Cert(ca::CertError),
|
type Rejection = AuthError;
|
||||||
LoadPrivateKey(ca::LoadKeyError),
|
|
||||||
ParsePublicKey(ca::LoadKeyError),
|
|
||||||
UnsupportedAlgorithm(String),
|
|
||||||
NoKey,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<MultipartError> for SignKeyError {
|
async fn from_request_parts(
|
||||||
fn from(e: MultipartError) -> Self {
|
parts: &mut Parts,
|
||||||
Self::Multipart(e)
|
ctx: &super::State,
|
||||||
}
|
) -> Result<Self, Self::Rejection> {
|
||||||
}
|
let TypedHeader(Authorization(bearer)) = parts
|
||||||
|
.extract::<TypedHeader<Authorization<Bearer>>>()
|
||||||
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
|
debug!("Failed to extract token from HTTP request: {}", e);
|
||||||
|
AuthError
|
||||||
|
})?;
|
||||||
|
let host = parts.extract::<TypedHeader<Host>>().await.map_or_else(
|
||||||
|
|_| "localhost".to_owned(),
|
||||||
|
|v| v.hostname().to_owned(),
|
||||||
|
);
|
||||||
|
|
||||||
impl From<ca::CertError> for SignKeyError {
|
let hostname =
|
||||||
fn from(e: ca::CertError) -> Self {
|
auth::get_token_subject(bearer.token()).map_err(|e| {
|
||||||
Self::Cert(e)
|
debug!("Could not get token subject: {}", e);
|
||||||
}
|
AuthError
|
||||||
}
|
})?;
|
||||||
|
let machine_id =
|
||||||
impl IntoResponse for SignKeyError {
|
get_machine_id(&hostname, ctx).await.ok_or_else(|| {
|
||||||
fn into_response(self) -> Response {
|
debug!("No machine ID found for host {}", hostname);
|
||||||
match self {
|
AuthError
|
||||||
Self::Multipart(e) => {
|
})?;
|
||||||
debug!("Error reading request: {}", e);
|
let claims = auth::validate_host_token(
|
||||||
let body = e.to_string();
|
bearer.token(),
|
||||||
(StatusCode::BAD_REQUEST, body).into_response()
|
&hostname,
|
||||||
}
|
&machine_id,
|
||||||
Self::Cert(e) => {
|
&host,
|
||||||
error!("Failed to sign certificate: {}", e);
|
|
||||||
let body = "Service Unavailable";
|
|
||||||
(StatusCode::SERVICE_UNAVAILABLE, body).into_response()
|
|
||||||
}
|
|
||||||
Self::LoadPrivateKey(e) => {
|
|
||||||
error!("Error loading CA private key: {}", e);
|
|
||||||
let body = "Service Unavailable";
|
|
||||||
(StatusCode::SERVICE_UNAVAILABLE, body).into_response()
|
|
||||||
}
|
|
||||||
Self::ParsePublicKey(e) => {
|
|
||||||
error!("Error parsing public keykey: {}", e);
|
|
||||||
let body = e.to_string();
|
|
||||||
(StatusCode::BAD_REQUEST, body).into_response()
|
|
||||||
}
|
|
||||||
Self::UnsupportedAlgorithm(a) => {
|
|
||||||
debug!("Requested certificate for unsupported key algorithm \"{}\"", a);
|
|
||||||
let body = format!("Unsupported key algorithm: {}", a);
|
|
||||||
(StatusCode::BAD_REQUEST, body).into_response()
|
|
||||||
}
|
|
||||||
Self::NoKey => {
|
|
||||||
debug!("No SSH public key provided in request");
|
|
||||||
(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
"No SSH public key provided in request",
|
|
||||||
)
|
)
|
||||||
.into_response()
|
.map_err(|e| {
|
||||||
}
|
debug!("Invalid auth token: {}", e);
|
||||||
|
AuthError
|
||||||
|
})?;
|
||||||
|
debug!("Successfully authenticated request from host {}", hostname);
|
||||||
|
Ok(claims)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_machine_id(hostname: &str, ctx: &super::State) -> Option<Uuid> {
|
||||||
|
let cache = ctx.cache.read().await;
|
||||||
|
if let Some((ts, m)) = cache.get(hostname) {
|
||||||
|
if ts.elapsed() < Duration::from_secs(60) {
|
||||||
|
debug!("Found cached machine ID for {}", hostname);
|
||||||
|
return Some(*m);
|
||||||
|
} else {
|
||||||
|
debug!("Cached machine ID for {} has expired", hostname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
drop(cache);
|
||||||
|
let machine_id =
|
||||||
|
machine_id::get_machine_id(hostname, ctx.config.clone()).await?;
|
||||||
|
let mut cache = ctx.cache.write().await;
|
||||||
|
debug!("Caching machine ID for {}", hostname);
|
||||||
|
cache.insert(hostname.into(), (Instant::now(), machine_id));
|
||||||
|
Some(machine_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -87,7 +99,7 @@ struct SignKeyRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn sign_host_cert(
|
pub(super) async fn sign_host_cert(
|
||||||
claims: Claims,
|
claims: HostClaims,
|
||||||
State(ctx): State<super::State>,
|
State(ctx): State<super::State>,
|
||||||
mut form: Multipart,
|
mut form: Multipart,
|
||||||
) -> Result<String, SignKeyError> {
|
) -> Result<String, SignKeyError> {
|
||||||
|
@ -137,7 +149,7 @@ pub(super) async fn sign_host_cert(
|
||||||
hostname
|
hostname
|
||||||
);
|
);
|
||||||
let cert =
|
let cert =
|
||||||
ca::sign_cert(&hostname, &pubkey, duration, &privkey, &[])?;
|
ca::sign_host_cert(&hostname, &pubkey, duration, &privkey, &[])?;
|
||||||
info!(
|
info!(
|
||||||
"Signed {} key for {}",
|
"Signed {} key for {}",
|
||||||
pubkey.algorithm().as_str(),
|
pubkey.algorithm().as_str(),
|
||||||
|
|
|
@ -1,29 +1,25 @@
|
||||||
|
mod error;
|
||||||
mod host;
|
mod host;
|
||||||
|
mod user;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::Instant;
|
||||||
|
|
||||||
use axum::async_trait;
|
|
||||||
use axum::extract::FromRequestParts;
|
|
||||||
use axum::headers::authorization::Bearer;
|
|
||||||
use axum::headers::{Authorization, Host};
|
|
||||||
use axum::http::request::Parts;
|
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum::response::{IntoResponse, Response};
|
use axum::response::{IntoResponse, Response};
|
||||||
use axum::routing::{get, post};
|
use axum::routing::{get, post};
|
||||||
use axum::{RequestPartsExt, Router, TypedHeader};
|
use axum::Router;
|
||||||
|
use openidconnect::core::CoreProviderMetadata;
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
use tracing::debug;
|
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::auth::{self, Claims};
|
|
||||||
use crate::config::Configuration;
|
use crate::config::Configuration;
|
||||||
use crate::machine_id;
|
|
||||||
|
|
||||||
struct Context {
|
struct Context {
|
||||||
config: Arc<Configuration>,
|
config: Arc<Configuration>,
|
||||||
cache: RwLock<HashMap<String, (Instant, Uuid)>>,
|
cache: RwLock<HashMap<String, (Instant, Uuid)>>,
|
||||||
|
oidc: RwLock<Option<(Instant, CoreProviderMetadata)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
type State = Arc<Context>;
|
type State = Arc<Context>;
|
||||||
|
@ -36,81 +32,20 @@ impl IntoResponse for AuthError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl FromRequestParts<Arc<Context>> for Claims {
|
|
||||||
type Rejection = AuthError;
|
|
||||||
|
|
||||||
async fn from_request_parts(
|
|
||||||
parts: &mut Parts,
|
|
||||||
ctx: &State,
|
|
||||||
) -> Result<Self, Self::Rejection> {
|
|
||||||
let TypedHeader(Authorization(bearer)) = parts
|
|
||||||
.extract::<TypedHeader<Authorization<Bearer>>>()
|
|
||||||
.await
|
|
||||||
.map_err(|e| {
|
|
||||||
debug!("Failed to extract token from HTTP request: {}", e);
|
|
||||||
AuthError
|
|
||||||
})?;
|
|
||||||
let host = parts.extract::<TypedHeader<Host>>().await.map_or_else(
|
|
||||||
|_| "localhost".to_owned(),
|
|
||||||
|v| v.hostname().to_owned(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let hostname =
|
|
||||||
auth::get_token_subject(bearer.token()).map_err(|e| {
|
|
||||||
debug!("Could not get token subject: {}", e);
|
|
||||||
AuthError
|
|
||||||
})?;
|
|
||||||
let machine_id =
|
|
||||||
get_machine_id(&hostname, ctx).await.ok_or_else(|| {
|
|
||||||
debug!("No machine ID found for host {}", hostname);
|
|
||||||
AuthError
|
|
||||||
})?;
|
|
||||||
let claims = auth::validate_token(
|
|
||||||
bearer.token(),
|
|
||||||
&hostname,
|
|
||||||
&machine_id,
|
|
||||||
&host,
|
|
||||||
)
|
|
||||||
.map_err(|e| {
|
|
||||||
debug!("Invalid auth token: {}", e);
|
|
||||||
AuthError
|
|
||||||
})?;
|
|
||||||
debug!("Successfully authenticated request from host {}", hostname);
|
|
||||||
Ok(claims)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn make_app(config: Configuration) -> Router {
|
pub fn make_app(config: Configuration) -> Router {
|
||||||
let ctx = Arc::new(Context {
|
let ctx = Arc::new(Context {
|
||||||
config: config.into(),
|
config: config.into(),
|
||||||
cache: RwLock::new(Default::default()),
|
cache: RwLock::new(Default::default()),
|
||||||
|
oidc: Default::default(),
|
||||||
});
|
});
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/", get(|| async { "UP" }))
|
.route("/", get(|| async { "UP" }))
|
||||||
.route("/host/sign", post(host::sign_host_cert))
|
.route("/host/sign", post(host::sign_host_cert))
|
||||||
|
.route("/user/oidc-config", get(user::get_oidc_config))
|
||||||
|
.route("/user/sign", post(user::sign_user_cert))
|
||||||
.with_state(ctx)
|
.with_state(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_machine_id(hostname: &str, ctx: &State) -> Option<Uuid> {
|
|
||||||
let cache = ctx.cache.read().await;
|
|
||||||
if let Some((ts, m)) = cache.get(hostname) {
|
|
||||||
if ts.elapsed() < Duration::from_secs(60) {
|
|
||||||
debug!("Found cached machine ID for {}", hostname);
|
|
||||||
return Some(*m);
|
|
||||||
} else {
|
|
||||||
debug!("Cached machine ID for {} has expired", hostname);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
drop(cache);
|
|
||||||
let machine_id =
|
|
||||||
machine_id::get_machine_id(hostname, ctx.config.clone()).await?;
|
|
||||||
let mut cache = ctx.cache.write().await;
|
|
||||||
debug!("Caching machine ID for {}", hostname);
|
|
||||||
cache.insert(hostname.into(), (Instant::now(), machine_id));
|
|
||||||
Some(machine_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use axum::body::Body;
|
use axum::body::Body;
|
||||||
|
|
|
@ -0,0 +1,244 @@
|
||||||
|
//! User CA operations
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
use axum::async_trait;
|
||||||
|
use axum::extract::multipart::Multipart;
|
||||||
|
use axum::extract::FromRequestParts;
|
||||||
|
use axum::extract::State;
|
||||||
|
use axum::headers::authorization::Bearer;
|
||||||
|
use axum::headers::Authorization;
|
||||||
|
use axum::http::request::Parts;
|
||||||
|
use axum::Json;
|
||||||
|
use axum::{RequestPartsExt, TypedHeader};
|
||||||
|
use openidconnect::core::{CoreClient, CoreProviderMetadata};
|
||||||
|
use openidconnect::core::{CoreIdToken, CoreIdTokenClaims};
|
||||||
|
use openidconnect::reqwest::async_http_client;
|
||||||
|
use openidconnect::IssuerUrl;
|
||||||
|
use openidconnect::Nonce;
|
||||||
|
use openidconnect::{ClientId, ClientSecret};
|
||||||
|
use serde::Serialize;
|
||||||
|
use ssh_key::Algorithm;
|
||||||
|
use tracing::{debug, error, info, trace, warn};
|
||||||
|
|
||||||
|
use super::error::SignKeyError;
|
||||||
|
use super::{AuthError, Context};
|
||||||
|
use crate::ca;
|
||||||
|
|
||||||
|
/// Response type for GET /user/openid-config
|
||||||
|
///
|
||||||
|
/// This structure contains OpenID configuration information for
|
||||||
|
/// client utilities.
|
||||||
|
#[derive(Debug, Default, Serialize)]
|
||||||
|
pub struct OidcConfigResponse {
|
||||||
|
url: Option<String>,
|
||||||
|
client_id: Option<String>,
|
||||||
|
client_secret: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// OpenID Connect ID token claims
|
||||||
|
pub struct Claims(CoreIdTokenClaims);
|
||||||
|
|
||||||
|
/// Axum request extractor for OIDC ID tokens in Authorization headers
|
||||||
|
///
|
||||||
|
/// This extractor parses an OpenID Connect identity token (as a JWT)
|
||||||
|
/// from the `Authorization` HTTP request header. If the token is
|
||||||
|
/// valid, a [`Claims`] structure is returned. If the token is not
|
||||||
|
/// valid (e.g. signed by an untrusted key, expired, for a different
|
||||||
|
/// audience, etc), [`AuthError`] is returned.
|
||||||
|
#[async_trait]
|
||||||
|
impl FromRequestParts<Arc<Context>> for Claims {
|
||||||
|
type Rejection = AuthError;
|
||||||
|
|
||||||
|
async fn from_request_parts(
|
||||||
|
parts: &mut Parts,
|
||||||
|
ctx: &super::State,
|
||||||
|
) -> Result<Self, Self::Rejection> {
|
||||||
|
let config = &ctx.config;
|
||||||
|
let oidc_config = &config.oidc.as_ref().ok_or_else(|| {
|
||||||
|
warn!("OpenID Connect not configured");
|
||||||
|
AuthError
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let TypedHeader(Authorization(bearer)) = parts
|
||||||
|
.extract::<TypedHeader<Authorization<Bearer>>>()
|
||||||
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
|
debug!("Failed to extract token from HTTP request: {}", e);
|
||||||
|
AuthError
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let token = CoreIdToken::from_str(bearer.token()).map_err(|e| {
|
||||||
|
debug!("Failed to parse OIDC ID token: {}", e);
|
||||||
|
AuthError
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let client_id = &oidc_config.client_id;
|
||||||
|
let client_secret = &oidc_config.client_secret;
|
||||||
|
let provider_metadata = get_metadata(ctx).await.ok_or(AuthError)?;
|
||||||
|
let client = CoreClient::from_provider_metadata(
|
||||||
|
provider_metadata,
|
||||||
|
ClientId::new(client_id.into()),
|
||||||
|
client_secret.as_ref().map(|s| ClientSecret::new(s.into())),
|
||||||
|
);
|
||||||
|
let verifier = client.id_token_verifier();
|
||||||
|
let claims = token
|
||||||
|
// Ignore the token nonce, as we have no way of validating it.
|
||||||
|
.into_claims(&verifier, |_: Option<&Nonce>| Ok(()))
|
||||||
|
.map_err(|e| {
|
||||||
|
debug!("Invalid ID token: {}", e);
|
||||||
|
AuthError
|
||||||
|
})?;
|
||||||
|
trace!("Token Claims: {:?}", claims);
|
||||||
|
debug!(
|
||||||
|
"Successfully authorized user {} (issuer {})",
|
||||||
|
claims.subject().as_str(),
|
||||||
|
claims.issuer().as_str()
|
||||||
|
);
|
||||||
|
Ok(Claims(claims))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve OpenID Connect client configuration
|
||||||
|
///
|
||||||
|
/// Clients can access this resource to determine the appropriate
|
||||||
|
/// configuration for the OpenID Connect identity provider where they
|
||||||
|
/// can obtain identity tokens.
|
||||||
|
pub(super) async fn get_oidc_config(
|
||||||
|
State(ctx): State<super::State>,
|
||||||
|
) -> Json<OidcConfigResponse> {
|
||||||
|
let config = &ctx.config;
|
||||||
|
let res = if let Some(oidc) = &config.oidc {
|
||||||
|
OidcConfigResponse {
|
||||||
|
url: Some(oidc.discovery_url.clone()),
|
||||||
|
client_id: Some(oidc.client_id.clone()),
|
||||||
|
client_secret: oidc.client_secret.clone(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Default::default()
|
||||||
|
};
|
||||||
|
Json(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// User SSH key signing request payload
|
||||||
|
#[derive(Default)]
|
||||||
|
struct SignKeyRequest {
|
||||||
|
/// Public keys to sign
|
||||||
|
pubkey: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handler for user certificate signing requests
|
||||||
|
///
|
||||||
|
/// An SSH user certificate will be signed for each submitted public
|
||||||
|
/// key. The valid principals on the certificates will be taken from
|
||||||
|
/// the OpenID Connect Identity Token in the Authorization header, via
|
||||||
|
/// the `sub`, `perferred_username`, and `email` claims (if present).
|
||||||
|
pub(super) async fn sign_user_cert(
|
||||||
|
Claims(claims): Claims,
|
||||||
|
State(ctx): State<super::State>,
|
||||||
|
mut form: Multipart,
|
||||||
|
) -> Result<String, SignKeyError> {
|
||||||
|
let username = claims.subject().as_str();
|
||||||
|
let mut body = SignKeyRequest::default();
|
||||||
|
|
||||||
|
while let Some(field) = form.next_field().await? {
|
||||||
|
match field.name() {
|
||||||
|
Some("pubkey") => {
|
||||||
|
body.pubkey = field.bytes().await?.into();
|
||||||
|
}
|
||||||
|
Some(n) => {
|
||||||
|
warn!("Client request included unsupported field {:?}", n);
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if body.pubkey.is_empty() {
|
||||||
|
return Err(SignKeyError::NoKey);
|
||||||
|
}
|
||||||
|
let mut alias = vec![];
|
||||||
|
if let Some(username) = claims.preferred_username() {
|
||||||
|
alias.push(username.as_str());
|
||||||
|
}
|
||||||
|
if let Some(email) = claims.email() {
|
||||||
|
if claims.email_verified() == Some(true) {
|
||||||
|
alias.push(email.as_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let config = &ctx.config;
|
||||||
|
let duration = Duration::from_secs(config.ca.user.cert_duration);
|
||||||
|
let privkey = ca::load_private_key(
|
||||||
|
&config.ca.user.private_key_file,
|
||||||
|
config.ca.user.private_key_passphrase_file.as_ref(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(SignKeyError::LoadPrivateKey)?;
|
||||||
|
|
||||||
|
let pubkey = ca::parse_public_key(&body.pubkey)
|
||||||
|
.map_err(SignKeyError::ParsePublicKey)?;
|
||||||
|
match pubkey.algorithm() {
|
||||||
|
Algorithm::Ecdsa { .. } => (),
|
||||||
|
Algorithm::Ed25519 => (),
|
||||||
|
Algorithm::Rsa { .. } => (),
|
||||||
|
_ => {
|
||||||
|
return Err(SignKeyError::UnsupportedAlgorithm(
|
||||||
|
pubkey.algorithm().as_str().into(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
debug!(
|
||||||
|
"Signing {} key for {}",
|
||||||
|
pubkey.algorithm().as_str(),
|
||||||
|
username
|
||||||
|
);
|
||||||
|
let cert = ca::sign_user_cert(username, &pubkey, duration, &privkey, &alias)?;
|
||||||
|
info!(
|
||||||
|
"Signed {} key for {}",
|
||||||
|
pubkey.algorithm().as_str(),
|
||||||
|
username
|
||||||
|
);
|
||||||
|
Ok(cert.to_openssh().map_err(ca::CertError::from)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get OIDC provider metadata (possibly from cache)
|
||||||
|
///
|
||||||
|
/// This function will return metadata for the configured OIDC identity
|
||||||
|
/// provider. When called for the first time, it will initiate an
|
||||||
|
/// HTTP request to the provider's OpenID Provider Configuration
|
||||||
|
/// Document (i.e. `/.well-known/openid-configuration`). The result is
|
||||||
|
/// cached for 1 hour, so subsequent calls to this function will not
|
||||||
|
/// initiate another HTTP request, unless more than 1 hour has passed
|
||||||
|
/// since the first request.
|
||||||
|
///
|
||||||
|
/// If an error occurs while attempting to fetch the metadata, `None`
|
||||||
|
/// is returned.
|
||||||
|
async fn get_metadata(ctx: &super::State) -> Option<CoreProviderMetadata> {
|
||||||
|
let cache = ctx.oidc.read().await;
|
||||||
|
if let Some((ts, m)) = &*cache {
|
||||||
|
if ts.elapsed() < Duration::from_secs(3600) {
|
||||||
|
debug!("Using cached OIDC provider metadata");
|
||||||
|
return Some(m.clone());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let oidc_url = &ctx.config.oidc.as_ref()?.discovery_url;
|
||||||
|
debug!("Fetching OIDC provider metadata");
|
||||||
|
let metadata = CoreProviderMetadata::discover_async(
|
||||||
|
IssuerUrl::new(oidc_url.into()).unwrap(),
|
||||||
|
async_http_client,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
match metadata {
|
||||||
|
Ok(m) => {
|
||||||
|
drop(cache);
|
||||||
|
debug!("Caching OIDC provider metadata");
|
||||||
|
let mut cache = ctx.oidc.write().await;
|
||||||
|
(*cache).replace((Instant::now(), m.clone()));
|
||||||
|
Some(m)
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to get OIDC provider metadata: {}", e);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,7 +8,7 @@ use ssh_key::{Algorithm, Fingerprint, PrivateKey, PublicKey};
|
||||||
use tempfile::NamedTempFile;
|
use tempfile::NamedTempFile;
|
||||||
use tracing_subscriber::EnvFilter;
|
use tracing_subscriber::EnvFilter;
|
||||||
|
|
||||||
use sshca::config::Configuration;
|
use sshca::config::{Configuration, OidcConfig};
|
||||||
|
|
||||||
static INIT: Once = Once::new();
|
static INIT: Once = Once::new();
|
||||||
|
|
||||||
|
@ -24,6 +24,11 @@ fn gen_machine_ids() -> Result<NamedTempFile, Box<dyn Error>> {
|
||||||
fn gen_config(machine_ids: &Path, host_key: &Path) -> Configuration {
|
fn gen_config(machine_ids: &Path, host_key: &Path) -> Configuration {
|
||||||
let mut config = Configuration {
|
let mut config = Configuration {
|
||||||
machine_ids: machine_ids.to_str().unwrap().into(),
|
machine_ids: machine_ids.to_str().unwrap().into(),
|
||||||
|
oidc: Some(OidcConfig {
|
||||||
|
discovery_url: "https://auth.example.org".into(),
|
||||||
|
client_id: "sshca".into(),
|
||||||
|
client_secret: None,
|
||||||
|
}),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
config.ca.host.private_key_file = host_key.to_str().unwrap().into();
|
config.ca.host.private_key_file = host_key.to_str().unwrap().into();
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
mod common;
|
||||||
|
|
||||||
|
use axum::body::Body;
|
||||||
|
use axum::http::{Request, StatusCode};
|
||||||
|
use tower::ServiceExt;
|
||||||
|
|
||||||
|
use sshca::server::make_app;
|
||||||
|
|
||||||
|
use common::setup;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_oidc_config() {
|
||||||
|
let (_ctx, config) = setup::setup().await.unwrap();
|
||||||
|
|
||||||
|
let app = make_app(config);
|
||||||
|
|
||||||
|
let res = app
|
||||||
|
.oneshot(
|
||||||
|
Request::builder()
|
||||||
|
.uri("/user/oidc-config")
|
||||||
|
.method("GET")
|
||||||
|
.body(Body::empty())
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
let body = hyper::body::to_bytes(res.into_body()).await.unwrap();
|
||||||
|
let result: serde_json::Value =
|
||||||
|
serde_json::from_str(std::str::from_utf8(&body).unwrap()).unwrap();
|
||||||
|
assert_eq!(result["url"].as_str(), Some("https://auth.example.org"));
|
||||||
|
assert_eq!(result["client_id"].as_str(), Some("sshca"));
|
||||||
|
assert_eq!(result["client_secret"].as_str(), None);
|
||||||
|
}
|
Loading…
Reference in New Issue