From 26028a7c2ca752ccbdef5d846add44d9c722fe08 Mon Sep 17 00:00:00 2001 From: Malcolm Still Date: Thu, 28 Mar 2024 23:02:48 +0000 Subject: [PATCH] Yay, test018 passes...all the tests pass! --- biscuit-datalog/src/rule.zig | 20 ++++++++++++++++++++ biscuit-samples/src/main.zig | 15 ++++++++++++++- biscuit/src/authorizer.zig | 10 ++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/biscuit-datalog/src/rule.zig b/biscuit-datalog/src/rule.zig index bc93ce4..b1fb127 100644 --- a/biscuit-datalog/src/rule.zig +++ b/biscuit-datalog/src/rule.zig @@ -245,6 +245,26 @@ pub const Rule = struct { } } + /// Checks there a no unbound variables in the head (i.e. every head variable must appear in the ) + pub fn validateVariables(rule: Rule) bool { + blk: for (rule.head.terms.items) |head_term| { + const head_variable = if (head_term == .variable) head_term.variable else continue; + + for (rule.body.items) |body_predicate| { + for (body_predicate.terms.items) |body_term| { + const body_variable = if (head_term == .variable) body_term.variable else continue; + + if (head_variable == body_variable) continue :blk; + } + } + + // We haven't found this loop's head variable anywhere in the body (i.e. the variable is unbound) + return false; + } + + return true; + } + pub fn format(rule: Rule, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void { try writer.print("{any} <- ", .{rule.head}); for (rule.body.items, 0..) |*predicate, i| { diff --git a/biscuit-samples/src/main.zig b/biscuit-samples/src/main.zig index e77611f..a7dda48 100644 --- a/biscuit-samples/src/main.zig +++ b/biscuit-samples/src/main.zig @@ -90,6 +90,7 @@ pub fn validate(alloc: mem.Allocator, token: []const u8, public_key: std.crypto. } }, .failed_authorizer_check => return error.NotImplemented, + .unbound_variable => continue, } } }, @@ -105,6 +106,7 @@ pub fn validate(alloc: mem.Allocator, token: []const u8, public_key: std.crypto. check_accounted_for = true; } }, + .unbound_variable => continue, } } }, @@ -117,7 +119,18 @@ pub fn validate(alloc: mem.Allocator, token: []const u8, public_key: std.crypto. }, else => return err, }, - .InvalidBlockRule => runValidation(alloc, token, public_key, authorizer_code, &errors) catch |err| switch (err) { + .InvalidBlockRule => |_| runValidation(alloc, token, public_key, authorizer_code, &errors) catch |err| switch (err) { + error.AuthorizationFailed => { + for (errors.items) |found_failed_check| { + switch (found_failed_check) { + .no_matching_policy => continue, + .denied_by_policy => continue, + .failed_block_check => continue, + .failed_authorizer_check => return error.NotImplemented, + .unbound_variable => return, + } + } + }, else => return err, }, }, diff --git a/biscuit/src/authorizer.zig b/biscuit/src/authorizer.zig index 94471ac..7709144 100644 --- a/biscuit/src/authorizer.zig +++ b/biscuit/src/authorizer.zig @@ -176,6 +176,10 @@ pub const Authorizer = struct { // Map from biscuit symbol space to authorizer symbol space const rule = try authority_rule.convert(&biscuit.symbols, &authorizer.symbols); + if (!rule.validateVariables()) { + try errors.append(.unbound_variable); + } + // A authority block's rule trusts const rule_trusted_origins = try TrustedOrigins.fromScopes( authorizer.allocator, @@ -208,6 +212,10 @@ pub const Authorizer = struct { const rule = try block_rule.convert(&biscuit.symbols, &authorizer.symbols); std.debug.print("block rule {any} CONVERTED to rule = {any}\n", .{ block_rule, rule }); + if (!rule.validateVariables()) { + try errors.append(.unbound_variable); + } + const block_rule_trusted_origins = try TrustedOrigins.fromScopes( authorizer.allocator, rule.scopes.items, @@ -374,6 +382,7 @@ const AuthorizerErrorKind = enum(u8) { denied_by_policy, failed_authorizer_check, failed_block_check, + unbound_variable, }; pub const AuthorizerError = union(AuthorizerErrorKind) { @@ -381,4 +390,5 @@ pub const AuthorizerError = union(AuthorizerErrorKind) { denied_by_policy: struct { deny_policy_id: usize }, failed_authorizer_check: struct { check_id: usize }, failed_block_check: struct { block_id: usize, check_id: usize }, + unbound_variable: void, };