Skip to content

Commit

Permalink
Fix parser + working test 026...this required some additional mapping…
Browse files Browse the repository at this point in the history
… in and is not quite what biscuit-java is doing, so maybe I need to look at this more
  • Loading branch information
malcolmstill committed Mar 28, 2024
1 parent 286621b commit b029049
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 38 deletions.
2 changes: 1 addition & 1 deletion biscuit-datalog/src/combinator.zig
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ pub const Combinator = struct {
// Lookup the next (trusted) fact
const origin_fact = combinator.trusted_fact_iterator.next() orelse return null;

std.debug.print("next trusted fact: {any}\n", .{origin_fact.fact});
std.debug.print("combinator next trusted fact: {any}\n", .{origin_fact.fact});

const origin = origin_fact.origin.*;
const fact = origin_fact.fact.*;
Expand Down
2 changes: 1 addition & 1 deletion biscuit-datalog/src/rule.zig
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ pub const Rule = struct {
var arena = std.heap.ArenaAllocator.init(allocator);
defer arena.deinit();

std.debug.print("\napplying rule:\n {any}\n", .{rule});
std.debug.print("\napplying rule (from origin {}):\n {any}\n", .{ origin_id, rule });
const matched_variables = try MatchedVariables.init(arena.allocator(), rule);

// TODO: if body is empty stuff
Expand Down
2 changes: 1 addition & 1 deletion biscuit-datalog/src/world.zig
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ pub const World = struct {
}

pub fn addRule(world: *World, origin_id: usize, scope: TrustedOrigins, rule: Rule) !void {
std.debug.print("\nworld: adding rule = {any} ({}, {any})\n", .{ rule, origin_id, scope });
std.debug.print("\nworld: adding rule (origin {}) = {any} (trusts {any})\n", .{ origin_id, rule, scope });
try world.rule_set.add(origin_id, scope, rule);
}

Expand Down
5 changes: 4 additions & 1 deletion biscuit-format/src/main.zig
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
pub const decode = @import("decode.zig");
pub const serialized_biscuit = @import("serialized_biscuit.zig");
pub const MIN_SCHEMA_VERSION = @import("serialized_biscuit.zig").MIN_SCHEMA_VERSION;
pub const MAX_SCHEMA_VERSION = @import("serialized_biscuit.zig").MAX_SCHEMA_VERSION;
pub const SignedBlock = @import("signed_block.zig").SignedBlock;
pub const SerializedBiscuit = @import("serialized_biscuit.zig").SerializedBiscuit;

test {
_ = @import("serialized_biscuit.zig");
Expand Down
2 changes: 1 addition & 1 deletion biscuit-parser/src/parser.zig
Original file line number Diff line number Diff line change
Expand Up @@ -903,7 +903,7 @@ pub const Parser = struct {

if (!parser.startsWith(",")) break;

try parser.expectString("'");
try parser.expectString(",");
}

return scps;
Expand Down
10 changes: 5 additions & 5 deletions biscuit-samples/src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -89,18 +89,18 @@ pub fn validate(alloc: mem.Allocator, token: []const u8, public_key: std.crypto.
check_accounted_for = true;
}
},
.failed_authority_check => return error.NotImplemented,
.failed_authorizer_check => return error.NotImplemented,
}
}
},
.Authorizer => |expected_failed_authority_check| {
.Authorizer => |expected_failed_authorizer_check| {
for (errors.items) |found_failed_check| {
switch (found_failed_check) {
.no_matching_policy => continue,
.denied_by_policy => continue,
.failed_block_check => return error.NotImplemented,
.failed_authority_check => |failed_block_check| {
if (failed_block_check.check_id == expected_failed_authority_check.check_id) {
.failed_authorizer_check => |failed_block_check| {
if (failed_block_check.check_id == expected_failed_authorizer_check.check_id) {
// continue :blk;
check_accounted_for = true;
}
Expand Down Expand Up @@ -136,7 +136,7 @@ pub fn runValidation(alloc: mem.Allocator, token: []const u8, public_key: std.cr
var b = try Biscuit.fromBytes(alloc, token, public_key);
defer b.deinit();

var a = b.authorizer(alloc);
var a = try b.authorizer(alloc);
defer a.deinit();

var it = std.mem.split(u8, authorizer_code, ";");
Expand Down
58 changes: 52 additions & 6 deletions biscuit/src/authorizer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,31 @@ pub const Authorizer = struct {
public_key_to_block_id: std.AutoHashMap(usize, std.ArrayList(usize)),
scopes: std.ArrayList(Scope),

pub fn init(allocator: std.mem.Allocator, biscuit: Biscuit) Authorizer {
pub fn init(allocator: std.mem.Allocator, biscuit: Biscuit) !Authorizer {
var symbols = SymbolTable.init("authorizer", allocator);
var public_key_to_block_id = std.AutoHashMap(usize, std.ArrayList(usize)).init(allocator);

// Map public key symbols into authorizer symbols and public_key_to_block_id map
var it = biscuit.public_key_to_block_id.iterator();
while (it.next()) |entry| {
const biscuit_public_key_index = entry.key_ptr.*;
const block_ids = entry.value_ptr.*;

const public_key = try biscuit.symbols.getPublicKey(biscuit_public_key_index);

const authorizer_public_key_index = try symbols.insertPublicKey(public_key);

try public_key_to_block_id.put(authorizer_public_key_index, try block_ids.clone());
}

return .{
.allocator = allocator,
.checks = std.ArrayList(builder.Check).init(allocator),
.policies = std.ArrayList(builder.Policy).init(allocator),
.biscuit = biscuit,
.world = World.init(allocator),
.symbols = SymbolTable.init("authorizer", allocator),
.public_key_to_block_id = biscuit.public_key_to_block_id, // FIXME: are we okay to just copy here?
.symbols = symbols,
.public_key_to_block_id = public_key_to_block_id,
.scopes = std.ArrayList(Scope).init(allocator),
};
}
Expand All @@ -48,6 +64,14 @@ pub const Authorizer = struct {
policy.deinit();
}
authorizer.policies.deinit();

{
var it = authorizer.public_key_to_block_id.valueIterator();
while (it.next()) |block_ids| {
block_ids.deinit();
}
}
authorizer.policies.deinit();
}

pub fn authorizerTrustedOrigins(authorizer: *Authorizer) !TrustedOrigins {
Expand Down Expand Up @@ -108,6 +132,19 @@ pub const Authorizer = struct {
/// 6. _biscuit_ (where it exists): run the checks from all the non-authority blocks
pub fn authorize(authorizer: *Authorizer, errors: *std.ArrayList(AuthorizerError)) !usize {
std.debug.print("\nAuthorizing biscuit:\n", .{});

std.debug.print("authorizer public keys:\n", .{});
for (authorizer.symbols.public_keys.items, 0..) |pk, i| {
std.debug.print(" [{}]: {x}\n", .{ i, pk.bytes });
}

{
var it = authorizer.public_key_to_block_id.iterator();
while (it.next()) |entry| {
std.debug.print("public_key_to_block_id: public key id = {}, block_ids = {any}\n", .{ entry.key_ptr.*, entry.value_ptr.items });
}
}

// 1.
// Load facts and rules from authority block into world. Our block's facts
// will have a particular symbol table that we map into the symvol table
Expand All @@ -116,6 +153,10 @@ pub const Authorizer = struct {
// For example, the token may have a string "user123" which has id 12. But
// when mapped into the world it may have id 5.
if (authorizer.biscuit) |biscuit| {
std.debug.print("biscuit token public keys:\n", .{});
for (biscuit.symbols.public_keys.items, 0..) |pk, i| {
std.debug.print(" [{}]: {x}\n", .{ i, pk.bytes });
}
for (biscuit.authority.facts.items) |authority_fact| {
const fact = try authority_fact.convert(&biscuit.symbols, &authorizer.symbols);
const origin = try Origin.initWithId(authorizer.allocator, 0);
Expand Down Expand Up @@ -165,6 +206,7 @@ pub const Authorizer = struct {

for (block.rules.items) |block_rule| {
const rule = try block_rule.convert(&biscuit.symbols, &authorizer.symbols);
std.debug.print("block rule {any} CONVERTED to rule = {any}\n", .{ block_rule, rule });

const block_rule_trusted_origins = try TrustedOrigins.fromScopes(
authorizer.allocator,
Expand All @@ -180,9 +222,12 @@ pub const Authorizer = struct {
}

// 2. Run the world to generate all facts
std.debug.print("\nGENERATING NEW FACTS\n", .{});
try authorizer.world.run(authorizer.symbols);
std.debug.print("\nEND GENERATING NEW FACTS\n", .{});

// 3. Run checks that have been added to this authorizer
std.debug.print("\nAUTHORIZER CHECKS\n", .{});
for (authorizer.checks.items) |c| {
std.debug.print("authorizer check = {any}\n", .{c});
const check = try c.convert(authorizer.allocator, &authorizer.symbols);
Expand All @@ -201,10 +246,11 @@ pub const Authorizer = struct {
.all => try authorizer.world.queryMatchAll(query, authorizer.symbols, rule_trusted_origins),
};

if (!is_match) try errors.append(.{ .failed_authority_check = .{ .check_id = check_id } });
if (!is_match) try errors.append(.{ .failed_authorizer_check = .{ .check_id = check_id } });
std.debug.print("match {any} = {}\n", .{ query, is_match });
}
}
std.debug.print("END AUTHORIZER CHECKS\n", .{});

// 4. Run checks in the biscuit's authority block
if (authorizer.biscuit) |biscuit| {
Expand Down Expand Up @@ -326,13 +372,13 @@ pub const Authorizer = struct {
const AuthorizerErrorKind = enum(u8) {
no_matching_policy,
denied_by_policy,
failed_authority_check,
failed_authorizer_check,
failed_block_check,
};

pub const AuthorizerError = union(AuthorizerErrorKind) {
no_matching_policy: void,
denied_by_policy: struct { deny_policy_id: usize },
failed_authority_check: struct { check_id: usize },
failed_authorizer_check: struct { check_id: usize },
failed_block_check: struct { block_id: usize, check_id: usize },
};
27 changes: 10 additions & 17 deletions biscuit/src/biscuit.zig
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const Authorizer = @import("authorizer.zig").Authorizer;
const Block = @import("block.zig").Block;
const SymbolTable = @import("biscuit-datalog").SymbolTable;
const World = @import("biscuit-datalog").world.World;
const SerializedBiscuit = @import("biscuit-format").serialized_biscuit.SerializedBiscuit;
const SerializedBiscuit = @import("biscuit-format").SerializedBiscuit;

pub const Biscuit = struct {
serialized: SerializedBiscuit,
Expand All @@ -23,27 +23,20 @@ pub const Biscuit = struct {
defer block_external_keys.deinit();
defer std.debug.assert(block_external_keys.items.len == 1 + serialized.blocks.items.len);

var symbols = SymbolTable.init("biscuit", allocator);
var token_symbols = SymbolTable.init("biscuit", allocator);

const authority = try Block.fromBytes(allocator, serialized.authority.block, &symbols);
for (authority.public_keys.items) |public_key| {
_ = try symbols.insertPublicKey(public_key);
}
const authority = try Block.fromBytes(allocator, serialized.authority, &token_symbols);
try block_external_keys.append(null);
std.debug.print("authority block =\n{any}\n", .{authority});

var blocks = std.ArrayList(Block).init(allocator);
for (serialized.blocks.items) |b| {
const block = try Block.fromBytes(allocator, b.block, &symbols);
for (serialized.blocks.items) |signed_block| {
const block = try Block.fromBytes(allocator, signed_block, &token_symbols);
std.debug.print("non-authority block =\n{any}\n", .{block});

const external_key = if (b.external_signature) |external_signature| external_signature.public_key else null;
const external_key = if (signed_block.external_signature) |external_signature| external_signature.public_key else null;
try block_external_keys.append(external_key);

for (block.public_keys.items) |public_key| {
_ = try symbols.insertPublicKey(public_key);
}

try blocks.append(block);
}

Expand All @@ -54,7 +47,7 @@ pub const Biscuit = struct {
for (block_external_keys.items, 0..) |block_external_key, block_id| {
const key = block_external_key orelse continue;

const key_index = try symbols.insertPublicKey(key);
const key_index = try token_symbols.insertPublicKey(key);
if (public_key_to_block_id.getPtr(key_index)) |list_ptr| {
try list_ptr.append(block_id);
} else {
Expand All @@ -75,7 +68,7 @@ pub const Biscuit = struct {
.serialized = serialized,
.authority = authority,
.blocks = blocks,
.symbols = symbols,
.symbols = token_symbols,
.public_key_to_block_id = public_key_to_block_id,
};
}
Expand All @@ -97,8 +90,8 @@ pub const Biscuit = struct {
biscuit.serialized.deinit();
}

pub fn authorizer(biscuit: *Biscuit, allocator: std.mem.Allocator) Authorizer {
return Authorizer.init(allocator, biscuit.*);
pub fn authorizer(biscuit: *Biscuit, allocator: std.mem.Allocator) !Authorizer {
return try Authorizer.init(allocator, biscuit.*);
}
};

Expand Down
22 changes: 17 additions & 5 deletions biscuit/src/block.zig
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
const std = @import("std");
const Ed25519 = std.crypto.sign.Ed25519;
const format = @import("biscuit-format");
const SignedBlock = @import("biscuit-format").SignedBlock;
const MIN_SCHEMA_VERSION = @import("biscuit-format").MIN_SCHEMA_VERSION;
const MAX_SCHEMA_VERSION = @import("biscuit-format").MAX_SCHEMA_VERSION;
const schema = @import("biscuit-schema");
const Fact = @import("biscuit-datalog").fact.Fact;
const Rule = @import("biscuit-datalog").rule.Rule;
const Check = @import("biscuit-datalog").check.Check;
const Scope = @import("biscuit-datalog").Scope;
const SymbolTable = @import("biscuit-datalog").symbol_table.SymbolTable;
const MIN_SCHEMA_VERSION = format.serialized_biscuit.MIN_SCHEMA_VERSION;
const MAX_SCHEMA_VERSION = format.serialized_biscuit.MAX_SCHEMA_VERSION;

pub const Block = struct {
version: u32,
Expand Down Expand Up @@ -47,7 +47,8 @@ pub const Block = struct {
}

/// Given a blocks contents as bytes, derserialize into runtime block
pub fn fromBytes(allocator: std.mem.Allocator, data: []const u8, symbols: *SymbolTable) !Block {
pub fn fromBytes(allocator: std.mem.Allocator, signed_block: SignedBlock, token_symbols: *SymbolTable) !Block {
const data = signed_block.block;
std.debug.print("Block.fromBytes\n", .{});
const decoded_block = try schema.decodeBlock(allocator, data);
defer decoded_block.deinit();
Expand All @@ -63,7 +64,16 @@ pub const Block = struct {

for (decoded_block.symbols.items) |symbol| {
_ = try block.symbols.insert(symbol.getSlice());
_ = try symbols.insert(symbol.getSlice());
}

// If we have an external signature we add the external public key that to the parent biscuit's symbols and we don't add the blocks symbols
// Otherwise add the blocks symbols to the biscuit's symbol table.
if (signed_block.external_signature) |external_signature| {
_ = try token_symbols.insertPublicKey(external_signature.public_key);
} else {
for (decoded_block.symbols.items) |symbol| {
_ = try token_symbols.insert(symbol.getSlice());
}
}

for (decoded_block.facts_v2.items) |fact| {
Expand All @@ -83,6 +93,8 @@ pub const Block = struct {
@memcpy(&pubkey_buf, public_key.key.getSlice());

const key = try Ed25519.PublicKey.fromBytes(pubkey_buf);

_ = try token_symbols.insertPublicKey(key);
try block.public_keys.append(key);
}

Expand Down

0 comments on commit b029049

Please sign in to comment.