1
0
Fork 0
mirror of https://github.com/zhaofengli/attic.git synced 2024-12-14 11:57:30 +00:00

Move back to jwt_simple

This effectively reverts commit 3e0b65a4c3.

Because jwt_simple doesn't have a unified type / trait that allows
signature and verification, I had to add a SignatureType enum to
approximate that.
This commit is contained in:
Cole Helbling 2023-11-12 12:11:17 -08:00
parent 32e6d858fa
commit 0a9d4938ef
9 changed files with 434 additions and 275 deletions

412
Cargo.lock generated
View file

@ -301,11 +301,10 @@ dependencies = [
"humantime",
"humantime-serde",
"itoa",
"jsonwebtoken",
"maybe-owned",
"rand",
"regex",
"rsa",
"rsa 0.9.3",
"ryu",
"sea-orm",
"sea-orm-migration",
@ -333,10 +332,10 @@ dependencies = [
"base64 0.21.2",
"chrono",
"displaydoc",
"jsonwebtoken",
"jwt-simple",
"lazy_static",
"regex",
"rsa",
"rsa 0.9.3",
"serde",
"serde_with",
"tracing",
@ -370,7 +369,7 @@ dependencies = [
"hex",
"http",
"hyper",
"ring 0.16.20",
"ring",
"time",
"tokio",
"tower",
@ -783,6 +782,12 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "base16ct"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
[[package]]
name = "base64"
version = "0.13.1"
@ -822,6 +827,12 @@ dependencies = [
"num-traits",
]
[[package]]
name = "binstring"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e0d60973d9320722cb1206f412740e162a33b8547ea8d6be75d7cff237c7a85"
[[package]]
name = "bitflags"
version = "1.3.2"
@ -967,11 +978,10 @@ dependencies = [
[[package]]
name = "cc"
version = "1.0.83"
version = "1.0.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
checksum = "0f8e7c90afad890484a21653d08b6e209ae34770fb5ee298f9c699fcc1e5c856"
dependencies = [
"jobserver",
"libc",
]
@ -1083,6 +1093,18 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
[[package]]
name = "coarsetime"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a90d114103adbc625300f346d4d09dfb4ab1c4a8df6868435dd903392ecf4354"
dependencies = [
"libc",
"once_cell",
"wasi",
"wasm-bindgen",
]
[[package]]
name = "codespan-reporting"
version = "0.11.1"
@ -1159,9 +1181,9 @@ dependencies = [
[[package]]
name = "const-oid"
version = "0.9.5"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f"
checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913"
[[package]]
name = "const_format"
@ -1255,6 +1277,18 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "crypto-bigint"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15"
dependencies = [
"generic-array",
"rand_core",
"subtle",
"zeroize",
]
[[package]]
name = "crypto-common"
version = "0.1.6"
@ -1352,12 +1386,23 @@ dependencies = [
[[package]]
name = "der"
version = "0.7.8"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c"
checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de"
dependencies = [
"const-oid",
"pem-rfc7468",
"pem-rfc7468 0.6.0",
"zeroize",
]
[[package]]
name = "der"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56acb310e15652100da43d130af8d97b509e95af61aab1c5a7939ef24337ee17"
dependencies = [
"const-oid",
"pem-rfc7468 0.7.0",
"zeroize",
]
@ -1433,6 +1478,20 @@ version = "0.15.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
[[package]]
name = "ecdsa"
version = "0.16.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0997c976637b606099b9985693efa3581e84e41f5c11ba5255f88711058ad428"
dependencies = [
"der 0.7.6",
"digest",
"elliptic-curve",
"rfc6979",
"signature 2.1.0",
"spki 0.7.2",
]
[[package]]
name = "ed25519-compact"
version = "2.0.4"
@ -1449,6 +1508,27 @@ version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
[[package]]
name = "elliptic-curve"
version = "0.13.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b"
dependencies = [
"base16ct",
"crypto-bigint",
"digest",
"ff",
"generic-array",
"group",
"hkdf",
"pem-rfc7468 0.7.0",
"pkcs8 0.10.2",
"rand_core",
"sec1",
"subtle",
"zeroize",
]
[[package]]
name = "encode_unicode"
version = "0.3.6"
@ -1518,6 +1598,16 @@ dependencies = [
"instant",
]
[[package]]
name = "ff"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449"
dependencies = [
"rand_core",
"subtle",
]
[[package]]
name = "filetime"
version = "0.2.21"
@ -1681,19 +1771,31 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
"zeroize",
]
[[package]]
name = "getrandom"
version = "0.2.10"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "group"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
dependencies = [
"ff",
"rand_core",
"subtle",
]
[[package]]
name = "h2"
version = "0.3.19"
@ -1810,6 +1912,30 @@ dependencies = [
"digest",
]
[[package]]
name = "hmac-sha1-compact"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05e2440a0078e20c3b68ca01234cea4219f23e64b0c0bdb1200c5550d54239bb"
[[package]]
name = "hmac-sha256"
version = "1.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc736091aacb31ddaa4cd5f6988b3c21e99913ac846b41f32538c5fae5d71bfe"
dependencies = [
"digest",
]
[[package]]
name = "hmac-sha512"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "520c9c3f6040661669bc5c91e551b605a520c8e0a63a766a91a65adef734d151"
dependencies = [
"digest",
]
[[package]]
name = "home"
version = "0.5.5"
@ -2074,15 +2200,6 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
[[package]]
name = "jobserver"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"
dependencies = [
"libc",
]
[[package]]
name = "js-sys"
version = "0.3.63"
@ -2093,17 +2210,43 @@ dependencies = [
]
[[package]]
name = "jsonwebtoken"
version = "9.1.0"
name = "jwt-simple"
version = "0.11.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "155c4d7e39ad04c172c5e3a99c434ea3b4a7ba7960b38ecd562b270b097cce09"
checksum = "0537086995d782ba2fb6c120a88f0d66c5ee5f1208a3559826d4cf2264b170da"
dependencies = [
"base64 0.21.2",
"pem",
"ring 0.17.5",
"anyhow",
"binstring",
"coarsetime",
"ct-codecs",
"ed25519-compact",
"hmac-sha1-compact",
"hmac-sha256",
"hmac-sha512",
"k256",
"p256",
"p384",
"rand",
"rsa 0.7.2",
"serde",
"serde_json",
"simple_asn1",
"spki 0.6.0",
"thiserror",
"zeroize",
]
[[package]]
name = "k256"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc"
dependencies = [
"cfg-if",
"ecdsa",
"elliptic-curve",
"once_cell",
"sha2",
"signature 2.1.0",
]
[[package]]
@ -2143,9 +2286,9 @@ checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
[[package]]
name = "libm"
version = "0.2.8"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
[[package]]
name = "libsqlite3-sys"
@ -2323,9 +2466,9 @@ dependencies = [
[[package]]
name = "num-bigint-dig"
version = "0.8.4"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151"
checksum = "2399c9463abc5f909349d8aa9ba080e0b88b3ce2885389b60b993f39b1a56905"
dependencies = [
"byteorder",
"lazy_static",
@ -2438,6 +2581,30 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "p256"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b"
dependencies = [
"ecdsa",
"elliptic-curve",
"primeorder",
"sha2",
]
[[package]]
name = "p384"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209"
dependencies = [
"ecdsa",
"elliptic-curve",
"primeorder",
"sha2",
]
[[package]]
name = "parking_lot"
version = "0.11.2"
@ -2470,13 +2637,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79"
[[package]]
name = "pem"
version = "3.0.2"
name = "pem-rfc7468"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3163d2912b7c3b52d651a055f2c7eec9ba5cd22d26ef75b8dd3a59980b185923"
checksum = "24d159833a9105500e0398934e205e0773f0b27529557134ecfc51c27646adac"
dependencies = [
"base64 0.21.2",
"serde",
"base64ct",
]
[[package]]
@ -2526,15 +2692,37 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkcs1"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eff33bdbdfc54cc98a2eca766ebdec3e1b8fb7387523d5c9c9a2891da856f719"
dependencies = [
"der 0.6.1",
"pkcs8 0.9.0",
"spki 0.6.0",
"zeroize",
]
[[package]]
name = "pkcs1"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f"
dependencies = [
"der",
"pkcs8",
"spki",
"der 0.7.6",
"pkcs8 0.10.2",
"spki 0.7.2",
]
[[package]]
name = "pkcs8"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba"
dependencies = [
"der 0.6.1",
"spki 0.6.0",
]
[[package]]
@ -2543,8 +2731,8 @@ version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
dependencies = [
"der",
"spki",
"der 0.7.6",
"spki 0.7.2",
]
[[package]]
@ -2574,6 +2762,15 @@ version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "primeorder"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf8d3875361e28f7753baefef104386e7aa47642c93023356d97fdef4003bfb5"
dependencies = [
"elliptic-curve",
]
[[package]]
name = "proc-macro-crate"
version = "0.1.5"
@ -2825,6 +3022,16 @@ dependencies = [
"winreg",
]
[[package]]
name = "rfc6979"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2"
dependencies = [
"hmac",
"subtle",
]
[[package]]
name = "ring"
version = "0.16.20"
@ -2835,25 +3042,11 @@ dependencies = [
"libc",
"once_cell",
"spin 0.5.2",
"untrusted 0.7.1",
"untrusted",
"web-sys",
"winapi",
]
[[package]]
name = "ring"
version = "0.17.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b"
dependencies = [
"cc",
"getrandom",
"libc",
"spin 0.9.8",
"untrusted 0.9.0",
"windows-sys 0.48.0",
]
[[package]]
name = "rkyv"
version = "0.7.42"
@ -2882,6 +3075,27 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "rsa"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "094052d5470cbcef561cb848a7209968c9f12dfa6d668f4bca048ac5de51099c"
dependencies = [
"byteorder",
"digest",
"num-bigint-dig",
"num-integer",
"num-iter",
"num-traits",
"pkcs1 0.4.1",
"pkcs8 0.9.0",
"rand_core",
"signature 1.6.4",
"smallvec",
"subtle",
"zeroize",
]
[[package]]
name = "rsa"
version = "0.9.3"
@ -2893,11 +3107,11 @@ dependencies = [
"num-bigint-dig",
"num-integer",
"num-traits",
"pkcs1",
"pkcs8",
"pkcs1 0.7.5",
"pkcs8 0.10.2",
"rand_core",
"signature",
"spki",
"signature 2.1.0",
"spki 0.7.2",
"subtle",
"zeroize",
]
@ -2950,7 +3164,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f"
dependencies = [
"log",
"ring 0.16.20",
"ring",
"sct",
"webpki",
]
@ -2962,7 +3176,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c911ba11bc8433e811ce56fde130ccf32f5127cab0e0194e9c68c5a5b671791e"
dependencies = [
"log",
"ring 0.16.20",
"ring",
"rustls-webpki",
"sct",
]
@ -2994,8 +3208,8 @@ version = "0.100.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b"
dependencies = [
"ring 0.16.20",
"untrusted 0.7.1",
"ring",
"untrusted",
]
[[package]]
@ -3046,8 +3260,8 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
dependencies = [
"ring 0.16.20",
"untrusted 0.7.1",
"ring",
"untrusted",
]
[[package]]
@ -3219,6 +3433,20 @@ version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
[[package]]
name = "sec1"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0aec48e813d6b90b15f0b8948af3c63483992dee44c03e9930b3eebdabe046e"
dependencies = [
"base16ct",
"der 0.7.6",
"generic-array",
"pkcs8 0.10.2",
"subtle",
"zeroize",
]
[[package]]
name = "security-framework"
version = "2.9.1"
@ -3406,6 +3634,16 @@ dependencies = [
"libc",
]
[[package]]
name = "signature"
version = "1.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c"
dependencies = [
"digest",
"rand_core",
]
[[package]]
name = "signature"
version = "2.1.0"
@ -3422,18 +3660,6 @@ version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a"
[[package]]
name = "simple_asn1"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085"
dependencies = [
"num-bigint",
"num-traits",
"thiserror",
"time",
]
[[package]]
name = "slab"
version = "0.4.8"
@ -3474,6 +3700,16 @@ dependencies = [
"lock_api",
]
[[package]]
name = "spki"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b"
dependencies = [
"base64ct",
"der 0.6.1",
]
[[package]]
name = "spki"
version = "0.7.2"
@ -3481,7 +3717,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a"
dependencies = [
"base64ct",
"der",
"der 0.7.6",
]
[[package]]
@ -4128,12 +4364,6 @@ version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "untrusted"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "url"
version = "2.3.1"
@ -4312,8 +4542,8 @@ version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
dependencies = [
"ring 0.16.20",
"untrusted 0.7.1",
"ring",
"untrusted",
]
[[package]]

View file

@ -60,7 +60,6 @@ tracing-subscriber = { version = "0.3.17", features = [ "json" ] }
uuid = { version = "1.3.3", features = ["v4"] }
console-subscriber = "0.1.9"
xdg = "2.5.0"
jsonwebtoken = "9.1.0"
rsa = "0.9.3"
[dependencies.async-compression]

View file

@ -1,17 +1,15 @@
//! HTTP middlewares for access control.
use attic::cache::CacheName;
use attic_token::util::parse_authorization_header;
use axum::{http::Request, middleware::Next, response::Response};
use jsonwebtoken::Algorithm;
use sea_orm::DatabaseConnection;
use tokio::sync::OnceCell;
use crate::access::{CachePermission, Token};
use crate::config::JWTSigningConfig;
use crate::database::{entity::cache::CacheModel, AtticDatabase};
use crate::error::ServerResult;
use crate::{RequestState, State};
use attic::cache::CacheName;
use attic_token::util::parse_authorization_header;
/// Auth state.
#[derive(Debug)]
@ -103,25 +101,19 @@ pub async fn apply_auth<B>(req: Request<B>, next: Next<B>) -> Response {
.and_then(parse_authorization_header)
.and_then(|jwt| {
let state = req.extensions().get::<State>().unwrap();
let (algorithm, decoding_key) = match &state.config.jwt.signing_config {
JWTSigningConfig::HS256SignAndVerify { decoding_key, .. } => {
(Algorithm::HS256, decoding_key)
}
JWTSigningConfig::RS256SignAndVerify { decoding_key, .. } => {
(Algorithm::RS256, decoding_key)
}
};
let signature_type = state.config.jwt.signing_config.clone().into();
let res_token = Token::from_jwt(
&jwt,
algorithm,
decoding_key,
&signature_type,
&state.config.jwt.token_bound_issuer,
&state.config.jwt.token_bound_audiences,
);
if let Err(e) = &res_token {
tracing::debug!("Ignoring bad JWT token: {}", e);
}
res_token.ok()
});

View file

@ -2,12 +2,11 @@ use anyhow::{anyhow, Result};
use chrono::{Duration as ChronoDuration, Utc};
use clap::Parser;
use humantime::Duration;
use jsonwebtoken::Algorithm;
use crate::Opts;
use attic::cache::CacheNamePattern;
use attic_server::access::Token;
use attic_server::config::{Config, JWTSigningConfig};
use attic_server::config::Config;
/// Generate a new token.
///
@ -116,18 +115,10 @@ pub async fn run(config: Config, opts: Opts) -> Result<()> {
if sub.dump_claims {
println!("{}", serde_json::to_string(token.opaque_claims())?);
} else {
let (algorithm, encoding_key) = match &config.jwt.signing_config {
JWTSigningConfig::HS256SignAndVerify { encoding_key, .. } => {
(Algorithm::HS256, encoding_key)
}
JWTSigningConfig::RS256SignAndVerify { encoding_key, .. } => {
(Algorithm::RS256, encoding_key)
}
};
let signature_type = config.jwt.signing_config.into();
let encoded_token = token.encode(
algorithm,
&encoding_key,
&signature_type,
&config.jwt.token_bound_issuer,
&config.jwt.token_bound_audiences,
)?;

View file

@ -1,5 +1,6 @@
//! Server configuration.
use std::collections::HashSet;
use std::env;
use std::net::SocketAddr;
use std::path::{Path, PathBuf};
@ -7,13 +8,14 @@ use std::time::Duration;
use anyhow::Result;
use async_compression::Level as CompressionLevel;
use attic_token::SignatureType;
use base64::{engine::general_purpose::STANDARD as BASE64_STANDARD, Engine};
use derivative::Derivative;
use serde::{de, Deserialize};
use xdg::BaseDirectories;
use crate::access::{
decode_token_hs256_secret, decode_token_rs256_secret, DecodingKey, EncodingKey,
decode_token_hs256_secret_base64, decode_token_rs256_secret_base64, HS256Key, RS256KeyPair,
};
use crate::narinfo::Compression as NixCompression;
use crate::storage::{LocalStorageConfig, S3StorageConfig};
@ -137,7 +139,7 @@ pub struct JWTConfig {
/// values.
#[serde(rename = "token-bound-audiences")]
#[serde(default = "Default::default")]
pub token_bound_audiences: Option<Vec<String>>,
pub token_bound_audiences: Option<HashSet<String>>,
#[serde(rename = "signing")]
#[serde(default = "load_jwt_signing_config_from_env")]
@ -152,10 +154,7 @@ pub enum JWTSigningConfig {
/// Set this to the base64-encoded HMAC secret to use for signing and verifying JWTs.
#[serde(rename = "token-hs256-secret-base64")]
#[serde(deserialize_with = "deserialize_token_hs256_secret_base64")]
HS256SignAndVerify {
encoding_key: EncodingKey,
decoding_key: DecodingKey,
},
HS256SignAndVerify(HS256Key),
/// JSON Web Token RSA secret.
///
@ -163,10 +162,16 @@ pub enum JWTSigningConfig {
/// JWTs.
#[serde(rename = "token-rs256-secret-base64")]
#[serde(deserialize_with = "deserialize_token_rs256_secret_base64")]
RS256SignAndVerify {
encoding_key: EncodingKey,
decoding_key: DecodingKey,
},
RS256SignAndVerify(RS256KeyPair),
}
impl From<JWTSigningConfig> for SignatureType {
fn from(value: JWTSigningConfig) -> Self {
match value {
JWTSigningConfig::HS256SignAndVerify(key) => Self::HS256(key),
JWTSigningConfig::RS256SignAndVerify(key) => Self::RS256(key),
}
}
}
/// Database connection configuration.
@ -324,27 +329,17 @@ fn load_jwt_signing_config_from_env() -> JWTSigningConfig {
fn load_token_hs256_secret_from_env() -> Option<JWTSigningConfig> {
let s = env::var(ENV_TOKEN_HS256_SECRET_BASE64).ok()?;
decode_token_hs256_secret(&s)
decode_token_hs256_secret_base64(&s)
.ok()
.map(
|(encoding_key, decoding_key)| JWTSigningConfig::HS256SignAndVerify {
encoding_key,
decoding_key,
},
)
.map(JWTSigningConfig::HS256SignAndVerify)
}
fn load_token_rs256_secret_from_env() -> Option<JWTSigningConfig> {
let s = env::var(ENV_TOKEN_RS256_SECRET_BASE64).ok()?;
decode_token_rs256_secret(&s)
decode_token_rs256_secret_base64(&s)
.ok()
.map(
|(encoding_key, decoding_key)| JWTSigningConfig::RS256SignAndVerify {
encoding_key,
decoding_key,
},
)
.map(JWTSigningConfig::RS256SignAndVerify)
}
fn load_database_url_from_env() -> String {
@ -398,30 +393,26 @@ impl Default for GarbageCollectionConfig {
}
}
fn deserialize_token_hs256_secret_base64<'de, D>(
deserializer: D,
) -> Result<(EncodingKey, DecodingKey), D::Error>
fn deserialize_token_hs256_secret_base64<'de, D>(deserializer: D) -> Result<HS256Key, D::Error>
where
D: de::Deserializer<'de>,
{
use de::Error;
let s = String::deserialize(deserializer)?;
let key = decode_token_hs256_secret(&s).map_err(Error::custom)?;
let key = decode_token_hs256_secret_base64(&s).map_err(Error::custom)?;
Ok(key)
}
fn deserialize_token_rs256_secret_base64<'de, D>(
deserializer: D,
) -> Result<(EncodingKey, DecodingKey), D::Error>
fn deserialize_token_rs256_secret_base64<'de, D>(deserializer: D) -> Result<RS256KeyPair, D::Error>
where
D: de::Deserializer<'de>,
{
use de::Error;
let s = String::deserialize(deserializer)?;
let key = decode_token_rs256_secret(&s).map_err(Error::custom)?;
let key = decode_token_rs256_secret_base64(&s).map_err(Error::custom)?;
Ok(key)
}

View file

@ -17,7 +17,7 @@ use chrono::{Months, Utc};
use rsa::pkcs1::EncodeRsaPrivateKey;
use tokio::fs::{self, OpenOptions};
use crate::access::{decode_token_rs256_secret, Token};
use crate::access::{decode_token_rs256_secret_base64, SignatureType, Token};
use crate::config;
use attic::cache::CacheNamePattern;
@ -73,8 +73,8 @@ pub async fn run_oobe() -> Result<()> {
perm.configure_cache_retention = true;
perm.destroy_cache = true;
let key = decode_token_rs256_secret(&rs256_secret_base64).unwrap();
token.encode(jsonwebtoken::Algorithm::RS256, &key.0, &None, &None)?
let key = decode_token_rs256_secret_base64(&rs256_secret_base64).unwrap();
token.encode(&SignatureType::RS256(key), &None, &None)?
};
eprintln!();

View file

@ -11,7 +11,7 @@ attic = { path = "../attic", default-features = false }
base64 = "0.21.2"
chrono = "0.4.31"
displaydoc = "0.2.4"
jsonwebtoken = { version = "9.1.0", features = ["use_pem"] }
jwt-simple = "0.11.5"
lazy_static = "1.4.0"
regex = "1.8.3"
serde = "1.0.163"

View file

@ -83,15 +83,18 @@ pub mod util;
#[cfg(test)]
mod tests;
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use std::error::Error as StdError;
use base64::{engine::general_purpose::STANDARD as BASE64_STANDARD, Engine};
use chrono::{DateTime, Utc};
use displaydoc::Display;
use jsonwebtoken::{Algorithm, Validation};
pub use jsonwebtoken::{DecodingKey, EncodingKey};
use rsa::pkcs1::{DecodeRsaPrivateKey, EncodeRsaPublicKey};
use jwt_simple::prelude::{Duration, RSAKeyPairLike, RSAPublicKeyLike, VerificationOptions};
pub use jwt_simple::{
algorithms::{HS256Key, MACLike, RS256KeyPair},
claims::{Claims, JWTClaims},
prelude::UnixTimeStamp,
};
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, BoolFromInt};
@ -124,60 +127,6 @@ macro_rules! require_permission_function {
};
}
/// A set of JWT claims.
///
/// The `CustomClaims` parameter can be set to `NoCustomClaims` if only standard
/// claims are used, or to a user-defined type that must be `serde`-serializable
/// if custom claims are required.
///
/// NOTE: This has been lifted from jwt_simple, but UnixTimeStamp has been
/// changed to i64, and Audiences is now a string.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JWTClaims<CustomClaims> {
/// Time the claims were created at
#[serde(rename = "iat", default, skip_serializing_if = "Option::is_none")]
pub issued_at: Option<i64>,
/// Time the claims expire at
#[serde(rename = "exp", default, skip_serializing_if = "Option::is_none")]
pub expires_at: Option<i64>,
/// Time the claims will be invalid until
#[serde(rename = "nbf", default, skip_serializing_if = "Option::is_none")]
pub invalid_before: Option<i64>,
/// Issuer - This can be set to anything application-specific
#[serde(rename = "iss", default, skip_serializing_if = "Option::is_none")]
pub issuer: Option<String>,
/// Subject - This can be set to anything application-specific
#[serde(rename = "sub", default, skip_serializing_if = "Option::is_none")]
pub subject: Option<String>,
/// Audiences
#[serde(rename = "aud", default, skip_serializing_if = "Option::is_none")]
pub audiences: Option<Vec<String>>,
/// JWT identifier
///
/// That property was originally designed to avoid replay attacks, but
/// keeping all previously sent JWT token IDs is unrealistic.
///
/// Replay attacks are better addressed by keeping only the timestamp of the
/// last valid token for a user, and rejecting anything older in future
/// tokens.
#[serde(rename = "jti", default, skip_serializing_if = "Option::is_none")]
pub jwt_id: Option<String>,
/// Nonce
#[serde(rename = "nonce", default, skip_serializing_if = "Option::is_none")]
pub nonce: Option<String>,
/// Custom (application-defined) claims
#[serde(flatten)]
pub custom: CustomClaims,
}
/// A validated JSON Web Token.
#[derive(Debug)]
pub struct Token(JWTClaims<TokenClaims>);
@ -271,7 +220,7 @@ pub enum Error {
PermissionDenied,
/// JWT error: {0}
TokenError(jsonwebtoken::errors::Error),
TokenError(jwt_simple::Error),
/// Base64 decode error: {0}
Base64Error(base64::DecodeError),
@ -283,36 +232,52 @@ pub enum Error {
Utf8Error(std::str::Utf8Error),
}
/// The supported JWT signature types.
pub enum SignatureType {
HS256(HS256Key),
RS256(RS256KeyPair),
}
impl Token {
/// Verifies and decodes a token.
pub fn from_jwt(
token: &str,
key_algorithm: Algorithm,
key: &jsonwebtoken::DecodingKey,
signature_type: &SignatureType,
maybe_bound_issuer: &Option<String>,
maybe_bound_audiences: &Option<Vec<String>>,
maybe_bound_audiences: &Option<HashSet<String>>,
) -> Result<Self> {
let mut required_spec_claims = vec!["exp", "nbf", "sub"];
let opts = VerificationOptions {
reject_before: None,
accept_future: false,
required_subject: None,
required_key_id: None,
required_public_key: None,
required_nonce: None,
allowed_issuers: maybe_bound_issuer
.as_ref()
.map(|s| [s.to_owned()].into())
.to_owned(),
allowed_audiences: maybe_bound_audiences.to_owned(),
time_tolerance: None,
max_validity: None,
max_token_length: None,
max_header_length: None,
};
let mut validation = Validation::new(key_algorithm);
validation.validate_nbf = true;
if let Some(bound_issuer) = maybe_bound_issuer {
validation.set_issuer(&[bound_issuer]);
required_spec_claims.push("iss");
}
if let Some(bound_audiences) = maybe_bound_audiences {
validation.set_audience(&bound_audiences);
required_spec_claims.push("aud");
}
validation.set_required_spec_claims(&required_spec_claims);
jsonwebtoken::decode::<JWTClaims<TokenClaims>>(token, key, &validation)
match signature_type {
SignatureType::HS256(key) => key
.verify_token(token, Some(opts))
.map_err(Error::TokenError)
.map(Token),
SignatureType::RS256(key) => {
let public_key = key.public_key();
public_key
.verify_token(token, Some(opts))
.map_err(Error::TokenError)
.map(|tokendata| tokendata.claims)
.map(Token)
}
}
}
/// Creates a new token with an expiration timestamp.
pub fn new(sub: String, exp: &DateTime<Utc>) -> Self {
@ -324,8 +289,13 @@ impl Token {
Self(JWTClaims {
issued_at: None,
expires_at: Some(exp.timestamp()),
invalid_before: Some(now_epoch.num_seconds()),
expires_at: Some(UnixTimeStamp::from_secs(
exp.timestamp().try_into().unwrap(),
)),
invalid_before: Some(Duration::new(
now_epoch.num_seconds().try_into().unwrap(),
0,
)),
issuer: None,
subject: Some(sub),
audiences: None,
@ -338,18 +308,23 @@ impl Token {
/// Encodes the token.
pub fn encode(
&self,
key_algorithm: Algorithm,
key: &jsonwebtoken::EncodingKey,
signature_type: &SignatureType,
maybe_bound_issuer: &Option<String>,
maybe_bound_audiences: &Option<Vec<String>>,
maybe_bound_audiences: &Option<HashSet<String>>,
) -> Result<String> {
let header = jsonwebtoken::Header::new(key_algorithm);
let mut token = self.0.clone();
let mut claims = self.0.clone();
claims.issuer = maybe_bound_issuer.to_owned();
claims.audiences = maybe_bound_audiences.to_owned();
if let Some(issuer) = maybe_bound_issuer {
token = token.with_issuer(issuer);
}
if let Some(audiences) = maybe_bound_audiences {
token = token.with_audiences(audiences.to_owned());
}
jsonwebtoken::encode(&header, &claims, key).map_err(Error::TokenError)
match signature_type {
SignatureType::HS256(key) => key.authenticate(token).map_err(Error::TokenError),
SignatureType::RS256(key) => key.sign(token).map_err(Error::TokenError),
}
}
/// Returns the subject of the token.
@ -454,28 +429,16 @@ impl CachePermission {
impl StdError for Error {}
pub fn decode_token_hs256_secret(s: &str) -> Result<(EncodingKey, DecodingKey)> {
let secret = BASE64_STANDARD.decode(s).map_err(Error::Base64Error)?;
let encoding_key = EncodingKey::from_secret(&secret);
let decoding_key = DecodingKey::from_secret(&secret);
Ok((encoding_key, decoding_key))
}
pub fn decode_token_rs256_secret(s: &str) -> Result<(EncodingKey, DecodingKey)> {
pub fn decode_token_hs256_secret_base64(s: &str) -> Result<HS256Key> {
let decoded = BASE64_STANDARD.decode(s).map_err(Error::Base64Error)?;
let secret = std::str::from_utf8(&decoded).map_err(Error::Utf8Error)?;
let private_key = rsa::RsaPrivateKey::from_pkcs1_pem(secret).map_err(Error::RsaKeyError)?;
let public_key = private_key.to_public_key();
let public_pkcs1_pem = public_key
.to_pkcs1_pem(rsa::pkcs1::LineEnding::LF)
.map_err(Error::RsaKeyError)?;
let encoding_key = EncodingKey::from_rsa_pem(&secret.as_bytes()).map_err(Error::TokenError)?;
let decoding_key =
DecodingKey::from_rsa_pem(public_pkcs1_pem.as_bytes()).map_err(Error::TokenError)?;
Ok((encoding_key, decoding_key))
Ok(HS256Key::from_bytes(&secret.as_bytes()))
}
pub fn decode_token_rs256_secret_base64(s: &str) -> Result<RS256KeyPair> {
let decoded = BASE64_STANDARD.decode(s).map_err(Error::Base64Error)?;
let secret = std::str::from_utf8(&decoded).map_err(Error::Utf8Error)?;
let keypair = RS256KeyPair::from_pem(secret).map_err(Error::TokenError)?;
Ok(keypair)
}

View file

@ -30,19 +30,12 @@ fn test_basic() {
// BASE64_SECRET=$(openssl rsa -in rs256 -outform PEM -traditional | base64 -w0)
let base64_secret = "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBNUZranRMRzV5eS9pMFlnYkQxeUJBK21GckNmLzZiQ2F0TDFFQ3ppNG1tZWhSZTcwCkFEL0dSSHhTVUErc0pZeCtZNjlyL0RqQWs2OFJlQ1c4b2FQWXhtc21RNG5VM2ZwZ2E3WWFqZ3ZoWmVsa3JtaC8KZ1ZURWtFTG1IZlJtQkwvOWlsT20yRHNtYTVhUFo0SFl6ellpdjJvcFF5UGRndXcyWXFtbzE3Nk5MdllCMmpJTwovR3FkdE55K3NPV296NktVSVlJa0hWWU5HMENVcFNzdXBqUTJ6VTVZMFc2UXlNQWFWd1BONElJT3lXWUNwZXRECjFJbWxYekhROXM4NXFSWnlLa21iZFhtTVBVWmUvekRxc2FFd3lscFlpT0RjbDdRYU5QTzEzZnk3UGtQMmVwdUkKTk5tZ1E0WEF0MkF4ZXNKck5ibUs4aG1iM3doRXZkNjRFMGdEV1FJREFRQUJBb0lCQUJEemNRd2IyVi8wK1JCMgoyeE5qMll2eHpPTi93S2FYWHBTbUxDUHRIUDhSVEU2RnM0VkZOckdrelBOMmhsL3ZNdjZ4YWdHNk1NbUZ5SFV6CnovSHIyTTY1NjRnOTloaFlXc29FSmFwL3hVYXNjYlhrdWZwZTBZeW4rcThra21JdDRtTmZYRlpXNWI0ODJmNWsKRERVdG5weTVBOEVoSzNOcGw0dnhia0E5dS90TlVlT1NHTkhPYVZjcHdERVhDNXJ4bmFxTm5wMkMwa1A4ODRINgpSb2lZVkF4bytHaVpNVzhIOFRmSXVsenh3c04yQnVNcUNmOGVhNG1EM0pRVHZ2REhhUHM4eVJTUlB3UmlHYUkzCnVybFRmdjg4U20va09oL0N2SkpoRnhCVkVNVjIydWRNUmU3L3NpTWtlbVlvUnhaTWJjRGVQK2h1RktJWTRSMEoKNnRJUHQ3VUNnWUVBOTlhL2IzeFBsQWh0ck02dUlUUXNQd0FYQUg3Q1NXL1FSdVJUTWVhYXVIMk9sRitjZmpMNApJS1Nsdy9QaUtaUEk1TFRWM2ZVZk5WNTVsOFZHTytsT2ViTFhnaXBYM3BqSDBma3AyY3Q2Smk3aGw0aUlXK0h0ClpJNE9KYkYwTTBETHdySkd3T25QL2trRHNxSW9IbC9MdTBRM2FxSm1RVCsvcG54R083R21kbDhDZ1lFQTY5NFcKZHF2NnF4VjF5V0Z4QWZOOE1hZStpTC9xY1VhTm85ZzMva2YvOXZ3VXdtcERvR0xnaVVLMWZKb3BUYlBjcWgwRwptbUZEQ3V2M1Q0OS9yU2k5dU4zYm82cmlXRUl4VFg1YUtFSjlpSEFMWDJGWDdGSDJRdUZGWEwzQ2c0ckdvL1pDCmdjUkxuS3dma3JUVnRxeEdaNjN4YmsvcFpHWjZtTW01VkNDck1VY0NnWUVBc3JUT1pQMG1CSC92VldQU2UyNjcKV05JZncrT2pCSUR6bGFxZHNxV3Rlc3BPUFA2VVFRdFBqM29wYlJvMlFmU21Md09XRXUzbEN2Nk1mcnRvNFZwaAprNjg1WmtwU0FkZjRmWmRFYmg4aWZOWGhKUHIyR0FyWXVtRVVJbW5LZUFxSTRtTGFVZEJHZ2Z6MEJhS1hldzlvClFDZjRMWlBjVjhBMzJUeFRDRWdZMTlFQ2dZQU04U2F5WkVWZzFkQ2N1Q2dIUDJEMUtJc2YzY2Z6WnplbVlkclEKclFxeWRxcDg4Rys5Z1M5bzJLdzBwaERXSHFSaEFTNjNrZGFuNXNLdkx1U0dqOUc1THhNNks4bzNwWW9uQW1QWQpDYTN4cXBRMUs1WXpkVnZaMTVxQ3VEYlFHUEZGVmVIWVZQa0JJOENud0J4cDVaSUhabGYxQVpXQTJNNnBTNGhMCndXOGpTUUtCZ1FDQmNJbjU4Y0lmZkhmMjM4SUJvZnR1UVVzREZGcnkzaUVpaWpTYmJ1WnB1Vm8zL2pWbUsyaEYKS2xUL2xoRDdWdGJ1V3phMG9WQmZDaWZqMnZ2S2pmZ0l6NnF3Um1UbC9DSjlWdUNHTUI1VG55cGl3OEtodXorSAo0L2twdDdNcW9WQ0dRSjd1WVQyQzY1K0JqNklnUnBQT09za3VKNW1RZ0FlbTQ3eDBrVnRSemc9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=";
let dec_key = decode_token_rs256_secret(base64_secret).unwrap().1;
let dec_key = decode_token_rs256_secret_base64(base64_secret).unwrap();
// TOKEN=$(jq -c < json | jwt encode --alg RS256 --secret @./rs256 -)
let token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJleHAiOjQxMDIzMjQ5ODYsImh0dHBzOi8vand0LmF0dGljLnJzL3YxIjp7ImNhY2hlcyI6eyJjYWNoZS1ybyI6eyJyIjoxfSwiY2FjaGUtcnciOnsiciI6MSwidyI6MX0sInRlYW0tKiI6eyJjYyI6MSwiciI6MSwidyI6MX19fSwiaWF0IjoxNjk5NzM0NTU3LCJuYmYiOjAsInN1YiI6Im1lb3cifQ.k1TCqAg5_yaBQByKnYn5zSvMsYi8XrHe1h8T2hijZiP1SsYYnKphKKm0e61lmr3tSM-3dtRRCNGB7elhetpuz2jz8fWyBmpjO-yIX2uB787iRKVjaVCEKSPjcKO9lGp9LlxKdNH0SLRmdwkJGQUHbzN6QurfiV4C54cPxC_43EamkOqFUFmmwohi_r76RZtMb8uyt-9t7Canpm7GfJg4uVg3MLgbvCKxJ4BSu4UgXPz-MYupHS_pIEtlCY8FjlVrXlBLAleUvcBPY2qML9gxpqBrh9s1qfLpCeTZkG-vDjb_Y8X0gXa0OshFrvnoIyHwDc9jmj1X35T0YslyjbQXWQ";
let decoded = Token::from_jwt(
token,
jsonwebtoken::Algorithm::RS256,
&dec_key,
&None,
&None,
)
.unwrap();
let decoded = Token::from_jwt(token, &SignatureType::RS256(dec_key), &None, &None).unwrap();
let perm_rw = decoded.get_permission_for_cache(&cache! { "cache-rw" });