From 4f7b9a4292003437549f78fef0c04d4363126b11 Mon Sep 17 00:00:00 2001 From: Anand Krishnamoorthi <35780660+anakrish@users.noreply.github.com> Date: Fri, 14 Mar 2025 10:49:57 -0700 Subject: [PATCH] fix!: Remove ring dependency (#380) Remove dependency on jsonwebtoken which brings in the ring crate. Ring crate triggers governance violations. Support for JWT will be implemented in future using a more governance compliant crate. BREAKING CHANGE Prior to this PR, support for jwt builtins was minimially implemented. Only io.jwt.decode and io.jwt.decode_verify was implemented. With this PR, those builtins will no longer be available. They are planned to be implemented in the future. In the meantime, they can be brought back in via Engine::add_extension. Signed-off-by: Anand Krishnamoorthi --- Cargo.toml | 4 --- README.md | 6 ++-- bindings/wasm/Cargo.toml | 3 +- src/builtins/jwt.rs | 73 ---------------------------------------- src/builtins/mod.rs | 4 --- src/builtins/opa.rs | 2 -- tests/opa.passing | 2 -- tests/opa.rs | 4 +++ 8 files changed, 10 insertions(+), 88 deletions(-) delete mode 100644 src/builtins/jwt.rs diff --git a/Cargo.toml b/Cargo.toml index 920aa91..4e76e73 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,6 @@ http = [] glob = ["dep:wax"] graph = [] jsonschema = ["dep:jsonschema"] -jwt = ["dep:jsonwebtoken", "dep:data-encoding", "dep:itertools"] no_std = ["lazy_static/spin_no_std"] opa-runtime = [] regex = ["dep:regex"] @@ -53,7 +52,6 @@ full-opa = [ "graph", "hex", "http", - "jwt", "jsonschema", "opa-runtime", "regex", @@ -117,8 +115,6 @@ uuid = { version = "1.15.1", default-features = false, features = ["v4", "fast-r jsonschema = { version = "0.29.0", default-features = false, optional = true } chrono = { version = "0.4.40", optional = true } chrono-tz = { version = "0.10.1", optional = true } -jsonwebtoken = { version = "9.3.1", optional = true } -itertools = { version = "0.14.0", default-features = false, optional = true } serde_yaml = {version = "0.9.16", default-features = false, optional = true } # Specify thread_rng for in order to use random_range diff --git a/README.md b/README.md index 73b6598..c12f3c7 100644 --- a/README.md +++ b/README.md @@ -298,8 +298,11 @@ The following test suites don't pass fully due to missing builtins: - `graphql` - `invalidkeyerror` - `jsonpatch` +- `jwtbuiltins` - `jwtdecodeverify` - `jwtencodesign` +- `jwtencodesignheadererrors` +- `jwtencodesignpayloaderrors` - `jwtencodesignraw` - `jwtverifyhs256` - `jwtverifyhs384` @@ -319,10 +322,9 @@ The following test suites don't pass fully due to missing builtins: - `regoparsemodule` - `rendertemplate` -Cryptographically insecure `sha1` related builtins are intentionally not supported to discourage their use. - They are captured in the following [github issues](https://github.com/microsoft/regorus/issues?q=is%3Aopen+is%3Aissue+label%3Alib). +Cryptographically insecure `sha1` related builtins are intentionally not supported to discourage their use. ### Grammar diff --git a/bindings/wasm/Cargo.toml b/bindings/wasm/Cargo.toml index c67e07b..ee7c30a 100644 --- a/bindings/wasm/Cargo.toml +++ b/bindings/wasm/Cargo.toml @@ -25,7 +25,8 @@ wasm-bindgen = "0.2.100" # when targeting wasm32-unknown-unknown. uuid = { version = "1.15.1", default-features = false, features = ["v4", "fast-rng", "js"]} # Enable wasm_js. See https://docs.rs/getrandom/latest/getrandom/#webassembly-support -getrandom = { version = "0.3", features = ["std", "wasm_js"] } +getrandom_for_jsonschema = { package = "getrandom", version = "0.2.15", features = ["std", "js"] } +getrandom = { version = "0.3.1", features = ["std", "wasm_js"] } [dev-dependencies] wasm-bindgen-test = "0.3.40" diff --git a/src/builtins/jwt.rs b/src/builtins/jwt.rs deleted file mode 100644 index 3cfa594..0000000 --- a/src/builtins/jwt.rs +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -use crate::ast::{Expr, Ref}; -use crate::builtins; -use crate::builtins::utils::{ensure_args_count, ensure_string}; -use crate::*; - -use crate::lexer::Span; -use crate::value::Value; - -use itertools::Itertools; - -use anyhow::{bail, Result}; - -pub fn register(m: &mut builtins::BuiltinsMap<&'static str, builtins::BuiltinFcn>) { - m.insert("io.jwt.decode", (jwt_decode, 1)); - m.insert("io.jwt.decode_verify", (jwt_decode_verify, 2)); -} - -fn decode(span: &Span, jwt: String, strict: bool) -> Result { - let Some((Ok(header), Ok(payload), Ok(signature))) = jwt - .split('.') - .map(|p| data_encoding::BASE64URL_NOPAD.decode(p.as_bytes())) - .collect_tuple() - else { - if strict { - bail!(span.error("invalid jwt token")); - } - return Ok(Value::Undefined); - }; - - let header = String::from_utf8_lossy(&header).to_string(); - let payload = String::from_utf8_lossy(&payload).to_string(); - let signature = data_encoding::HEXLOWER_PERMISSIVE.encode(&signature); - - let signature = Value::String(signature.into()); - let header = Value::from_json_str(&header)?; - - if header["enc"] != Value::Undefined { - bail!(span.error("JWT is a JWE object, which is not supported")); - } - - if header["cty"] == "JWT".into() { - if payload.len() <= 2 || !payload.starts_with('"') || !payload.ends_with('"') { - bail!(span.error("invalid nested JWT")); - } - // Ignore "" - decode(span, payload[1..payload.len() - 1].to_string(), strict) - } else { - let payload = Value::from_json_str(&payload)?; - Ok(Value::from_array([header, payload, signature].into())) - } -} - -fn jwt_decode(span: &Span, params: &[Ref], args: &[Value], strict: bool) -> Result { - let name = "io.jwt.decode"; - ensure_args_count(span, name, params, args, 1)?; - let jwt = ensure_string(name, ¶ms[0], &args[0])?; - - decode(span, jwt.to_string(), strict) //header, payload, signature, strict) -} - -fn jwt_decode_verify( - span: &Span, - params: &[Ref], - args: &[Value], - _strict: bool, -) -> Result { - let name = "io.jwt.decode_verify"; - ensure_args_count(span, name, params, args, 2)?; - Ok(Value::Undefined) -} diff --git a/src/builtins/mod.rs b/src/builtins/mod.rs index adf6c89..5b984f1 100644 --- a/src/builtins/mod.rs +++ b/src/builtins/mod.rs @@ -18,8 +18,6 @@ mod glob; mod graph; #[cfg(feature = "http")] mod http; -#[cfg(feature = "jwt")] -mod jwt; pub mod numbers; mod objects; #[cfg(feature = "opa-runtime")] @@ -83,8 +81,6 @@ lazy_static! { //units::register(&mut m); types::register(&mut m); encoding::register(&mut m); - #[cfg(feature = "jwt")] - jwt::register(&mut m); #[cfg(feature = "time")] time::register(&mut m); diff --git a/src/builtins/opa.rs b/src/builtins/opa.rs index b427b77..56acca5 100644 --- a/src/builtins/opa.rs +++ b/src/builtins/opa.rs @@ -67,8 +67,6 @@ fn opa_runtime(span: &Span, params: &[Ref], args: &[Value], _strict: bool) "hex", #[cfg(feature = "http")] "http", - #[cfg(feature = "jwt")] - "jwt", #[cfg(feature = "jsonschema")] "jsonschema", #[cfg(feature = "opa-runtime")] diff --git a/tests/opa.passing b/tests/opa.passing index 9a41649..ee212a1 100644 --- a/tests/opa.passing +++ b/tests/opa.passing @@ -52,7 +52,6 @@ v0/jsonfilteridempotent v0/jsonremove v0/jsonremoveidempotent v0/jsonschema -v0/jwtbuiltins v0/negation v0/nestedreferences v0/numbersrange @@ -165,7 +164,6 @@ v1/jsonfilteridempotent v1/jsonremove v1/jsonremoveidempotent v1/jsonschema -v1/jwtbuiltins v1/negation v1/nestedreferences v1/numbersrange diff --git a/tests/opa.rs b/tests/opa.rs index e46bd37..7595a7d 100644 --- a/tests/opa.rs +++ b/tests/opa.rs @@ -210,6 +210,10 @@ fn run_opa_tests(opa_tests_dir: String, folders: &[String]) -> Result<()> { if let Some(ref mut want_result) = &mut case.want_result { want_result.as_array_mut()?.sort(); } + } else if case.note == "withkeyword/builtin: nested, multiple mocks" { + // Mocks non-existent jwt builtin. + println!("skipping mock test for io.jwt.decode_verify: {}", case.note); + continue; } // Normalize for comparison.