Skip to content

Commit

Permalink
feat: add reject if
Browse files Browse the repository at this point in the history
This acts like the opposite of `check if`: if there is a match, then authorization fails.

Using `reject if` raises the block version to 5
  • Loading branch information
divarvel committed Dec 28, 2023
1 parent 18fca86 commit 63a60a2
Show file tree
Hide file tree
Showing 16 changed files with 279 additions and 20 deletions.
33 changes: 33 additions & 0 deletions biscuit-auth/examples/testcases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ fn main() {

add_test_result(&mut results, expressions_v4(&target, &root, test));

add_test_result(&mut results, reject_if(&target, &root, test));

if json {
let s = serde_json::to_string_pretty(&TestCases {
root_private_key: hex::encode(root.private().to_bytes()),
Expand Down Expand Up @@ -1882,6 +1884,37 @@ fn expressions_v4(target: &str, root: &KeyPair, test: bool) -> TestResult {
}
}

fn reject_if(target: &str, root: &KeyPair, test: bool) -> TestResult {
let mut rng: StdRng = SeedableRng::seed_from_u64(1234);
let title = "test reject if".to_string();
let filename = "test029_reject_if".to_string();
let token;

let biscuit = biscuit!(r#"reject if test($test), $test"#)
.build_with_rng(&root, SymbolTable::default(), &mut rng)
.unwrap();
token = print_blocks(&biscuit);

let data = write_or_load_testcase(target, &filename, root, &biscuit, test);

let mut validations = BTreeMap::new();
validations.insert(
"".to_string(),
validate_token(root, &data[..], "test(false); allow if true"),
);
validations.insert(
"rejection".to_string(),
validate_token(root, &data[..], "test(true); allow if true"),
);

TestResult {
title,
filename,
token,
validations,
}
}

fn print_blocks(token: &Biscuit) -> Vec<BlockContent> {
let mut v = Vec::new();

Expand Down
92 changes: 88 additions & 4 deletions biscuit-auth/samples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1925,7 +1925,7 @@ allow if true;

revocation ids:
- `470e4bf7aa2a01ab39c98150bd06aa15b4aa5d86509044a8809a8634cd8cf2b42269a51a774b65d10bac9369d013070b00187925196a8e680108473f11cf8f03`
- `93a7315ab1272da9eeef015f6fecbc9ac96fe4660e6204bf64ea2105ebe309e9c9cadc0a26c5604f13910fae3f2cd0800756afb6b6b208bf77adeb1ab2f42405`
- `342167bc54bc642b6718a276875e55b6d39e9b21e4ce13b926a3d398b6c057fc436385bf4c817a16f9ecdf0b0d950e8b8258a20aeb3fd8896c5e9c1f0a53da03`

authorizer world:
```
Expand Down Expand Up @@ -2157,9 +2157,9 @@ allow if true;

revocation ids:
- `3771cefe71beb21ead35a59c8116ee82627a5717c0295f35980662abccb159fe1b37848cb1818e548656bd4fd882d0094a2daab631c76b2b72e3a093914bfe04`
- `45133b90f228a81fe4d3042a79f6c6b7608e656e903d6b1f4db32cd774b09b8315af360879a5f210ad7be37ff55e3eb34f237bcc9711407b6329ac6018bfb400`
- `179f054f3c572646aba5013159ae192ac42f5666dbdd984129955f4652b6829e59f54aa251e451f96329d42a2524ce569c3e1ec52e708b642dd8994af51dd703`
- `edab54789d6656936fcd28200b9c61643434842d531f09f209fad555e11ff53174db174dafba126e6de448983a56f78d2042bc5782d71a45799c022fe69fb30d`
- `2d629fdc645be3957e1120a972a63f8914c3258739b6c6822a82919cefacb85d4a8e14bc5e69c79cd1545d269a24dc110a7e955d9203ccb66401a6177558d70a`
- `63bd286ba10e6fa010c997a1a0f0a0accfefc2df32176c48e0196553614da63596a5d99842a8bd7e14d67de0d3edb94df428a1c16ca17695807d06f8a38beb0a`
- `42d1dd9b62e3d4cb3675bcb53c82a4f26f2d7830839b61d4a810eb79853fc1da62bb77e94664e84f5f8cf21610b873984f043b207e49b6f95bb0dc60d445840b`
- `6a62306831e9dbe83e7b33db96b758c77dd690930f2d2d87e239b210b1944c5582bf6d7e1bfea8e7f928c27f2fff0e2ee2e0adc41e11e0c3abe8d7b96b9ede07`

authorizer world:
Expand Down Expand Up @@ -2341,3 +2341,87 @@ World {

result: `Ok(0)`


------------------------------

## test reject if: test029_reject_if.bc
### token

authority:
symbols: ["test"]

public keys: []

```
reject if test($test), $test;
```

### validation

authorizer code:
```
test(false);
allow if true;
```

revocation ids:
- `2060031eb9968b492123440fa9cbc781f18be812961e765a34a8702d3eee0ed54910710efbb41b3141f60748a815012fe0e703a5b5604f4262d1ac7e79766b07`

authorizer world:
```
World {
facts: {
(
"test(false)",
{
None,
},
),
}
rules: {}
checks: {
"reject if test($test), $test",
}
policies: {
"allow if true",
}
}
```

result: `Ok(0)`
### validation for "rejection"

authorizer code:
```
test(true);
allow if true;
```

revocation ids:
- `2060031eb9968b492123440fa9cbc781f18be812961e765a34a8702d3eee0ed54910710efbb41b3141f60748a815012fe0e703a5b5604f4262d1ac7e79766b07`

authorizer world:
```
World {
facts: {
(
"test(true)",
{
None,
},
),
}
rules: {}
checks: {
"reject if test($test), $test",
}
policies: {
"allow if true",
}
}
```

result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedBlockCheck { block_id: 0, check_id: 0, rule: "reject if test($test), $test" })] }))`

93 changes: 89 additions & 4 deletions biscuit-auth/samples/samples.json
Original file line number Diff line number Diff line change
Expand Up @@ -1837,7 +1837,7 @@
"authorizer_code": "allow if true;\n",
"revocation_ids": [
"470e4bf7aa2a01ab39c98150bd06aa15b4aa5d86509044a8809a8634cd8cf2b42269a51a774b65d10bac9369d013070b00187925196a8e680108473f11cf8f03",
"93a7315ab1272da9eeef015f6fecbc9ac96fe4660e6204bf64ea2105ebe309e9c9cadc0a26c5604f13910fae3f2cd0800756afb6b6b208bf77adeb1ab2f42405"
"342167bc54bc642b6718a276875e55b6d39e9b21e4ce13b926a3d398b6c057fc436385bf4c817a16f9ecdf0b0d950e8b8258a20aeb3fd8896c5e9c1f0a53da03"
]
}
}
Expand Down Expand Up @@ -2065,9 +2065,9 @@
"authorizer_code": "check if query(1, 2) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189, ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463;\n\ndeny if query(3);\ndeny if query(1, 2);\ndeny if query(0) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189;\nallow if true;\n",
"revocation_ids": [
"3771cefe71beb21ead35a59c8116ee82627a5717c0295f35980662abccb159fe1b37848cb1818e548656bd4fd882d0094a2daab631c76b2b72e3a093914bfe04",
"45133b90f228a81fe4d3042a79f6c6b7608e656e903d6b1f4db32cd774b09b8315af360879a5f210ad7be37ff55e3eb34f237bcc9711407b6329ac6018bfb400",
"179f054f3c572646aba5013159ae192ac42f5666dbdd984129955f4652b6829e59f54aa251e451f96329d42a2524ce569c3e1ec52e708b642dd8994af51dd703",
"edab54789d6656936fcd28200b9c61643434842d531f09f209fad555e11ff53174db174dafba126e6de448983a56f78d2042bc5782d71a45799c022fe69fb30d",
"2d629fdc645be3957e1120a972a63f8914c3258739b6c6822a82919cefacb85d4a8e14bc5e69c79cd1545d269a24dc110a7e955d9203ccb66401a6177558d70a",
"63bd286ba10e6fa010c997a1a0f0a0accfefc2df32176c48e0196553614da63596a5d99842a8bd7e14d67de0d3edb94df428a1c16ca17695807d06f8a38beb0a",
"42d1dd9b62e3d4cb3675bcb53c82a4f26f2d7830839b61d4a810eb79853fc1da62bb77e94664e84f5f8cf21610b873984f043b207e49b6f95bb0dc60d445840b",
"6a62306831e9dbe83e7b33db96b758c77dd690930f2d2d87e239b210b1944c5582bf6d7e1bfea8e7f928c27f2fff0e2ee2e0adc41e11e0c3abe8d7b96b9ede07"
]
}
Expand Down Expand Up @@ -2150,6 +2150,91 @@
]
}
}
},
{
"title": "test reject if",
"filename": "test029_reject_if.bc",
"token": [
{
"symbols": [
"test"
],
"public_keys": [],
"external_key": null,
"code": "reject if test($test), $test;\n"
}
],
"validations": {
"": {
"world": {
"facts": [
[
"test(false)",
[
null
]
]
],
"rules": [],
"checks": [
"reject if test($test), $test"
],
"policies": [
"allow if true"
]
},
"result": {
"Ok": 0
},
"authorizer_code": "test(false);\n\nallow if true;\n",
"revocation_ids": [
"2060031eb9968b492123440fa9cbc781f18be812961e765a34a8702d3eee0ed54910710efbb41b3141f60748a815012fe0e703a5b5604f4262d1ac7e79766b07"
]
},
"rejection": {
"world": {
"facts": [
[
"test(true)",
[
null
]
]
],
"rules": [],
"checks": [
"reject if test($test), $test"
],
"policies": [
"allow if true"
]
},
"result": {
"Err": {
"FailedLogic": {
"Unauthorized": {
"policy": {
"Allow": 0
},
"checks": [
{
"Block": {
"block_id": 0,
"check_id": 0,
"rule": "reject if test($test), $test"
}
}
]
}
}
}
},
"authorizer_code": "test(true);\n\nallow if true;\n",
"revocation_ids": [
"2060031eb9968b492123440fa9cbc781f18be812961e765a34a8702d3eee0ed54910710efbb41b3141f60748a815012fe0e703a5b5604f4262d1ac7e79766b07"
]
}
}
}
]
}
Binary file modified biscuit-auth/samples/test024_third_party.bc
Binary file not shown.
Binary file modified biscuit-auth/samples/test026_public_keys_interning.bc
Binary file not shown.
Binary file added biscuit-auth/samples/test029_reject_if.bc
Binary file not shown.
23 changes: 20 additions & 3 deletions biscuit-auth/src/datalog/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -840,11 +840,14 @@ pub struct SchemaVersion {
contains_scopes: bool,
contains_v4: bool,
contains_check_all: bool,
contains_reject_if: bool,
}

impl SchemaVersion {
pub fn version(&self) -> u32 {
if self.contains_scopes || self.contains_v4 || self.contains_check_all {
if self.contains_reject_if {
5
} else if self.contains_scopes || self.contains_v4 || self.contains_check_all {
4
} else {
MIN_SCHEMA_VERSION
Expand All @@ -863,11 +866,15 @@ impl SchemaVersion {
))
} else if self.contains_check_all {
Err(error::Format::DeserializationError(
"v3 blocks must not have use all".to_string(),
"v3 blocks must not have check all".to_string(),
))
} else {
Ok(())
}
} else if version < 5 && self.contains_reject_if {
Err(error::Format::DeserializationError(
"v5 blocks must not have reject if".to_string(),
))
} else {
Ok(())
}
Expand All @@ -887,7 +894,16 @@ pub fn get_schema_version(
.iter()
.any(|c: &Check| c.queries.iter().any(|q| !q.scopes.is_empty()));

let contains_check_all = checks.iter().any(|c: &Check| c.kind == CheckKind::All);
let mut contains_check_all = false;
let mut contains_reject_if = false;

for c in checks.iter() {
if c.kind == CheckKind::All {
contains_check_all = true;
} else if c.kind == CheckKind::Reject {
contains_reject_if = true;
}
}

let contains_v4 = rules.iter().any(|rule| contains_v4_op(&rule.expressions))
|| checks.iter().any(|check| {
Expand All @@ -901,6 +917,7 @@ pub fn get_schema_version(
contains_scopes,
contains_v4,
contains_check_all,
contains_reject_if,
}
}

Expand Down
7 changes: 4 additions & 3 deletions biscuit-auth/src/datalog/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,10 +282,11 @@ impl SymbolTable {
.collect::<Vec<_>>();

format!(
"check {} {}",
"{} {}",
match c.kind {
crate::builder::CheckKind::One => "if",
crate::builder::CheckKind::All => "all",
crate::builder::CheckKind::One => "check if",
crate::builder::CheckKind::All => "check all",
crate::builder::CheckKind::Reject => "reject if",
},
queries.join(" or ")
)
Expand Down
19 changes: 15 additions & 4 deletions biscuit-auth/src/format/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,19 @@ pub fn proto_block_to_token_block(
rules.push(v2::proto_rule_to_token_rule(rule, version)?.0);
}

if version == MIN_SCHEMA_VERSION && input.checks_v2.iter().any(|c| c.kind.is_some()) {
return Err(error::Format::DeserializationError(
"deserialization error: v3 blocks must not contain a check kind".to_string(),
));
if version < MAX_SCHEMA_VERSION {
for c in input.checks_v2.iter() {
if version == MIN_SCHEMA_VERSION && c.kind.is_some() {
return Err(error::Format::DeserializationError(
"deserialization error: v3 blocks must not contain a check kind".to_string(),
));
} else if c.kind == Some(schema::check_v2::Kind::Reject as i32) {
return Err(error::Format::DeserializationError(
"deserialization error: v4 blocks must not contain reject if checks"
.to_string(),
));
}
}
}

for check in input.checks_v2.iter() {
Expand Down Expand Up @@ -326,6 +335,7 @@ pub mod v2 {
kind: match input.kind {
crate::token::builder::CheckKind::One => None,
crate::token::builder::CheckKind::All => Some(Kind::All as i32),
crate::token::builder::CheckKind::Reject => Some(Kind::Reject as i32),
},
}
}
Expand All @@ -343,6 +353,7 @@ pub mod v2 {
let kind = match input.kind {
None | Some(0) => crate::token::builder::CheckKind::One,
Some(1) => crate::token::builder::CheckKind::All,
Some(2) => crate::token::builder::CheckKind::Reject,
_ => {
return Err(error::Format::DeserializationError(
"deserialization error: invalid check kind".to_string(),
Expand Down
1 change: 1 addition & 0 deletions biscuit-auth/src/format/schema.proto
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ message CheckV2 {
enum Kind {
One = 0;
All = 1;
Reject = 2;
}
}

Expand Down
Loading

0 comments on commit 63a60a2

Please sign in to comment.