Skip to content
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
7 changes: 0 additions & 7 deletions biscuit-auth/src/token/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,13 +173,6 @@ pub trait ToAnyParam {
fn to_any_param(&self) -> AnyParam;
}

#[cfg(feature = "datalog-macro")]
impl ToAnyParam for PublicKey {
fn to_any_param(&self) -> AnyParam {
AnyParam::PublicKey(*self)
}
}

#[cfg(test)]
mod tests {
use std::{collections::HashMap, convert::TryFrom};
Expand Down
10 changes: 10 additions & 0 deletions biscuit-auth/src/token/builder/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,16 @@ impl Check {
}
}

// TODO maybe introduce a conversion trait to support refs, multiple values, non-pk scopes
#[cfg(feature = "datalog-macro")]
pub fn set_macro_scope_param(
&mut self,
name: &str,
param: PublicKey,
) -> Result<(), error::Token> {
self.set_scope_lenient(name, param)
}

pub fn validate_parameters(&self) -> Result<(), error::Token> {
for rule in &self.queries {
rule.validate_parameters()?;
Expand Down
10 changes: 10 additions & 0 deletions biscuit-auth/src/token/builder/policy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,16 @@ impl Policy {
}
}

// TODO maybe introduce a conversion trait to support refs, multiple values, non-pk scopes
#[cfg(feature = "datalog-macro")]
pub fn set_macro_scope_param(
&mut self,
name: &str,
param: PublicKey,
) -> Result<(), error::Token> {
self.set_scope_lenient(name, param)
}

pub fn validate_parameters(&self) -> Result<(), error::Token> {
for query in &self.queries {
query.validate_parameters()?;
Expand Down
10 changes: 10 additions & 0 deletions biscuit-auth/src/token/builder/rule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,16 @@ impl Rule {
}
}

// TODO maybe introduce a conversion trait to support refs, multiple values, non-pk scopes
#[cfg(feature = "datalog-macro")]
pub fn set_macro_scope_param(
&mut self,
name: &str,
param: PublicKey,
) -> Result<(), error::Token> {
self.set_scope_lenient(name, param)
}

pub(super) fn apply_parameters(&mut self) {
if let Some(parameters) = self.parameters.clone() {
self.head.terms = self
Expand Down
25 changes: 24 additions & 1 deletion biscuit-auth/tests/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Copyright (c) 2019 Geoffroy Couprie <[email protected]> and Contributors to the Eclipse Foundation.
* SPDX-License-Identifier: Apache-2.0
*/
use biscuit_auth::{builder, datalog::RunLimits, KeyPair};
use biscuit_auth::{builder, datalog::RunLimits, KeyPair, PublicKey};
use biscuit_quote::{
authorizer, authorizer_merge, biscuit, biscuit_merge, block, block_merge, check, fact, policy,
rule,
Expand Down Expand Up @@ -314,3 +314,26 @@ fn ecdsa() {
r#"rule($0, true) <- fact($0, $1, $2, "my_value", {0}) trusting secp256r1/0245dd01132962da3812911b746b080aed714873c1812e7cefacf13e3880712da0"#,
);
}

#[test]
fn trusting() {
// this should only work with a proper `PublicKey` value, and fail when trying to provide a string instead
let pubkey: PublicKey =
"secp256r1/0245dd01132962da3812911b746b080aed714873c1812e7cefacf13e3880712da0"
.parse()
.unwrap();
let _ = authorizer!(
r#"
nonce("a"); operation("o"); pathname("p");
d($x) <- nonce($x) trusting {pubkey}
"#
);
let _ = rule!(
r#"
data($nonce, $operation, $pathname)
<- nonce($nonce), operation($operation), pathname($pathname)

trusting {pubkey}
"#,
);
}
94 changes: 83 additions & 11 deletions biscuit-quote/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@ struct Builder {

// parameters used in the datalog source
pub datalog_parameters: HashSet<String>,
// scope parameters used in the datalog source
pub datalog_scope_parameters: HashSet<String>,
// parameters provided to the macro
pub macro_parameters: HashSet<String>,

Expand All @@ -227,6 +229,7 @@ impl Builder {
parameters,

datalog_parameters: HashSet::new(),
datalog_scope_parameters: HashSet::new(),
macro_parameters,

facts: Vec::new(),
Expand Down Expand Up @@ -286,7 +289,8 @@ impl Builder {
}

if let Some(parameters) = &rule.scope_parameters {
self.datalog_parameters.extend(parameters.keys().cloned());
self.datalog_scope_parameters
.extend(parameters.keys().cloned());
}
}

Expand Down Expand Up @@ -316,12 +320,17 @@ impl Builder {
}

fn validate(&self) -> Result<(), error::LanguageError> {
if self.macro_parameters.is_subset(&self.datalog_parameters) {
let all_parameters = self
.datalog_parameters
.union(&self.datalog_scope_parameters)
.cloned()
.collect();
if self.macro_parameters.is_subset(&all_parameters) {
Ok(())
} else {
let unused_parameters: Vec<String> = self
.macro_parameters
.difference(&self.datalog_parameters)
.difference(&all_parameters)
.cloned()
.collect();
Err(error::LanguageError::Parameters {
Expand All @@ -334,6 +343,7 @@ impl Builder {

struct Item {
parameters: HashSet<String>,
scope_parameters: HashSet<String>,
start: TokenStream,
middle: TokenStream,
end: TokenStream,
Expand All @@ -348,6 +358,7 @@ impl Item {
.flatten()
.map(|(name, _)| name.to_owned())
.collect(),
scope_parameters: HashSet::new(),
start: quote! {
let mut __biscuit_auth_item = #fact;
},
Expand All @@ -360,6 +371,7 @@ impl Item {
fn rule(rule: &Rule) -> Self {
Self {
parameters: Item::rule_params(rule).collect(),
scope_parameters: Item::rule_scope_params(rule).collect(),
start: quote! {
let mut __biscuit_auth_item = #rule;
},
Expand All @@ -373,6 +385,11 @@ impl Item {
fn check(check: &Check) -> Self {
Self {
parameters: check.queries.iter().flat_map(Item::rule_params).collect(),
scope_parameters: check
.queries
.iter()
.flat_map(Item::rule_scope_params)
.collect(),
start: quote! {
let mut __biscuit_auth_item = #check;
},
Expand All @@ -386,6 +403,11 @@ impl Item {
fn policy(policy: &Policy) -> Self {
Self {
parameters: policy.queries.iter().flat_map(Item::rule_params).collect(),
scope_parameters: policy
.queries
.iter()
.flat_map(Item::rule_scope_params)
.collect(),
start: quote! {
let mut __biscuit_auth_item = #policy;
},
Expand All @@ -400,19 +422,22 @@ impl Item {
rule.parameters
.iter()
.flatten()
.map(|(name, _)| name.as_ref())
.chain(
rule.scope_parameters
.iter()
.flatten()
.map(|(name, _)| name.as_ref()),
)
.map(str::to_owned)
.map(|(name, _)| name.to_string())
}

fn rule_scope_params(rule: &Rule) -> impl Iterator<Item = String> + '_ {
rule.scope_parameters
.iter()
.flatten()
.map(|(name, _)| name.to_string())
}

fn needs_param(&self, name: &str) -> bool {
self.parameters.contains(name)
}
fn needs_scope_param(&self, name: &str) -> bool {
self.scope_parameters.contains(name)
}

fn add_param(&mut self, name: &str, clone: bool) {
let ident = Ident::new(name, Span::call_site());
Expand All @@ -427,6 +452,20 @@ impl Item {
__biscuit_auth_item.set_macro_param(#name, #expr).unwrap();
});
}

fn add_scope_param(&mut self, name: &str, clone: bool) {
let ident = Ident::new(name, Span::call_site());

let expr = if clone {
quote! { ::core::clone::Clone::clone(&#ident) }
} else {
quote! { #ident }
};

self.middle.extend(quote! {
__biscuit_auth_item.set_macro_scope_param(#name, #expr).unwrap();
});
}
}

impl ToTokens for Item {
Expand Down Expand Up @@ -477,6 +516,21 @@ impl ToTokens for Builder {
}
}

for param in &self.datalog_scope_parameters {
let mut items = items
.iter_mut()
.filter(|i| i.needs_scope_param(param))
.peekable();

loop {
match (items.next(), items.peek()) {
(Some(cur), Some(_next)) => cur.add_scope_param(param, true),
(Some(cur), None) => cur.add_scope_param(param, false),
(None, _) => break,
}
}
}

let builder_type = &self.builder_type;
let builder_quote = if let Some(target) = &self.target {
quote! {
Expand Down Expand Up @@ -558,6 +612,12 @@ pub fn rule(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
}
}

for param in &builder.datalog_scope_parameters {
if rule_item.needs_scope_param(param) {
rule_item.add_scope_param(param, false);
}
}

(quote! {
{
#params_quote
Expand Down Expand Up @@ -694,6 +754,12 @@ pub fn check(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
}
}

for param in &builder.datalog_scope_parameters {
if check_item.needs_scope_param(param) {
check_item.add_scope_param(param, false);
}
}

(quote! {
{
#params_quote
Expand Down Expand Up @@ -766,6 +832,12 @@ pub fn policy(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
}
}

for param in &builder.datalog_scope_parameters {
if policy_item.needs_scope_param(param) {
policy_item.add_scope_param(param, false);
}
}

(quote! {
{
#params_quote
Expand Down
Loading