biscuit_auth/token/builder/
biscuit.rs

1/*
2 * Copyright (c) 2019 Geoffroy Couprie <contact@geoffroycouprie.com> and Contributors to the Eclipse Foundation.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5use super::{BlockBuilder, Check, Fact, Rule, Scope, Term};
6use crate::builder_ext::BuilderExt;
7use crate::crypto::PublicKey;
8use crate::datalog::SymbolTable;
9use crate::token::default_symbol_table;
10use crate::{error, Biscuit, KeyPair};
11use rand::{CryptoRng, RngCore};
12
13use std::fmt;
14use std::time::SystemTime;
15use std::{collections::HashMap, convert::TryInto, fmt::Write};
16
17/// creates a Biscuit
18#[derive(Clone, Default)]
19pub struct BiscuitBuilder {
20    inner: BlockBuilder,
21    root_key_id: Option<u32>,
22}
23
24impl BiscuitBuilder {
25    pub fn new() -> BiscuitBuilder {
26        BiscuitBuilder {
27            inner: BlockBuilder::new(),
28            root_key_id: None,
29        }
30    }
31
32    pub fn merge(mut self, other: BlockBuilder) -> Self {
33        self.inner = self.inner.merge(other);
34        self
35    }
36
37    pub fn fact<F: TryInto<Fact>>(mut self, fact: F) -> Result<Self, error::Token>
38    where
39        error::Token: From<<F as TryInto<Fact>>::Error>,
40    {
41        self.inner = self.inner.fact(fact)?;
42        Ok(self)
43    }
44
45    pub fn rule<Ru: TryInto<Rule>>(mut self, rule: Ru) -> Result<Self, error::Token>
46    where
47        error::Token: From<<Ru as TryInto<Rule>>::Error>,
48    {
49        self.inner = self.inner.rule(rule)?;
50        Ok(self)
51    }
52
53    pub fn check<C: TryInto<Check>>(mut self, check: C) -> Result<Self, error::Token>
54    where
55        error::Token: From<<C as TryInto<Check>>::Error>,
56    {
57        self.inner = self.inner.check(check)?;
58        Ok(self)
59    }
60
61    pub fn code<T: AsRef<str>>(mut self, source: T) -> Result<Self, error::Token> {
62        self.inner = self
63            .inner
64            .code_with_params(source, HashMap::new(), HashMap::new())?;
65        Ok(self)
66    }
67
68    pub fn code_with_params<T: AsRef<str>>(
69        mut self,
70        source: T,
71        params: HashMap<String, Term>,
72        scope_params: HashMap<String, PublicKey>,
73    ) -> Result<Self, error::Token> {
74        self.inner = self.inner.code_with_params(source, params, scope_params)?;
75        Ok(self)
76    }
77
78    pub fn scope(mut self, scope: Scope) -> Self {
79        self.inner = self.inner.scope(scope);
80        self
81    }
82
83    #[cfg(test)]
84    pub(crate) fn right(self, resource: &str, right: &str) -> Self {
85        use crate::builder::fact;
86
87        use super::string;
88
89        self.fact(fact("right", &[string(resource), string(right)]))
90            .unwrap()
91    }
92
93    pub fn context(mut self, context: String) -> Self {
94        self.inner = self.inner.context(context);
95        self
96    }
97
98    pub fn root_key_id(mut self, root_key_id: u32) -> Self {
99        self.root_key_id = Some(root_key_id);
100        self
101    }
102
103    /// returns all of the datalog loaded in the biscuit builder
104    pub fn dump(&self) -> (Vec<Fact>, Vec<Rule>, Vec<Check>) {
105        (
106            self.inner.facts.clone(),
107            self.inner.rules.clone(),
108            self.inner.checks.clone(),
109        )
110    }
111
112    pub fn dump_code(&self) -> String {
113        let (facts, rules, checks) = self.dump();
114        let mut f = String::new();
115        for fact in facts {
116            let _ = writeln!(f, "{};", fact);
117        }
118        for rule in rules {
119            let _ = writeln!(f, "{};", rule);
120        }
121        for check in checks {
122            let _ = writeln!(f, "{};", check);
123        }
124        f
125    }
126
127    pub fn build(self, root_key: &KeyPair) -> Result<Biscuit, error::Token> {
128        self.build_with_symbols(root_key, default_symbol_table())
129    }
130
131    pub fn build_with_symbols(
132        self,
133        root_key: &KeyPair,
134        symbols: SymbolTable,
135    ) -> Result<Biscuit, error::Token> {
136        self.build_with_rng(root_key, symbols, &mut rand::rngs::OsRng)
137    }
138
139    pub fn build_with_rng<R: RngCore + CryptoRng>(
140        self,
141        root: &KeyPair,
142        symbols: SymbolTable,
143        rng: &mut R,
144    ) -> Result<Biscuit, error::Token> {
145        let authority_block = self.inner.build(symbols.clone());
146        Biscuit::new_with_rng(rng, self.root_key_id, root, symbols, authority_block)
147    }
148
149    pub fn build_with_key_pair(
150        self,
151        root: &KeyPair,
152        symbols: SymbolTable,
153        next: &KeyPair,
154    ) -> Result<Biscuit, error::Token> {
155        let authority_block = self.inner.build(symbols.clone());
156        Biscuit::new_with_key_pair(self.root_key_id, root, next, symbols, authority_block)
157    }
158}
159
160impl fmt::Display for BiscuitBuilder {
161    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162        match self.root_key_id {
163            None => writeln!(f, "// no root key id set")?,
164            Some(id) => writeln!(f, "// root key id: {}", id)?,
165        }
166        self.inner.fmt(f)
167    }
168}
169
170impl BuilderExt for BiscuitBuilder {
171    fn resource(mut self, name: &str) -> Self {
172        self.inner = self.inner.resource(name);
173        self
174    }
175    fn check_resource(mut self, name: &str) -> Self {
176        self.inner = self.inner.check_resource(name);
177        self
178    }
179    fn check_resource_prefix(mut self, prefix: &str) -> Self {
180        self.inner = self.inner.check_resource_prefix(prefix);
181        self
182    }
183    fn check_resource_suffix(mut self, suffix: &str) -> Self {
184        self.inner = self.inner.check_resource_suffix(suffix);
185        self
186    }
187    fn operation(mut self, name: &str) -> Self {
188        self.inner = self.inner.operation(name);
189        self
190    }
191    fn check_operation(mut self, name: &str) -> Self {
192        self.inner = self.inner.check_operation(name);
193        self
194    }
195    fn check_expiration_date(mut self, date: SystemTime) -> Self {
196        self.inner = self.inner.check_expiration_date(date);
197        self
198    }
199}