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 <anakrish@microsoft.com>
This commit is contained in:
Anand Krishnamoorthi
2025-03-14 10:49:57 -07:00
committed by GitHub
parent 4a2df93ae2
commit 4f7b9a4292
8 changed files with 10 additions and 88 deletions
-4
View File
@@ -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
+4 -2
View File
@@ -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
+2 -1
View File
@@ -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"
-73
View File
@@ -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<Value> {
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<Expr>], args: &[Value], strict: bool) -> Result<Value> {
let name = "io.jwt.decode";
ensure_args_count(span, name, params, args, 1)?;
let jwt = ensure_string(name, &params[0], &args[0])?;
decode(span, jwt.to_string(), strict) //header, payload, signature, strict)
}
fn jwt_decode_verify(
span: &Span,
params: &[Ref<Expr>],
args: &[Value],
_strict: bool,
) -> Result<Value> {
let name = "io.jwt.decode_verify";
ensure_args_count(span, name, params, args, 2)?;
Ok(Value::Undefined)
}
-4
View File
@@ -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);
-2
View File
@@ -67,8 +67,6 @@ fn opa_runtime(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool)
"hex",
#[cfg(feature = "http")]
"http",
#[cfg(feature = "jwt")]
"jwt",
#[cfg(feature = "jsonschema")]
"jsonschema",
#[cfg(feature = "opa-runtime")]
-2
View File
@@ -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
+4
View File
@@ -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.