Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor the builder API #251

Merged
merged 5 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
373 changes: 199 additions & 174 deletions biscuit-auth/benches/token.rs

Large diffs are not rendered by default.

27 changes: 12 additions & 15 deletions biscuit-auth/examples/testcases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -878,9 +878,9 @@ fn scoped_rules(target: &str, root: &KeyPair, test: bool) -> TestResult {
)
.unwrap();

let mut block3 = BlockBuilder::new();

block3.add_fact(r#"owner("alice", "file2")"#).unwrap();
let block3 = BlockBuilder::new()
.add_fact(r#"owner("alice", "file2")"#)
.unwrap();

let keypair3 = KeyPair::new_with_rng(Algorithm::Ed25519, &mut rng);
let biscuit3 = biscuit2.append_with_keypair(&keypair3, block3).unwrap();
Expand Down Expand Up @@ -973,14 +973,13 @@ fn expired_token(target: &str, root: &KeyPair, test: bool) -> TestResult {
.build_with_rng(&root, SymbolTable::default(), &mut rng)
.unwrap();

let mut block2 = block!(r#"check if resource("file1");"#);

// January 1 2019
block2.check_expiration_date(
UNIX_EPOCH
.checked_add(Duration::from_secs(49 * 365 * 24 * 3600))
.unwrap(),
);
let block2 = block!(r#"check if resource("file1");"#)
// January 1 2019
.check_expiration_date(
UNIX_EPOCH
.checked_add(Duration::from_secs(49 * 365 * 24 * 3600))
.unwrap(),
);

let keypair2 = KeyPair::new_with_rng(Algorithm::Ed25519, &mut rng);
let biscuit2 = biscuit1.append_with_keypair(&keypair2, block2).unwrap();
Expand Down Expand Up @@ -1410,10 +1409,8 @@ fn unbound_variables_in_rule(target: &str, root: &KeyPair, test: bool) -> TestRe
.build_with_rng(&root, SymbolTable::default(), &mut rng)
.unwrap();

let mut block2 = BlockBuilder::new();

// this one does not go through the parser because it checks for unused variables
block2
let block2 = BlockBuilder::new()
// this one does not go through the parser because it checks for unused variables
.add_rule(rule(
"operation",
&[var("unbound"), string("read")],
Expand Down
14 changes: 5 additions & 9 deletions biscuit-auth/examples/third_party.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,13 @@ fn main() {
let mut rng: StdRng = SeedableRng::seed_from_u64(0);
let root = KeyPair::new_with_rng(Algorithm::Ed25519, &mut rng);
let external = KeyPair::new_with_rng(Algorithm::Ed25519, &mut rng);

let mut builder = Biscuit::builder();

let external_pub = hex::encode(external.public().to_bytes());

builder
let biscuit1 = Biscuit::builder()
.add_check(
format!("check if external_fact(\"hello\") trusting ed25519/{external_pub}").as_str(),
)
.unwrap();

let biscuit1 = builder
.unwrap()
.build_with_rng(&root, SymbolTable::default(), &mut rng)
.unwrap();

Expand All @@ -27,8 +22,9 @@ fn main() {
let serialized_req = biscuit1.third_party_request().unwrap().serialize().unwrap();

let req = biscuit_auth::ThirdPartyRequest::deserialize(&serialized_req).unwrap();
let mut builder = BlockBuilder::new();
builder.add_fact("external_fact(\"hello\")").unwrap();
let builder = BlockBuilder::new()
.add_fact("external_fact(\"hello\")")
.unwrap();
let res = req.create_block(&external.private(), builder).unwrap();

let biscuit2 = biscuit1.append_third_party(external.public(), res).unwrap();
Expand Down
96 changes: 58 additions & 38 deletions biscuit-auth/src/token/authorizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,35 +203,40 @@ impl Authorizer {

/// Add the rules, facts, checks, and policies of another `Authorizer`.
/// If a token has already been added to `other`, it is not merged into `self`.
pub fn merge(&mut self, mut other: Authorizer) {
self.merge_block(other.authorizer_block_builder);
pub fn merge(&mut self, mut other: Authorizer) -> Result<(), error::Token> {
self.merge_block(other.authorizer_block_builder)?;
self.policies.append(&mut other.policies);
Ok(())
}

/// Add the rules, facts, and checks of another `BlockBuilder`.
pub fn merge_block(&mut self, other: BlockBuilder) {
self.authorizer_block_builder.merge(other)
pub fn merge_block(&mut self, other: BlockBuilder) -> Result<(), error::Token> {
self.authorizer_block_builder = self.authorizer_block_builder.clone().merge(other);
Ok(())
}

pub fn add_fact<F: TryInto<Fact>>(&mut self, fact: F) -> Result<(), error::Token>
where
error::Token: From<<F as TryInto<Fact>>::Error>,
{
self.authorizer_block_builder.add_fact(fact)
self.authorizer_block_builder = self.authorizer_block_builder.clone().add_fact(fact)?;
Ok(())
}

pub fn add_rule<Ru: TryInto<Rule>>(&mut self, rule: Ru) -> Result<(), error::Token>
where
error::Token: From<<Ru as TryInto<Rule>>::Error>,
{
self.authorizer_block_builder.add_rule(rule)
self.authorizer_block_builder = self.authorizer_block_builder.clone().add_rule(rule)?;
Ok(())
}

pub fn add_check<C: TryInto<Check>>(&mut self, check: C) -> Result<(), error::Token>
where
error::Token: From<<C as TryInto<Check>>::Error>,
{
self.authorizer_block_builder.add_check(check)
self.authorizer_block_builder = self.authorizer_block_builder.clone().add_check(check)?;
Ok(())
}

/// adds some datalog code to the authorizer
Expand Down Expand Up @@ -380,7 +385,7 @@ impl Authorizer {
}

pub fn add_scope(&mut self, scope: Scope) {
self.authorizer_block_builder.add_scope(scope);
self.authorizer_block_builder = self.authorizer_block_builder.clone().add_scope(scope);
}

/// Returns the runtime limits of the authorizer
Expand Down Expand Up @@ -608,7 +613,11 @@ impl Authorizer {
/// adds a fact with the current time
pub fn set_time(&mut self) {
let fact = fact("time", &[date(&SystemTime::now())]);
self.authorizer_block_builder.add_fact(fact).unwrap();
self.authorizer_block_builder = self
.authorizer_block_builder
.clone()
.add_fact(fact)
.unwrap();
}

/// add a policy to the authorizer
Expand Down Expand Up @@ -1213,15 +1222,18 @@ impl TryFrom<AuthorizerPolicies> for Authorizer {
let mut authorizer = Self::new();

for fact in facts.into_iter() {
authorizer.authorizer_block_builder.add_fact(fact)?;
authorizer.authorizer_block_builder =
authorizer.authorizer_block_builder.add_fact(fact)?;
}

for rule in rules.into_iter() {
authorizer.authorizer_block_builder.add_rule(rule)?;
authorizer.authorizer_block_builder =
authorizer.authorizer_block_builder.add_rule(rule)?;
}

for check in checks.into_iter() {
authorizer.authorizer_block_builder.add_check(check)?;
authorizer.authorizer_block_builder =
authorizer.authorizer_block_builder.add_check(check)?;
}

for policy in policies {
Expand Down Expand Up @@ -1271,11 +1283,12 @@ impl AuthorizerPolicies {
pub type AuthorizerLimits = RunLimits;

impl BuilderExt for Authorizer {
fn add_resource(&mut self, name: &str) {
fn add_resource(mut self, name: &str) -> Self {
let f = fact("resource", &[string(name)]);
self.add_fact(f).unwrap();
self
}
fn check_resource(&mut self, name: &str) {
fn check_resource(mut self, name: &str) -> Self {
self.add_check(Check {
queries: vec![rule(
"resource_check",
Expand All @@ -1285,12 +1298,14 @@ impl BuilderExt for Authorizer {
kind: CheckKind::One,
})
.unwrap();
self
}
fn add_operation(&mut self, name: &str) {
fn add_operation(mut self, name: &str) -> Self {
let f = fact("operation", &[string(name)]);
self.add_fact(f).unwrap();
self
}
fn check_operation(&mut self, name: &str) {
fn check_operation(mut self, name: &str) -> Self {
self.add_check(Check {
queries: vec![rule(
"operation_check",
Expand All @@ -1300,8 +1315,9 @@ impl BuilderExt for Authorizer {
kind: CheckKind::One,
})
.unwrap();
self
}
fn check_resource_prefix(&mut self, prefix: &str) {
fn check_resource_prefix(mut self, prefix: &str) -> Self {
let check = constrained_rule(
"prefix",
&[var("resource")],
Expand All @@ -1320,9 +1336,10 @@ impl BuilderExt for Authorizer {
kind: CheckKind::One,
})
.unwrap();
self
}

fn check_resource_suffix(&mut self, suffix: &str) {
fn check_resource_suffix(mut self, suffix: &str) -> Self {
let check = constrained_rule(
"suffix",
&[var("resource")],
Expand All @@ -1341,9 +1358,10 @@ impl BuilderExt for Authorizer {
kind: CheckKind::One,
})
.unwrap();
self
}

fn check_expiration_date(&mut self, exp: SystemTime) {
fn check_expiration_date(mut self, exp: SystemTime) -> Self {
let check = constrained_rule(
"expiration",
&[var("time")],
Expand All @@ -1362,6 +1380,7 @@ impl BuilderExt for Authorizer {
kind: CheckKind::One,
})
.unwrap();
self
}
}

Expand Down Expand Up @@ -1522,10 +1541,11 @@ mod tests {
use crate::Biscuit;
use crate::KeyPair;
let keypair = KeyPair::new(Algorithm::Ed25519);
let mut builder = Biscuit::builder();
builder.add_fact("user(\"John Doe\", 42)").unwrap();

let biscuit = builder.build(&keypair).unwrap();
let biscuit = Biscuit::builder()
.add_fact("user(\"John Doe\", 42)")
.unwrap()
.build(&keypair)
.unwrap();

let mut authorizer = biscuit.authorizer().unwrap();
let res: Vec<(String, i64)> = authorizer
Expand All @@ -1542,10 +1562,11 @@ mod tests {
use crate::Biscuit;
use crate::KeyPair;
let keypair = KeyPair::new(Algorithm::Ed25519);
let mut builder = Biscuit::builder();
builder.add_fact("user(\"John Doe\")").unwrap();

let biscuit = builder.build(&keypair).unwrap();
let biscuit = Biscuit::builder()
.add_fact("user(\"John Doe\")")
.unwrap()
.build(&keypair)
.unwrap();

let mut authorizer = biscuit.authorizer().unwrap();
let res: Vec<(String,)> = authorizer.query("data($name) <- user($name)").unwrap();
Expand All @@ -1559,25 +1580,24 @@ mod tests {
let root = KeyPair::new(Algorithm::Ed25519);
let external = KeyPair::new(Algorithm::Ed25519);

let mut builder = Biscuit::builder();
let mut scope_params = HashMap::new();
scope_params.insert("external_pub".to_string(), external.public());
builder

let biscuit1 = Biscuit::builder()
.add_code_with_params(
r#"right("read");
check if group("admin") trusting {external_pub};
"#,
check if group("admin") trusting {external_pub};
"#,
HashMap::new(),
scope_params,
)
.unwrap()
.build(&root)
.unwrap();

let biscuit1 = builder.build(&root).unwrap();

let req = biscuit1.third_party_request().unwrap();

let mut builder = BlockBuilder::new();
builder
let builder = BlockBuilder::new()
.add_code(
r#"group("admin");
check if right("read");
Expand Down Expand Up @@ -1741,17 +1761,17 @@ mod tests {
fn authorizer_display_before_and_after_authorization() {
let root = KeyPair::new(Algorithm::Ed25519);

let mut token_builder = BiscuitBuilder::new();
token_builder
let token = BiscuitBuilder::new()
.add_code(
r#"
authority_fact(true);
authority_rule($v) <- authority_fact($v);
check if authority_fact(true), authority_rule(true);
"#,
)
.unwrap()
.build(&root)
.unwrap();
let token = token_builder.build(&root).unwrap();

let mut authorizer = token.authorizer().unwrap();
authorizer
Expand Down
Loading
Loading