From 92654565eb5f56d593963978a7d7cce7bdad931a Mon Sep 17 00:00:00 2001 From: Clement Delafargue Date: Mon, 13 Jan 2025 15:08:17 +0100 Subject: [PATCH 1/6] update deps (including biscuit-auth to 6.0.0) --- Cargo.lock | 438 ++++++++++++++++++++++++++++++++++++++++------------- Cargo.toml | 2 +- 2 files changed, 335 insertions(+), 105 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 567f17a..2327952 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,9 +28,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" [[package]] name = "atty" @@ -45,9 +45,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "base16ct" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] name = "base64" @@ -63,23 +69,28 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "biscuit-auth" -version = "5.0.0" +version = "6.0.0-beta.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95490f2c91dc452247d00a2fb4779bcedb7693e669354fa1fe2a96679f4950cc" +checksum = "5c201f713f0a77e455f9bfd74bc47a8c009d41abc6c755fd4d34d72ae593f6a7" dependencies = [ "base64", "biscuit-parser", "biscuit-quote", + "ecdsa", "ed25519-dalek", + "elliptic-curve", "getrandom 0.1.16", "hex", "nom", + "p256", + "pkcs8 0.9.0", "prost", "prost-types", "rand", "rand_core", "regex", "serde", + "serde_json", "sha2 0.9.9", "thiserror", "time", @@ -107,9 +118,9 @@ dependencies = [ [[package]] name = "biscuit-parser" -version = "0.1.2" +version = "0.2.0-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9fd6da963e73f7e6db729c3bd76784863ba405b15acbbb5cb08ebc2adbd3bf" +checksum = "9f52db87488d52f9aeb29c6b7294b736c1341b8730fee49cd1681522398bb59b" dependencies = [ "hex", "nom", @@ -122,12 +133,12 @@ dependencies = [ [[package]] name = "biscuit-quote" -version = "0.2.2" +version = "0.3.0-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0071fe3634b644a8df1434e3e14841e480c4238059c66a94e479b7eff98c2bd3" +checksum = "97887efd447743d2f1a545a8eee5afc4315aedb8a6bfa0c4afcb0974a779907a" dependencies = [ "biscuit-parser", - "proc-macro-error", + "proc-macro-error2", "proc-macro2", "quote", "syn 1.0.109", @@ -141,9 +152,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be" [[package]] name = "block-buffer" @@ -177,15 +188,18 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fca2be1d5c43812bae364ee3f30b3afcb7877cf59f4aeb94c66f313a41d2fac9" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "cc" -version = "1.1.7" +version = "1.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" +checksum = "c8293772165d9345bdaaa39b45b2109591e63fe5e6fbc23c6ff930a048aa310b" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -195,9 +209,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ "android-tzdata", "iana-time-zone", @@ -254,19 +268,31 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -301,7 +327,16 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.96", +] + +[[package]] +name = "der" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +dependencies = [ + "const-oid", ] [[package]] @@ -311,6 +346,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", + "pem-rfc7468", "zeroize", ] @@ -339,7 +375,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", + "const-oid", "crypto-common", + "subtle", +] + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der 0.7.9", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "serdect", + "signature", + "spki 0.7.3", ] [[package]] @@ -348,7 +401,7 @@ version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ - "pkcs8", + "pkcs8 0.10.2", "signature", ] @@ -373,11 +426,32 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pem-rfc7468", + "pkcs8 0.10.2", + "rand_core", + "sec1", + "serdect", + "subtle", + "zeroize", +] + [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", "windows-sys", @@ -385,9 +459,19 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[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 = "fiat-crypto" @@ -403,6 +487,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -427,6 +512,17 @@ dependencies = [ "wasi 0.11.0+wasi-snapshot-preview1", ] +[[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 = "hashbrown" version = "0.12.3" @@ -454,11 +550,20 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -498,16 +603,17 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -519,15 +625,15 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "log" @@ -641,9 +747,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "opaque-debug" @@ -657,6 +763,18 @@ version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" +[[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 0.10.8", +] + [[package]] name = "parse_duration" version = "2.1.1" @@ -668,14 +786,33 @@ dependencies = [ "regex", ] +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[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]] name = "pkcs8" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ - "der", - "spki", + "der 0.7.9", + "spki 0.7.3", ] [[package]] @@ -686,12 +823,20 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.19" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2288c0e17cc8d342c712bb43a257a80ebffce59cdb33d5000d8348f3ec02528b" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ "zerocopy", - "zerocopy-derive", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", ] [[package]] @@ -718,11 +863,33 @@ dependencies = [ "version_check", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.96", +] + [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] @@ -762,9 +929,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.36" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -801,9 +968,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.5" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -813,9 +980,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -824,69 +991,100 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] -name = "rustc_version" +name = "rfc6979" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.7.0", "errno", "libc", "linux-raw-sys", "windows-sys", ] +[[package]] +name = "rustversion" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" + [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der 0.7.9", + "generic-array", + "pkcs8 0.10.2", + "serdect", + "subtle", + "zeroize", +] + [[package]] name = "semver" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" [[package]] name = "serde" -version = "1.0.204" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.96", ] [[package]] name = "serde_json" -version = "1.0.121" +version = "1.0.135" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ab380d7d9f22ef3f21ad3e6c1ebe8e4fc7a2000ccba2e4d71fc96f15b2cb609" +checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" dependencies = [ "itoa", "memchr", @@ -894,6 +1092,16 @@ dependencies = [ "serde", ] +[[package]] +name = "serdect" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177" +dependencies = [ + "base16ct", + "serde", +] + [[package]] name = "sha2" version = "0.9.9" @@ -924,15 +1132,31 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signature" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ + "digest 0.10.7", "rand_core", ] +[[package]] +name = "spki" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +dependencies = [ + "der 0.6.1", +] + [[package]] name = "spki" version = "0.7.3" @@ -940,7 +1164,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", - "der", + "der 0.7.9", ] [[package]] @@ -968,9 +1192,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.72" +version = "2.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" dependencies = [ "proc-macro2", "quote", @@ -979,12 +1203,14 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.10.1" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" dependencies = [ "cfg-if", "fastrand", + "getrandom 0.2.15", + "once_cell", "rustix", "windows-sys", ] @@ -1006,29 +1232,29 @@ checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.96", ] [[package]] name = "time" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "itoa", @@ -1047,9 +1273,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" dependencies = [ "num-conv", "time-core", @@ -1063,9 +1289,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "version_check" @@ -1087,34 +1313,35 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", + "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.96", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1122,22 +1349,25 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.96", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "winapi" @@ -1157,9 +1387,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ "windows-sys", ] @@ -1181,9 +1411,9 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.52.0" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets", ] @@ -1270,7 +1500,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.96", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 648b9a8..70b183a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ path = "src/main.rs" [dependencies] atty = "0.2.14" -biscuit-auth = { version = "5.0.0", features = ["serde-error"] } +biscuit-auth = { version = "6.0.0-beta.1", features = ["serde-error"] } clap = { version = "^3.0", features = ["color", "derive"] } chrono = "^0.4" hex = "0.4.3" From 93d3568f08a7b40e17ddf3b7c43ec74fa51c3b39 Mon Sep 17 00:00:00 2001 From: Clement Delafargue Date: Mon, 13 Jan 2025 15:05:25 +0100 Subject: [PATCH 2/6] Migrate to biscuit-auth 6.0.0 - biscuit-datalog v3.3 support - secp256r1 support - authorizers are now immutable (except for fact generation): adding code to a parsed snapshot is not possible anymore --- src/cli.rs | 65 ++++++----- src/errors.rs | 2 + src/input.rs | 47 ++++---- src/inspect.rs | 307 ++++++++++++++++++++++++++++--------------------- src/main.rs | 74 ++++++------ 5 files changed, 275 insertions(+), 220 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index 32acf1d..3c7b2ab 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,3 +1,4 @@ +use biscuit_auth::Algorithm; use clap::Parser; use std::path::PathBuf; @@ -49,6 +50,9 @@ pub struct KeyPairCmd { /// Output the private key raw bytes directly, with no hex encoding #[clap(long, requires("only-private-key"))] pub raw_private_key_output: bool, + /// Key algorithm: ed25519 (default) or secp256r1 + #[clap(long, default_value_t)] + pub key_algorithm: Algorithm, } /// Generate a biscuit from a private key and an authority block @@ -79,6 +83,9 @@ pub struct Generate { /// Read the private key raw bytes directly (only available when reading the private key from a file) #[clap(long, conflicts_with = "private-key", requires = "private-key-file")] pub raw_private_key: bool, + /// Key algorithm: ed25519 (default) or secp256r1 + #[clap(long, default_value_t)] + pub key_algorithm: Algorithm, /// The optional context string attached to the authority block #[clap(long)] pub context: Option, @@ -142,6 +149,11 @@ pub struct Inspect { /// Read the public key raw bytes directly #[clap(long, requires("public-key-file"), conflicts_with("public-key"))] pub raw_public_key: bool, + /// Key algorithm: ed25519 (default) or secp256r1 + #[clap(long, default_value_t)] + pub key_algorithm: Algorithm, + #[clap(flatten)] + pub run_limits_args: common_args::RunLimitArgs, #[clap(flatten)] pub authorization_args: common_args::AuthorizeArgs, #[clap(flatten)] @@ -169,7 +181,7 @@ pub struct InspectSnapshot { #[clap(long)] pub raw_input: bool, #[clap(flatten)] - pub authorization_args: common_args::AuthorizeArgs, + pub run_limits_args: common_args::RunLimitArgs, #[clap(flatten)] pub query_args: common_args::QueryArgs, #[clap(flatten)] @@ -209,6 +221,9 @@ pub struct GenerateThirdPartyBlock { /// Read the private key raw bytes directly (only available when reading the private key from a file) #[clap(long, conflicts_with = "private-key", requires = "private-key-file")] pub raw_private_key: bool, + /// Key algorithm: ed25519 (default) or secp256r1 + #[clap(long, default_value_t)] + pub key_algorithm: Algorithm, /// Output the block raw bytes directly, with no base64 encoding #[clap(long)] pub raw_output: bool, @@ -254,7 +269,7 @@ mod common_args { pub struct ParamArg { /// Provide a value for a datalog parameter. `type` is optional and defaults to `string`. Possible types are pubkey, string, integer, date, bytes or bool. /// Bytes values must be hex-encoded and start with `hex:` - /// Public keys must be hex-encoded and start with `ed25519/` + /// Public keys must be hex-encoded and start with `ed25519/` or `secp256r1/` #[clap( long, value_parser = clap::builder::ValueParser::new(parse_param), @@ -263,6 +278,25 @@ mod common_args { pub param: Vec, } + /// Arguments related to runtime limits + #[derive(Parser)] + pub struct RunLimitArgs { + /// Configure the maximum amount of facts that can be generated + /// before aborting evaluation + #[clap(long)] + pub max_facts: Option, + /// Configure the maximum amount of iterations before aborting + /// evaluation + #[clap(long)] + pub max_iterations: Option, + /// Configure the maximum evaluation duration before aborting + #[clap( + long, + parse(try_from_str = parse_duration) + )] + pub max_time: Option, + } + /// Arguments related to running authorization #[derive(Parser)] pub struct AuthorizeArgs { @@ -291,33 +325,6 @@ mod common_args { conflicts_with("authorize-interactive") )] pub authorize_with: Option, - /// Configure the maximum amount of facts that can be generated - /// before aborting evaluation - #[clap( - long, - requires("authorize-with"), - requires("authorize-interactive"), - requires("authorize-with-file") - )] - pub max_facts: Option, - /// Configure the maximum amount of iterations before aborting - /// evaluation - #[clap( - long, - requires("authorize-with"), - requires("authorize-interactive"), - requires("authorize-with-file") - )] - pub max_iterations: Option, - /// Configure the maximum evaluation duration before aborting - #[clap( - long, - requires("authorize-with"), - requires("authorize-interactive"), - requires("authorize-with-file"), - parse(try_from_str = parse_duration) - )] - pub max_time: Option, /// Include the current time in the verifier facts #[clap(long)] pub include_time: bool, diff --git a/src/errors.rs b/src/errors.rs index 99ed2aa..34ad733 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -27,6 +27,8 @@ pub enum CliError { MissingPublicKeyForQuerying, #[error("Signatures check failed")] SignaturesCheckFailed, + #[error("Datalog fact generation failed")] + EvaluationFailed, #[error("Authorization failed")] AuthorizationFailed, #[error("Querying failed")] diff --git a/src/input.rs b/src/input.rs index 7bfdb92..bbe33d5 100644 --- a/src/input.rs +++ b/src/input.rs @@ -2,7 +2,8 @@ use anyhow::Result; use atty::Stream; use biscuit_auth::{ builder::{BiscuitBuilder, BlockBuilder, Rule, Term}, - Authorizer, ThirdPartyRequest, UnverifiedBiscuit, {PrivateKey, PublicKey}, + Algorithm, Authorizer, AuthorizerBuilder, PrivateKey, PublicKey, ThirdPartyRequest, + UnverifiedBiscuit, }; use chrono::{DateTime, Duration, Utc}; use parse_duration as duration_parser; @@ -131,8 +132,8 @@ pub fn read_authority_from( from: &DatalogInput, all_params: &[Param], context: &Option, - builder: &mut BiscuitBuilder, -) -> Result<()> { + builder: BiscuitBuilder, +) -> Result { let string = match from { DatalogInput::FromEditor => read_editor_string()?, DatalogInput::FromStdin => read_stdin_string("datalog program")?, @@ -153,22 +154,22 @@ pub fn read_authority_from( } } - builder - .add_code_with_params(&string, params, scope_params) + let mut builder = builder + .code_with_params(&string, params, scope_params) .map_err(|e| ParseError("datalog statements".to_string(), e.to_string()))?; if let Some(ctx) = context { - builder.set_context(ctx.to_owned()); + builder = builder.context(ctx.to_owned()); } - Ok(()) + Ok(builder) } pub fn read_block_from( from: &DatalogInput, all_params: &[Param], context: &Option, - builder: &mut BlockBuilder, -) -> Result<()> { + builder: BlockBuilder, +) -> Result { let string = match from { DatalogInput::FromEditor => read_editor_string()?, DatalogInput::FromStdin => read_stdin_string("datalog program")?, @@ -188,22 +189,22 @@ pub fn read_block_from( } } } - builder - .add_code_with_params(&string, params, scope_params) + let mut builder = builder + .code_with_params(&string, params, scope_params) .map_err(|e| ParseError("datalog statements".to_string(), e.to_string()))?; if let Some(ctx) = context { - builder.set_context(ctx.to_owned()); + builder = builder.context(ctx.to_owned()); } - Ok(()) + Ok(builder) } pub fn read_authorizer_from( from: &DatalogInput, all_params: &[Param], - authorizer: &mut Authorizer, -) -> Result<()> { + builder: AuthorizerBuilder, +) -> Result { let string = match from { DatalogInput::FromEditor => read_editor_string()?, DatalogInput::FromStdin => read_stdin_string("datalog program")?, @@ -223,14 +224,14 @@ pub fn read_authorizer_from( } } } - authorizer - .add_code_with_params(&string, params, scope_params) + let builder = builder + .code_with_params(&string, params, scope_params) .map_err(|e| ParseError("datalog statements".to_string(), e.to_string()))?; - Ok(()) + Ok(builder) } -pub fn read_private_key_from(from: &KeyBytes) -> Result { +pub fn read_private_key_from(from: &KeyBytes, alg: Algorithm) -> Result { let bytes = match from { KeyBytes::FromStdin(KeyFormat::RawBytes) => read_stdin_bytes()?, KeyBytes::FromStdin(KeyFormat::HexKey) => { @@ -246,11 +247,11 @@ pub fn read_private_key_from(from: &KeyBytes) -> Result { )?, KeyBytes::HexString(str) => hex::decode(str)?, }; - PrivateKey::from_bytes(&bytes) + PrivateKey::from_bytes(&bytes, alg) .map_err(|e| ParseError("private key".to_string(), format!("{}", &e)).into()) } -pub fn read_public_key_from(from: &KeyBytes) -> Result { +pub fn read_public_key_from(from: &KeyBytes, alg: Algorithm) -> Result { let bytes = match from { KeyBytes::FromStdin(KeyFormat::RawBytes) => read_stdin_bytes()?, KeyBytes::FromStdin(KeyFormat::HexKey) => { @@ -266,7 +267,7 @@ pub fn read_public_key_from(from: &KeyBytes) -> Result { )?, KeyBytes::HexString(str) => hex::decode(str)?, }; - PublicKey::from_bytes(&bytes) + PublicKey::from_bytes(&bytes, alg) .map_err(|e| ParseError("public key".to_string(), format!("{}", &e)).into()) } @@ -424,7 +425,7 @@ pub fn parse_param(kv: &str) -> Result { ))?; let bytes = hex::decode(hex_key).map_err(|e| Error::new(ErrorKind::Other, format!("{}", &e))); - let pubkey = PublicKey::from_bytes(&bytes?) + let pubkey = PublicKey::from_bytes(&bytes?, Algorithm::Ed25519) .map_err(|e| Error::new(ErrorKind::Other, format!("{}", &e)))?; Ok(Param::PublicKey(name.to_string(), pubkey)) }, diff --git a/src/inspect.rs b/src/inspect.rs index e096ed8..a73b440 100644 --- a/src/inspect.rs +++ b/src/inspect.rs @@ -3,26 +3,26 @@ use biscuit_auth::{ builder::{Fact, Rule}, datalog::RunLimits, error::{FailedCheck, Logic, MatchedPolicy, RunLimit, Token}, - Authorizer, UnverifiedBiscuit, + Authorizer, AuthorizerBuilder, UnverifiedBiscuit, }; use chrono::offset::Utc; use serde::Serialize; use serde_json::json; +use std::path::PathBuf; use std::{fmt::Display, fs}; -use std::{path::PathBuf, time::Duration}; use crate::cli::*; use crate::errors::CliError::*; use crate::input::*; -#[derive(Serialize)] +#[derive(Serialize, Debug)] struct TokenBlock { code: String, external_key: Option, revocation_id: String, } -#[derive(Serialize)] +#[derive(Serialize, Debug)] struct TokenDescription { sealed: bool, root_key_id: Option, @@ -65,7 +65,7 @@ impl Display for TokenDescription { } } -#[derive(Copy, Clone, Serialize)] +#[derive(Copy, Clone, Serialize, Debug)] #[serde(untagged)] enum RResult { Ok(A), @@ -82,6 +82,13 @@ impl From> for RResult { } impl RResult { + pub fn is_err(&self) -> bool { + match self { + Self::Ok(_) => false, + Self::Err { .. } => true, + } + } + pub fn into_result(self) -> std::result::Result { match self { Self::Ok(a) => Ok(a), @@ -90,20 +97,29 @@ impl RResult { } } -#[derive(Serialize)] +#[derive(Serialize, Debug)] struct QueryResult { query: String, query_all: bool, facts: RResult, Token>, + elapsed_micros: u128, } impl Display for QueryResult { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { writeln!(f)?; if self.query_all { - writeln!(f, "🔎 Running query on all facts: {}", &self.query)?; + writeln!( + f, + "🔎 Running query on all facts: {} ({}μs)", + &self.query, self.elapsed_micros + )?; } else { - writeln!(f, "🔎 Running query: {}", &self.query)?; + writeln!( + f, + "🔎 Running query: {} ({}μs)", + &self.query, self.elapsed_micros + )?; } match &self.facts.clone().into_result() { Ok(facts) => { @@ -123,12 +139,12 @@ impl Display for QueryResult { } } -#[derive(Serialize)] +#[derive(Serialize, Debug)] struct AuthResult { policies: Vec, result: RResult<(usize, String), Token>, iterations: u64, - elapsed: Duration, + elapsed_micros: Option, } impl Display for AuthResult { @@ -138,7 +154,9 @@ impl Display for AuthResult { writeln!( f, "✅ Authorizer check succeeded 🛡️ ({}μs, {} iterations)", - self.elapsed.as_micros(), + self.elapsed_micros + .map(|e| e.to_string()) + .unwrap_or("n/a".to_string()), self.iterations, )?; writeln!(f, "Matched allow policy: {}", policy) @@ -147,7 +165,9 @@ impl Display for AuthResult { writeln!( f, "❌ Authorizer check failed 🛡️ ({}μs, {} iterations)", - self.elapsed.as_micros(), + self.elapsed_micros + .map(|e| e.to_string()) + .unwrap_or("n/a".to_string()), self.iterations, )?; match e { @@ -160,7 +180,7 @@ impl Display for AuthResult { } } -#[derive(Serialize)] +#[derive(Serialize, Debug)] pub struct InspectionResults { token: TokenDescription, signatures_check: Option, @@ -216,54 +236,80 @@ impl InspectionResults { struct SnapshotDescription { code: String, iterations: u64, - elapsed_micros: u128, + elapsed_micros: Option, + already_evaluated: bool, } impl Display for SnapshotDescription { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { writeln!(f, "{}", self.code)?; - writeln!( - f, - "⏱️ Execution time: {}μs ({} iterations)", - self.elapsed_micros, self.iterations - ) + if let Some(elapsed_micros) = self.elapsed_micros { + writeln!( + f, + "⏱️ Execution time: {}μs ({} iterations)", + elapsed_micros, self.iterations + ) + } else { + writeln!(f, "⏱️ Execution time: not evaluated yet") + } } } #[derive(Serialize)] pub struct SnapshotInspectionResults { - snapshot: SnapshotDescription, - auth: Option, - query: Option, + contents: SnapshotDescription, + evaluation: RResult, } impl Display for SnapshotInspectionResults { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.snapshot.fmt(f)?; + self.contents.fmt(f)?; - match &self.auth { - None => writeln!(f, "🙈 Datalog check skipped 🛡️")?, - Some(auth_result) => auth_result.fmt(f)?, + match &self.evaluation { + RResult::Ok(r) => r.fmt(f), + RResult::Err { error } => writeln!(f, "❌ Evaluation failed: {}", error), + } + } +} + +impl SnapshotInspectionResults { + pub fn ensure_success(&self) -> Result<()> { + match self.evaluation { + RResult::Ok(ref eval_result) => eval_result.ensure_success(), + RResult::Err { .. } => Err(EvaluationFailed)?, } + } +} + +#[derive(Serialize, Debug)] +pub struct SnapshotEvaluationResults { + iterations: u64, + auth: AuthResult, + query: Option, +} + +impl Display for SnapshotEvaluationResults { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.auth.fmt(f)?; match &self.query { None => Ok(()), Some(query_result) => query_result.fmt(f), - } + }?; + + Ok(()) } } -impl SnapshotInspectionResults { +impl SnapshotEvaluationResults { pub fn ensure_success(&self) -> Result<()> { - if let Some(ref auth) = self.auth { - if auth.result.clone().into_result().is_err() { - Err(AuthorizationFailed)?; - } + if self.auth.result.is_err() { + Err(AuthorizationFailed)?; } - if let Some(ref query) = self.query { - if query.facts.clone().into_result().is_err() { + if let Some(ref query_result) = self.query { + if query_result.facts.is_err() { Err(QueryFailed)?; } } @@ -277,7 +323,7 @@ fn handle_query( query_all: bool, all_params: &[Param], authorizer: &mut Authorizer, -) -> Result { +) -> std::result::Result { let mut rule = query.clone(); for p in all_params { @@ -303,6 +349,10 @@ fn handle_query( facts: facts .map(|fs| fs.iter().map(|f| f.to_string()).collect::>()) .into(), + elapsed_micros: authorizer + .execution_time() + .expect("Missing execution time") + .as_micros(), }) } @@ -390,8 +440,7 @@ pub fn handle_inspect_inner(inspect: &Inspect) -> Result { let external_key = external_keys .get(i) .expect("Incorrect block index") - .clone() - .map(hex::encode); + .map(|pk| pk.to_string()); blocks.push(TokenBlock { code: biscuit.print_block_source(i)?, external_key, @@ -413,36 +462,34 @@ pub fn handle_inspect_inner(inspect: &Inspect) -> Result { let query_result; if let Some(key_from) = public_key_from { - let key = read_public_key_from(&key_from)?; + let key = read_public_key_from(&key_from, inspect.key_algorithm)?; let sig_result = biscuit.verify(key); signatures_check = Some(sig_result.is_ok()); if let Ok(biscuit) = sig_result { - let mut authorizer_builder = biscuit.authorizer()?; + let mut authorizer_builder = AuthorizerBuilder::new(); if let Some(auth_from) = authorizer_from { - read_authorizer_from( - &auth_from, - &inspect.param_arg.param, - &mut authorizer_builder, - )?; + authorizer_builder = + read_authorizer_from(&auth_from, &inspect.param_arg.param, authorizer_builder)?; if inspect.authorization_args.include_time { let now = Utc::now().to_rfc3339(); let time_fact = format!("time({})", now); - authorizer_builder.add_fact(time_fact.as_ref())?; + authorizer_builder = authorizer_builder.fact(time_fact.as_ref())?; } - let (_, _, _, policies) = authorizer_builder.dump(); + let mut authorizer = authorizer_builder.build(&biscuit)?; + let (_, _, _, policies) = authorizer.dump(); - let authorizer_result = authorizer_builder.authorize_with_limits(RunLimits { + let authorizer_result = authorizer.authorize_with_limits(RunLimits { max_facts: inspect - .authorization_args + .run_limits_args .max_facts .unwrap_or_else(|| RunLimits::default().max_facts), max_iterations: inspect - .authorization_args + .run_limits_args .max_iterations .unwrap_or_else(|| RunLimits::default().max_iterations), max_time: inspect - .authorization_args + .run_limits_args .max_time .map_or_else(|| RunLimits::default().max_time, |d| d.to_std().unwrap()), }); @@ -457,16 +504,16 @@ pub fn handle_inspect_inner(inspect: &Inspect) -> Result { ) }) .into(), - iterations: authorizer_builder.iterations(), - elapsed: authorizer_builder.execution_time(), + iterations: authorizer.iterations(), + elapsed_micros: authorizer.execution_time().map(|e| e.as_micros()), }); if let Some(snapshot_file) = &inspect.dump_snapshot_to { if inspect.dump_raw_snapshot { - let bytes = authorizer_builder.to_raw_snapshot()?; + let bytes = authorizer.to_raw_snapshot()?; fs::write(snapshot_file, bytes)?; } else { - let str = authorizer_builder.to_base64_snapshot()?; + let str = authorizer.to_base64_snapshot()?; fs::write(snapshot_file, str)?; } } @@ -476,19 +523,20 @@ pub fn handle_inspect_inner(inspect: &Inspect) -> Result { query, inspect.query_args.query_all, &inspect.param_arg.param, - &mut authorizer_builder, + &mut authorizer, )?); } else { query_result = None; } } else { auth_result = None; + let mut authorizer = biscuit.authorizer()?; if let Some(query) = &inspect.query_args.query { query_result = Some(handle_query( query, inspect.query_args.query_all, &inspect.param_arg.param, - &mut authorizer_builder, + &mut authorizer, )?); } else { query_result = None; @@ -550,92 +598,83 @@ pub fn handle_inspect_snapshot_inner( BiscuitBytes::FromFile(snapshot_format, inspect_snapshot.snapshot_file.clone()) }; - let authorizer_from = match ( - &inspect_snapshot.authorization_args.authorize_interactive, - &inspect_snapshot.authorization_args.authorize_with, - &inspect_snapshot.authorization_args.authorize_with_file, - ) { - (false, None, None) => None, - (true, None, None) => Some(DatalogInput::FromEditor), - (false, Some(str), None) => Some(DatalogInput::DatalogString(str.to_owned())), - (false, None, Some(path)) => Some(DatalogInput::FromFile(path.to_path_buf())), - // the other combinations are prevented by clap - _ => unreachable!(), - }; - - if let Some(vf) = &authorizer_from { - ensure_no_input_conflict(vf, &snapshot_from)?; - } - let mut authorizer = read_snapshot_from(&snapshot_from)?; - let snapshot_description = SnapshotDescription { + + let contents = SnapshotDescription { code: authorizer.to_string(), iterations: authorizer.iterations(), - elapsed_micros: authorizer.execution_time().as_micros(), + elapsed_micros: authorizer.execution_time().map(|d| d.as_micros()), + already_evaluated: authorizer.execution_time().is_some(), }; - let auth_result; - let query_result; + let evaluation = handle_snapshot_evaluation(inspect_snapshot, &mut authorizer); - if let Some(auth_from) = authorizer_from { - read_authorizer_from( - &auth_from, - &inspect_snapshot.param_arg.param, - &mut authorizer, - )?; - if inspect_snapshot.authorization_args.include_time { - let now = Utc::now().to_rfc3339(); - let time_fact = format!("time({})", now); - authorizer.add_fact(time_fact.as_ref())?; - } - let (_, _, _, policies) = authorizer.dump(); - - let authorizer_result = authorizer.authorize_with_limits(RunLimits { - max_facts: inspect_snapshot - .authorization_args - .max_facts - .unwrap_or_else(|| RunLimits::default().max_facts), - max_iterations: inspect_snapshot - .authorization_args - .max_iterations - .unwrap_or_else(|| RunLimits::default().max_iterations), - max_time: inspect_snapshot - .authorization_args - .max_time - .map_or_else(|| RunLimits::default().max_time, |d| d.to_std().unwrap()), - }); - auth_result = Some(AuthResult { - policies: policies.iter().map(|p| p.to_string()).collect::>(), - result: authorizer_result - .map(|i| { - ( - i, - policies.get(i).expect("Incorrect policy index").to_string(), - ) - }) - .into(), - iterations: authorizer.iterations(), - elapsed: authorizer.execution_time(), - }); - } else { - auth_result = None; - } + Ok(SnapshotInspectionResults { + contents, + evaluation: evaluation.into(), + }) +} - if let Some(query) = &inspect_snapshot.query_args.query { - query_result = Some(handle_query( - query, - inspect_snapshot.query_args.query_all, - &inspect_snapshot.param_arg.param, - &mut authorizer, - )?); - } else { - query_result = None; - } +fn handle_snapshot_evaluation( + inspect_snapshot: &InspectSnapshot, + authorizer: &mut Authorizer, +) -> std::result::Result { + let _ = authorizer.run()?; + + let (_, _, _, policies) = authorizer.dump(); + let policies: Vec = policies.into_iter().map(|p| p.to_string()).collect(); + + let authorizer_result = authorizer.authorize_with_limits(RunLimits { + max_facts: inspect_snapshot + .run_limits_args + .max_facts + .unwrap_or_else(|| RunLimits::default().max_facts), + max_iterations: inspect_snapshot + .run_limits_args + .max_iterations + .unwrap_or_else(|| RunLimits::default().max_iterations), + max_time: inspect_snapshot + .run_limits_args + .max_time + .map_or_else(|| RunLimits::default().max_time, |d| d.to_std().unwrap()), + }); + + let result = match authorizer_result { + Ok(policy_id) => RResult::Ok(( + policy_id, + policies + .get(policy_id) + .expect("Incorrect policy index") + .to_string(), + )), + Err(e) => RResult::Err { error: e }, + }; - Ok(SnapshotInspectionResults { - snapshot: snapshot_description, - auth: auth_result, - query: query_result, + let auth = AuthResult { + policies, + result, + iterations: authorizer.iterations(), + elapsed_micros: authorizer.execution_time().map(|e| e.as_micros()), + }; + + let query = inspect_snapshot + .query_args + .query + .as_ref() + .map(|query| { + handle_query( + query, + inspect_snapshot.query_args.query_all, + &inspect_snapshot.param_arg.param, + authorizer, + ) + }) + .transpose()?; + + Ok(SnapshotEvaluationResults { + iterations: authorizer.iterations(), + auth, + query, }) } diff --git a/src/main.rs b/src/main.rs index 51fd951..8d9daac 100644 --- a/src/main.rs +++ b/src/main.rs @@ -62,7 +62,7 @@ fn handle_keypair(key_pair_cmd: &KeyPairCmd) -> Result<()> { }; let private_key: Option = if let Some(f) = private_key_from { - Some(read_private_key_from(f)?) + Some(read_private_key_from(f, key_pair_cmd.key_algorithm)?) } else { None }; @@ -70,7 +70,7 @@ fn handle_keypair(key_pair_cmd: &KeyPairCmd) -> Result<()> { let key_pair = if let Some(private) = private_key { KeyPair::from(&private) } else { - KeyPair::new() + KeyPair::new_with_algorithm(key_pair_cmd.key_algorithm) }; match ( @@ -116,32 +116,35 @@ fn handle_generate(generate: &Generate) -> Result<()> { None => DatalogInput::FromEditor, }; - let private_key: Result = read_private_key_from(&match ( - &generate.private_key, - &generate.private_key_file, - &generate.raw_private_key, - ) { - (Some(hex_string), None, false) => KeyBytes::HexString(hex_string.to_owned()), - (None, Some(file), true) => KeyBytes::FromFile(KeyFormat::RawBytes, file.to_path_buf()), - (None, Some(file), false) => KeyBytes::FromFile(KeyFormat::HexKey, file.to_path_buf()), - // the other combinations are prevented by clap - _ => unreachable!(), - }); + let private_key: Result = read_private_key_from( + &match ( + &generate.private_key, + &generate.private_key_file, + &generate.raw_private_key, + ) { + (Some(hex_string), None, false) => KeyBytes::HexString(hex_string.to_owned()), + (None, Some(file), true) => KeyBytes::FromFile(KeyFormat::RawBytes, file.to_path_buf()), + (None, Some(file), false) => KeyBytes::FromFile(KeyFormat::HexKey, file.to_path_buf()), + // the other combinations are prevented by clap + _ => unreachable!(), + }, + generate.key_algorithm, + ); let root = KeyPair::from(&private_key?); let mut builder = Biscuit::builder(); - read_authority_from( + builder = read_authority_from( &authority_from, &generate.param_arg.param, &generate.context, - &mut builder, + builder, )?; if let Some(ttl) = &generate.add_ttl { - builder.check_expiration_date(ttl.to_datetime().into()); + builder = builder.check_expiration_date(ttl.to_datetime().into()); } if let Some(root_key_id) = &generate.root_key_id { - builder.set_root_key_id(*root_key_id); + builder = builder.root_key_id(*root_key_id); } let biscuit = builder.build(&root).expect("Error building biscuit"); // todo display error let encoded = if generate.raw { @@ -188,15 +191,15 @@ fn handle_attenuate(attenuate: &Attenuate) -> Result<()> { let biscuit = read_biscuit_from(&biscuit_from)?; let mut block_builder = BlockBuilder::new(); - read_block_from( + block_builder = read_block_from( &block_from, &attenuate.param_arg.param, &attenuate.block_args.context, - &mut block_builder, + block_builder, )?; if let Some(ttl) = &attenuate.block_args.add_ttl { - block_builder.check_expiration_date(ttl.to_datetime().into()); + block_builder = block_builder.check_expiration_date(ttl.to_datetime().into()); } let new_biscuit = biscuit.append(block_builder)?; @@ -269,30 +272,33 @@ fn handle_generate_third_party_block( ensure_no_input_conflict(&block_from, &request_from)?; - let private_key: Result = read_private_key_from(&match ( - &generate_third_party_block.private_key, - &generate_third_party_block.private_key_file, - &generate_third_party_block.raw_private_key, - ) { - (Some(hex_string), None, false) => KeyBytes::HexString(hex_string.to_owned()), - (None, Some(file), true) => KeyBytes::FromFile(KeyFormat::RawBytes, file.to_path_buf()), - (None, Some(file), false) => KeyBytes::FromFile(KeyFormat::HexKey, file.to_path_buf()), - // the other combinations are prevented by clap - _ => unreachable!(), - }); + let private_key: Result = read_private_key_from( + &match ( + &generate_third_party_block.private_key, + &generate_third_party_block.private_key_file, + &generate_third_party_block.raw_private_key, + ) { + (Some(hex_string), None, false) => KeyBytes::HexString(hex_string.to_owned()), + (None, Some(file), true) => KeyBytes::FromFile(KeyFormat::RawBytes, file.to_path_buf()), + (None, Some(file), false) => KeyBytes::FromFile(KeyFormat::HexKey, file.to_path_buf()), + // the other combinations are prevented by clap + _ => unreachable!(), + }, + generate_third_party_block.key_algorithm, + ); let request = read_request_from(&request_from)?; let mut builder = BlockBuilder::new(); - read_block_from( + builder = read_block_from( &block_from, &generate_third_party_block.param_arg.param, &generate_third_party_block.block_args.context, - &mut builder, + builder, )?; if let Some(ttl) = &generate_third_party_block.block_args.add_ttl { - builder.check_expiration_date(ttl.to_datetime().into()); + builder = builder.check_expiration_date(ttl.to_datetime().into()); } let block = request.create_block(&private_key?, builder)?; From edb136c0fd994b43685edaec892fda07e9d800f1 Mon Sep 17 00:00:00 2001 From: Clement Delafargue Date: Thu, 16 Jan 2025 15:27:23 +0100 Subject: [PATCH 3/6] inspect: allow dumping and loading policies snapshot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A policies snapshot is built from an `AuthorizerBuilder`, and does not contain a biscuit. It allows to easily share authorizer contents that can be added to a biscuit during verification. Name is not set in stone. I don’t think using `AuthorizerBuilder` in the CLI would make a lot of sense, since it’s really tied to the rust implementation --- src/cli.rs | 41 +++++++++++++++++++++++++++++++++++--- src/input.rs | 45 +++++++++++++++++++++++++++++++++++++++--- src/inspect.rs | 53 ++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 123 insertions(+), 16 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index 3c7b2ab..c7eab10 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -16,8 +16,8 @@ pub struct Opts { pub enum SubCommand { #[clap(name = "keypair")] KeyPairCmd(KeyPairCmd), - Inspect(Inspect), - InspectSnapshot(InspectSnapshot), + Inspect(Box), + InspectSnapshot(Box), Generate(Generate), Attenuate(Attenuate), GenerateRequest(GenerateRequest), @@ -166,6 +166,12 @@ pub struct Inspect { /// Output the snapshot raw bytes directly, with no base64 encoding #[clap(long, requires("dump-snapshot-to"))] pub dump_raw_snapshot: bool, + /// Save an authorizer builder snapshot to a file + #[clap(long, parse(from_os_str))] + pub dump_policies_snapshot_to: Option, + /// Output the snapshot raw bytes directly, with no base64 encoding + #[clap(long, requires("dump-snapshot-to"))] + pub dump_raw_raw_policies_snapshot: bool, } /// Inspect a snapshot @@ -305,7 +311,9 @@ mod common_args { long, alias("verify-interactive"), conflicts_with("authorize-with"), - conflicts_with("authorize-with-file") + conflicts_with("authorize-with-file"), + conflicts_with("authorize-with-snapshot"), + conflicts_with("authorize-with-snapshot-file") )] pub authorize_interactive: bool, /// Authorize the biscuit with the provided authorizer. @@ -314,6 +322,8 @@ mod common_args { parse(from_os_str), alias("verify-with-file"), conflicts_with("authorize-with"), + conflicts_with("authorize-with-snapshot"), + conflicts_with("authorize-with-snapshot-file"), conflicts_with("authorize-interactive") )] pub authorize_with_file: Option, @@ -322,9 +332,34 @@ mod common_args { long, alias("verify-with"), conflicts_with("authorize-with-file"), + conflicts_with("authorize-with-snapshot"), + conflicts_with("authorize-with-snapshot-file"), conflicts_with("authorize-interactive") )] pub authorize_with: Option, + /// Authorize the biscuit with the provided snapshot + /// The snapshot must not be evaluated + #[clap( + long, + conflicts_with("authorize-with"), + conflicts_with("authorize-with-file"), + conflicts_with("authorize-with-snapshot-file"), + conflicts_with("authorize-interactive") + )] + pub authorize_with_snapshot: Option, + /// Authorize the biscuit with the provided snapshot + /// The snapshot must not be evaluated + #[clap( + long, + conflicts_with("authorize-with"), + conflicts_with("authorize-with-file"), + conflicts_with("authorize-with-snapshot"), + conflicts_with("authorize-interactive") + )] + pub authorize_with_snapshot_file: Option, + /// Read the snapshot from a binary file + #[clap(long, requires("authorize-with-snapshot-file"))] + pub authorize_with_raw_snapshot_file: bool, /// Include the current time in the verifier facts #[clap(long)] pub include_time: bool, diff --git a/src/input.rs b/src/input.rs index bbe33d5..b6e18d7 100644 --- a/src/input.rs +++ b/src/input.rs @@ -51,6 +51,16 @@ pub enum DatalogInput { DatalogString(String), } +pub enum AuthorizerInput { + FromDatalog(DatalogInput, Vec), + FromSnapshot(SnapshotInput), +} + +pub enum SnapshotInput { + FromFile(PathBuf, BiscuitFormat), + FromString(String), +} + pub fn ensure_no_input_conflict(datalog: &DatalogInput, biscuit: &BiscuitBytes) -> Result<()> { match (datalog, biscuit) { // running $EDITOR as a child process requires a working stdin. When contents from stdin has already been read, this is @@ -200,10 +210,18 @@ pub fn read_block_from( Ok(builder) } -pub fn read_authorizer_from( +pub fn read_authorizer_from(from: &AuthorizerInput) -> Result { + match from { + AuthorizerInput::FromDatalog(datalog, all_params) => { + read_authorizer_from_datalog(datalog, all_params) + } + AuthorizerInput::FromSnapshot(snapshot) => read_authorizer_from_snapshot(snapshot), + } +} + +pub fn read_authorizer_from_datalog( from: &DatalogInput, all_params: &[Param], - builder: AuthorizerBuilder, ) -> Result { let string = match from { DatalogInput::FromEditor => read_editor_string()?, @@ -224,13 +242,34 @@ pub fn read_authorizer_from( } } } - let builder = builder + let builder = AuthorizerBuilder::new() .code_with_params(&string, params, scope_params) .map_err(|e| ParseError("datalog statements".to_string(), e.to_string()))?; Ok(builder) } +fn read_authorizer_from_snapshot( + snapshot: &SnapshotInput, +) -> std::result::Result { + let builder = match snapshot { + SnapshotInput::FromFile(path, BiscuitFormat::RawBiscuit) => { + AuthorizerBuilder::from_raw_snapshot( + &fs::read(path).map_err(|_| FileNotFound(path.clone()))?, + )? + } + SnapshotInput::FromFile(path, BiscuitFormat::Base64Biscuit) => { + AuthorizerBuilder::from_base64_snapshot( + fs::read_to_string(path) + .map_err(|_| FileNotFound(path.clone()))? + .trim(), + )? + } + SnapshotInput::FromString(str) => AuthorizerBuilder::from_base64_snapshot(str)?, + }; + Ok(builder) +} + pub fn read_private_key_from(from: &KeyBytes, alg: Algorithm) -> Result { let bytes = match from { KeyBytes::FromStdin(KeyFormat::RawBytes) => read_stdin_bytes()?, diff --git a/src/inspect.rs b/src/inspect.rs index a73b440..b3dcd50 100644 --- a/src/inspect.rs +++ b/src/inspect.rs @@ -3,7 +3,7 @@ use biscuit_auth::{ builder::{Fact, Rule}, datalog::RunLimits, error::{FailedCheck, Logic, MatchedPolicy, RunLimit, Token}, - Authorizer, AuthorizerBuilder, UnverifiedBiscuit, + Authorizer, UnverifiedBiscuit, }; use chrono::offset::Utc; use serde::Serialize; @@ -412,17 +412,41 @@ pub fn handle_inspect_inner(inspect: &Inspect) -> Result { &inspect.authorization_args.authorize_interactive, &inspect.authorization_args.authorize_with, &inspect.authorization_args.authorize_with_file, + &inspect.authorization_args.authorize_with_snapshot, + &inspect.authorization_args.authorize_with_snapshot_file, ) { - (false, None, None) => None, - (true, None, None) => Some(DatalogInput::FromEditor), - (false, Some(str), None) => Some(DatalogInput::DatalogString(str.to_owned())), - (false, None, Some(path)) => Some(DatalogInput::FromFile(path.to_path_buf())), + (false, None, None, None, None) => None, + (true, None, None, None, None) => Some(AuthorizerInput::FromDatalog( + DatalogInput::FromEditor, + inspect.param_arg.param.clone(), + )), + (false, Some(str), None, None, None) => Some(AuthorizerInput::FromDatalog( + DatalogInput::DatalogString(str.to_owned()), + inspect.param_arg.param.clone(), + )), + (false, None, Some(path), None, None) => Some(AuthorizerInput::FromDatalog( + DatalogInput::FromFile(path.to_path_buf()), + inspect.param_arg.param.clone(), + )), + (false, None, None, Some(str), None) => Some(AuthorizerInput::FromSnapshot( + SnapshotInput::FromString(str.to_owned()), + )), + (false, None, None, None, Some(path)) => { + Some(AuthorizerInput::FromSnapshot(SnapshotInput::FromFile( + path.to_path_buf(), + if inspect.authorization_args.authorize_with_raw_snapshot_file { + BiscuitFormat::RawBiscuit + } else { + BiscuitFormat::Base64Biscuit + }, + ))) + } // the other combinations are prevented by clap _ => unreachable!(), }; - if let Some(vf) = &authorizer_from { - ensure_no_input_conflict(vf, &biscuit_from)?; + if let Some(AuthorizerInput::FromDatalog(dlf, _)) = &authorizer_from { + ensure_no_input_conflict(dlf, &biscuit_from)?; } if inspect.query_args.query.is_some() && public_key_from.is_none() { @@ -467,15 +491,24 @@ pub fn handle_inspect_inner(inspect: &Inspect) -> Result { signatures_check = Some(sig_result.is_ok()); if let Ok(biscuit) = sig_result { - let mut authorizer_builder = AuthorizerBuilder::new(); + let mut authorizer_builder; if let Some(auth_from) = authorizer_from { - authorizer_builder = - read_authorizer_from(&auth_from, &inspect.param_arg.param, authorizer_builder)?; + authorizer_builder = read_authorizer_from(&auth_from)?; if inspect.authorization_args.include_time { let now = Utc::now().to_rfc3339(); let time_fact = format!("time({})", now); authorizer_builder = authorizer_builder.fact(time_fact.as_ref())?; } + if let Some(policies_snapshot_file) = &inspect.dump_policies_snapshot_to { + if inspect.dump_raw_raw_policies_snapshot { + let bytes = authorizer_builder.to_raw_snapshot()?; + fs::write(policies_snapshot_file, bytes)?; + } else { + let str = authorizer_builder.to_base64_snapshot()?; + fs::write(policies_snapshot_file, str)?; + } + } + let mut authorizer = authorizer_builder.build(&biscuit)?; let (_, _, _, policies) = authorizer.dump(); From 87277e74af694cc45723eac8da3e8b4694600986 Mon Sep 17 00:00:00 2001 From: Clement Delafargue Date: Mon, 20 Jan 2025 15:38:49 +0100 Subject: [PATCH 4/6] use prefixed versions for public & private key string representations Public and Private keys are now using the following string format everywhere: `{algorithm}/{bytes}` `--key-algorithm` is now used when reading binary input, or to assert an algorithm when reading a key from a string. --- README.md | 6 ++-- src/cli.rs | 22 +++++++----- src/input.rs | 92 ++++++++++++++++++++++++++++++++++++-------------- src/inspect.rs | 2 +- src/main.rs | 19 +++++------ 5 files changed, 91 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 3209c0e..8edba58 100644 --- a/README.md +++ b/README.md @@ -39,8 +39,8 @@ Here are a list of common use-cases: $ # this will output the keypair, you can then copy/paste the components $ biscuit keypair > Generating a new random keypair -> Private key: d1e3ebc3f522cc2f7bb40c2377830d834c41ebeb0aa54d881a75059704dfa6cb -> Public key: 80c596ea5a6ade1a2f8e7bf96359732d9274789d8e85c0a0a62adbff16f4b289 +> Private key: ed25519/d1e3ebc3f522cc2f7bb40c2377830d834c41ebeb0aa54d881a75059704dfa6cb +> Public key: ed25519/80c596ea5a6ade1a2f8e7bf96359732d9274789d8e85c0a0a62adbff16f4b289 $ # this will save the private key to a file so you can use it later $ biscuit keypair --only-private-key > private-key-file @@ -50,7 +50,7 @@ $ biscuit keypair --only-private-key > private-key-file ```sh $ biscuit keypair --from-private-key-file private-key-file --only-public-key -> 2341bc530d8f074100734a41cc05cc82e4e2564eff61b0408f8e37a08f384767 +> ed25519/2341bc530d8f074100734a41cc05cc82e4e2564eff61b0408f8e37a08f384767 ``` ### Create a biscuit token diff --git a/src/cli.rs b/src/cli.rs index c7eab10..51533e2 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -36,7 +36,11 @@ pub struct KeyPairCmd { #[clap(long, parse(from_os_str))] pub from_private_key_file: Option, /// Read the private key raw bytes directly, with no hex decoding - #[clap(long, requires("from-private-key-file"))] + #[clap( + long, + requires("from-private-key-file"), + conflicts_with("from-private-key") + )] pub from_raw_private_key: bool, /// Only output the public part of the key pair #[clap(long, conflicts_with("only-private-key"))] @@ -51,8 +55,8 @@ pub struct KeyPairCmd { #[clap(long, requires("only-private-key"))] pub raw_private_key_output: bool, /// Key algorithm: ed25519 (default) or secp256r1 - #[clap(long, default_value_t)] - pub key_algorithm: Algorithm, + #[clap(long)] + pub key_algorithm: Option, } /// Generate a biscuit from a private key and an authority block @@ -84,8 +88,8 @@ pub struct Generate { #[clap(long, conflicts_with = "private-key", requires = "private-key-file")] pub raw_private_key: bool, /// Key algorithm: ed25519 (default) or secp256r1 - #[clap(long, default_value_t)] - pub key_algorithm: Algorithm, + #[clap(long)] + pub key_algorithm: Option, /// The optional context string attached to the authority block #[clap(long)] pub context: Option, @@ -150,8 +154,8 @@ pub struct Inspect { #[clap(long, requires("public-key-file"), conflicts_with("public-key"))] pub raw_public_key: bool, /// Key algorithm: ed25519 (default) or secp256r1 - #[clap(long, default_value_t)] - pub key_algorithm: Algorithm, + #[clap(long)] + pub key_algorithm: Option, #[clap(flatten)] pub run_limits_args: common_args::RunLimitArgs, #[clap(flatten)] @@ -228,8 +232,8 @@ pub struct GenerateThirdPartyBlock { #[clap(long, conflicts_with = "private-key", requires = "private-key-file")] pub raw_private_key: bool, /// Key algorithm: ed25519 (default) or secp256r1 - #[clap(long, default_value_t)] - pub key_algorithm: Algorithm, + #[clap(long)] + pub key_algorithm: Option, /// Output the block raw bytes directly, with no base64 encoding #[clap(long)] pub raw_output: bool, diff --git a/src/input.rs b/src/input.rs index b6e18d7..49c7dc2 100644 --- a/src/input.rs +++ b/src/input.rs @@ -270,44 +270,84 @@ fn read_authorizer_from_snapshot( Ok(builder) } -pub fn read_private_key_from(from: &KeyBytes, alg: Algorithm) -> Result { - let bytes = match from { - KeyBytes::FromStdin(KeyFormat::RawBytes) => read_stdin_bytes()?, +pub fn read_private_key_from(from: &KeyBytes, alg: &Option) -> Result { + let key = match from { + KeyBytes::FromStdin(KeyFormat::RawBytes) => { + let bytes = read_stdin_bytes()?; + PrivateKey::from_bytes(&bytes, alg.unwrap_or_default()) + .map_err(|e| ParseError("private key".to_string(), format!("{}", &e)))? + } KeyBytes::FromStdin(KeyFormat::HexKey) => { - hex::decode(read_stdin_string("hex-encoded private key")?)? + let str = read_stdin_string("hex-encoded private key")?; + str.parse() + .map_err(|e| ParseError("private key".to_string(), format!("{}", &e)))? } KeyBytes::FromFile(KeyFormat::RawBytes, path) => { - fs::read(path).map_err(|_| FileNotFound(path.clone()))? + let bytes = fs::read(path).map_err(|_| FileNotFound(path.clone()))?; + PrivateKey::from_bytes(&bytes, alg.unwrap_or_default()) + .map_err(|e| ParseError("private key".to_string(), format!("{}", &e)))? } - KeyBytes::FromFile(KeyFormat::HexKey, path) => hex::decode( - fs::read_to_string(path) - .map_err(|_| FileNotFound(path.clone()))? - .trim(), - )?, - KeyBytes::HexString(str) => hex::decode(str)?, + KeyBytes::FromFile(KeyFormat::HexKey, path) => { + let str = fs::read_to_string(path).map_err(|_| FileNotFound(path.clone()))?; + str.parse() + .map_err(|e| ParseError("private key".to_string(), format!("{}", &e)))? + } + KeyBytes::HexString(str) => str + .parse() + .map_err(|e| ParseError("private key".to_string(), format!("{}", &e)))?, }; - PrivateKey::from_bytes(&bytes, alg) - .map_err(|e| ParseError("private key".to_string(), format!("{}", &e)).into()) + let key_alg = key.algorithm().into(); + + if let Some(a) = alg { + if *a != key_alg { + Err(std::io::Error::other(format!( + "Inconsistent algorithm: key algorithm is {}, expected algorithm is {}", + key_alg, a + )))? + } + } + + Ok(key) } -pub fn read_public_key_from(from: &KeyBytes, alg: Algorithm) -> Result { - let bytes = match from { - KeyBytes::FromStdin(KeyFormat::RawBytes) => read_stdin_bytes()?, +pub fn read_public_key_from(from: &KeyBytes, alg: &Option) -> Result { + let key = match from { + KeyBytes::FromStdin(KeyFormat::RawBytes) => { + let bytes = read_stdin_bytes()?; + PublicKey::from_bytes(&bytes, alg.unwrap_or_default()) + .map_err(|e| ParseError("public key".to_string(), format!("{}", &e)))? + } KeyBytes::FromStdin(KeyFormat::HexKey) => { - hex::decode(read_stdin_string("hex-encoded public key")?)? + let str = read_stdin_string("hex-encoded public key")?; + str.parse() + .map_err(|e| ParseError("public key".to_string(), format!("{}", &e)))? } KeyBytes::FromFile(KeyFormat::RawBytes, path) => { - fs::read(path).map_err(|_| FileNotFound(path.clone()))? + let bytes = fs::read(path).map_err(|_| FileNotFound(path.clone()))?; + PublicKey::from_bytes(&bytes, alg.unwrap_or_default()) + .map_err(|e| ParseError("public key".to_string(), format!("{}", &e)))? } - KeyBytes::FromFile(KeyFormat::HexKey, path) => hex::decode( - fs::read_to_string(path) - .map_err(|_| FileNotFound(path.clone()))? - .trim(), - )?, - KeyBytes::HexString(str) => hex::decode(str)?, + KeyBytes::FromFile(KeyFormat::HexKey, path) => { + let str = fs::read_to_string(path).map_err(|_| FileNotFound(path.clone()))?; + str.parse() + .map_err(|e| ParseError("public key".to_string(), format!("{}", &e)))? + } + KeyBytes::HexString(str) => str + .parse() + .map_err(|e| ParseError("public key".to_string(), format!("{}", &e)))?, }; - PublicKey::from_bytes(&bytes, alg) - .map_err(|e| ParseError("public key".to_string(), format!("{}", &e)).into()) + let key_alg = key.algorithm().into(); + + if let Some(a) = alg { + if *a != key_alg { + Err(std::io::Error::other(format!( + "Inconsistent algorithm: key algorithm is {}, expected algorithm is {}", + key_alg, a + )))? + } + } + + Ok(key) } pub fn read_biscuit_from(from: &BiscuitBytes) -> Result { diff --git a/src/inspect.rs b/src/inspect.rs index b3dcd50..43014fd 100644 --- a/src/inspect.rs +++ b/src/inspect.rs @@ -486,7 +486,7 @@ pub fn handle_inspect_inner(inspect: &Inspect) -> Result { let query_result; if let Some(key_from) = public_key_from { - let key = read_public_key_from(&key_from, inspect.key_algorithm)?; + let key = read_public_key_from(&key_from, &inspect.key_algorithm)?; let sig_result = biscuit.verify(key); signatures_check = Some(sig_result.is_ok()); diff --git a/src/main.rs b/src/main.rs index 8d9daac..a25aa6d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -62,7 +62,7 @@ fn handle_keypair(key_pair_cmd: &KeyPairCmd) -> Result<()> { }; let private_key: Option = if let Some(f) = private_key_from { - Some(read_private_key_from(f, key_pair_cmd.key_algorithm)?) + Some(read_private_key_from(f, &key_pair_cmd.key_algorithm)?) } else { None }; @@ -70,7 +70,7 @@ fn handle_keypair(key_pair_cmd: &KeyPairCmd) -> Result<()> { let key_pair = if let Some(private) = private_key { KeyPair::from(&private) } else { - KeyPair::new_with_algorithm(key_pair_cmd.key_algorithm) + KeyPair::new_with_algorithm(key_pair_cmd.key_algorithm.unwrap_or_default()) }; match ( @@ -85,23 +85,20 @@ fn handle_keypair(key_pair_cmd: &KeyPairCmd) -> Result<()> { } else { println!("Generating a new random keypair"); } - println!( - "Private key: {}", - hex::encode(key_pair.private().to_bytes()) - ); - println!("Public key: {}", hex::encode(key_pair.public().to_bytes())); + println!("Private key: {}", key_pair.private().to_prefixed_string()); + println!("Public key: {}", key_pair.public()); } (true, true, false, false) => { let _ = io::stdout().write_all(&key_pair.private().to_bytes()); } (true, false, false, false) => { - println!("{}", hex::encode(key_pair.private().to_bytes())); + println!("{}", key_pair.private().to_prefixed_string()); } (false, false, true, true) => { let _ = io::stdout().write_all(&key_pair.public().to_bytes()); } (false, false, true, false) => { - println!("{}", hex::encode(key_pair.public().to_bytes())); + println!("{}", key_pair.public()); } // the other combinations are prevented by clap _ => unreachable!(), @@ -128,7 +125,7 @@ fn handle_generate(generate: &Generate) -> Result<()> { // the other combinations are prevented by clap _ => unreachable!(), }, - generate.key_algorithm, + &generate.key_algorithm, ); let root = KeyPair::from(&private_key?); @@ -284,7 +281,7 @@ fn handle_generate_third_party_block( // the other combinations are prevented by clap _ => unreachable!(), }, - generate_third_party_block.key_algorithm, + &generate_third_party_block.key_algorithm, ); let request = read_request_from(&request_from)?; From 272fb5f2a9833dbd1e4742d6ec363d0846f5a274 Mon Sep 17 00:00:00 2001 From: Clement Delafargue Date: Mon, 27 Jan 2025 12:00:21 +0100 Subject: [PATCH 5/6] display datalog version in biscuit inspect --- README.md | 6 +++--- src/inspect.rs | 14 +++++++++++++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8edba58..9ad9354 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ By default, `biscuit` inspect only prints out the biscuit contents (datalog bloc $ # this will inspect the token stored in the given file $ biscuit inspect biscuit-file > Authority block: -> == Datalog == +> == Datalog v3.0 == > right("file1"); > > == Revocation id == @@ -91,7 +91,7 @@ A public key can be provided to check the biscuit root key (the command exits wi $ # this will make sure the biscuit root key is the same as the one that's provided $ biscuit inspect --public-key-file public-key-file biscuit-file > Authority block: -> == Datalog == +> == Datalog v3.0 == > right("file1"); > > == Revocation id == @@ -112,7 +112,7 @@ $ biscuit inspect --public-key-file public-key-file \ --authorize-with 'allow if right("file1");' \ biscuit-file > Authority block: -> == Datalog == +> == Datalog v3.0 == > right("file1"); > > == Revocation id == diff --git a/src/inspect.rs b/src/inspect.rs index 43014fd..46acc9b 100644 --- a/src/inspect.rs +++ b/src/inspect.rs @@ -17,6 +17,7 @@ use crate::input::*; #[derive(Serialize, Debug)] struct TokenBlock { + version: u32, code: String, external_key: Option, revocation_id: String, @@ -29,6 +30,16 @@ struct TokenDescription { blocks: Vec, } +fn get_version_string(v: u32) -> String { + match v { + 3 => "v3.0".to_string(), + 4 => "v3.1".to_string(), + 5 => "v3.2".to_string(), + 6 => "v3.3".to_string(), + _ => "(unsupported version)".to_string(), + } +} + impl Display for TokenDescription { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if self.sealed { @@ -54,7 +65,7 @@ impl Display for TokenDescription { writeln!(f, "Block n°{}:", i)?; } - writeln!(f, "== Datalog ==")?; + writeln!(f, "== Datalog {} ==", get_version_string(block.version))?; writeln!(f, "{}", block.code)?; writeln!(f, "== Revocation id ==")?; @@ -472,6 +483,7 @@ pub fn handle_inspect_inner(inspect: &Inspect) -> Result { .get(i) .map(hex::encode) .unwrap_or_else(|| "n/a".to_owned()), + version: biscuit.block_version(i)?, }); } From 624b7fc259f9a3d7c5d133084ed7709a3d14c298 Mon Sep 17 00:00:00 2001 From: Clement Delafargue Date: Mon, 27 Jan 2025 15:36:26 +0100 Subject: [PATCH 6/6] biscuit-cli 0.6.0-beta.1 --- CHANGELOG.md | 8 ++++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c952b5c..4a8b671 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# `0.6.0-beta.1` + +- biscuit-auth 6.0.0-beta.1 + - biscuit-datalog v3.3 support + - ECDSA signatures support + - policy snapshots support +- display datalog version in blocks + # `0.5.0` - biscuit-auth 5.0.0 diff --git a/Cargo.lock b/Cargo.lock index 2327952..1a453c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -99,7 +99,7 @@ dependencies = [ [[package]] name = "biscuit-cli" -version = "0.5.0" +version = "0.6.0-beta.1" dependencies = [ "anyhow", "atty", diff --git a/Cargo.toml b/Cargo.toml index 70b183a..a4d5da1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "biscuit-cli" -version = "0.5.0" +version = "0.6.0-beta.1" description = "a CLI to manipulate biscuit tokens" authors = ["Clement Delafargue "] edition = "2018"