biscuit_auth/token/
mod.rs

1//! main structures to interact with Biscuit tokens
2use std::convert::TryInto;
3use std::fmt::Display;
4
5use self::public_keys::PublicKeys;
6
7use super::crypto::{KeyPair, PublicKey};
8use super::datalog::SymbolTable;
9use super::error;
10use super::format::SerializedBiscuit;
11use builder::{BiscuitBuilder, BlockBuilder};
12use prost::Message;
13use rand_core::{CryptoRng, RngCore};
14
15use crate::crypto::{self};
16use crate::format::convert::proto_block_to_token_block;
17use crate::format::schema::{self, ThirdPartyBlockContents};
18use authorizer::Authorizer;
19
20pub mod authorizer;
21pub(crate) mod block;
22pub mod builder;
23pub mod builder_ext;
24pub(crate) mod public_keys;
25pub(crate) mod third_party;
26pub mod unverified;
27
28pub use block::Block;
29pub use third_party::*;
30
31/// minimum supported version of the serialization format
32pub const MIN_SCHEMA_VERSION: u32 = 3;
33/// maximum supported version of the serialization format
34pub const MAX_SCHEMA_VERSION: u32 = 5;
35
36/// some symbols are predefined and available in every implementation, to avoid
37/// transmitting them with every token
38pub fn default_symbol_table() -> SymbolTable {
39    SymbolTable::new()
40}
41
42/// This structure represents a valid Biscuit token
43///
44/// It contains multiple `Block` elements, the associated symbol table,
45/// and a serialized version of this data
46///
47/// ```rust
48/// extern crate biscuit_auth as biscuit;
49///
50/// use biscuit::{KeyPair, Biscuit, builder::*, builder_ext::*};
51///
52/// fn main() {
53///   let root = KeyPair::new();
54///
55///   // first we define the authority block for global data,
56///   // like access rights
57///   // data from the authority block cannot be created in any other block
58///   let mut builder = Biscuit::builder();
59///   builder.add_fact(fact("right", &[string("/a/file1.txt"), string("read")]));
60///
61///   // facts and rules can also be parsed from a string
62///   builder.add_fact("right(\"/a/file1.txt\", \"read\")").expect("parse error");
63///
64///   let token1 = builder.build(&root).unwrap();
65///
66///   // we can create a new block builder from that token
67///   let mut builder2 = BlockBuilder::new();
68///   builder2.check_operation("read");
69///
70///   let token2 = token1.append(builder2).unwrap();
71/// }
72/// ```
73#[derive(Clone, Debug)]
74pub struct Biscuit {
75    pub(crate) root_key_id: Option<u32>,
76    pub(crate) authority: schema::Block,
77    pub(crate) blocks: Vec<schema::Block>,
78    pub(crate) symbols: SymbolTable,
79    pub(crate) container: SerializedBiscuit,
80}
81
82impl Biscuit {
83    /// create the first block's builder
84    ///
85    /// call [`builder::BiscuitBuilder::build`] to create the token
86    pub fn builder() -> BiscuitBuilder {
87        BiscuitBuilder::new()
88    }
89
90    /// deserializes a token and validates the signature using the root public key
91    pub fn from<T, KP>(slice: T, key_provider: KP) -> Result<Self, error::Token>
92    where
93        T: AsRef<[u8]>,
94        KP: RootKeyProvider,
95    {
96        Biscuit::from_with_symbols(slice.as_ref(), key_provider, default_symbol_table())
97    }
98
99    /// deserializes a token and validates the signature using the root public key
100    pub fn from_base64<T, KP>(slice: T, key_provider: KP) -> Result<Self, error::Token>
101    where
102        T: AsRef<[u8]>,
103        KP: RootKeyProvider,
104    {
105        Biscuit::from_base64_with_symbols(slice, key_provider, default_symbol_table())
106    }
107
108    /// serializes the token
109    pub fn to_vec(&self) -> Result<Vec<u8>, error::Token> {
110        self.container.to_vec().map_err(error::Token::Format)
111    }
112
113    /// serializes the token and encode it to a (URL safe) base64 string
114    pub fn to_base64(&self) -> Result<String, error::Token> {
115        self.container
116            .to_vec()
117            .map_err(error::Token::Format)
118            .map(|v| base64::encode_config(v, base64::URL_SAFE))
119    }
120
121    /// serializes the token
122    pub fn serialized_size(&self) -> Result<usize, error::Token> {
123        Ok(self.container.serialized_size())
124    }
125
126    /// creates a sealed version of the token
127    ///
128    /// sealed tokens cannot be attenuated
129    pub fn seal(&self) -> Result<Biscuit, error::Token> {
130        let container = self.container.seal()?;
131
132        let mut token = self.clone();
133        token.container = container;
134
135        Ok(token)
136    }
137
138    /// creates a authorizer from this token
139    pub fn authorizer(&self) -> Result<Authorizer, error::Token> {
140        Authorizer::from_token(self)
141    }
142
143    /// runs authorization with the provided authorizer
144    pub fn authorize(&self, authorizer: &Authorizer) -> Result<usize, error::Token> {
145        let mut a = authorizer.clone();
146        a.add_token(self)?;
147        a.authorize()
148    }
149
150    /// adds a new block to the token
151    ///
152    /// since the public key is integrated into the token, the keypair can be
153    /// discarded right after calling this function
154    pub fn append(&self, block_builder: BlockBuilder) -> Result<Self, error::Token> {
155        let keypair = KeyPair::new_with_rng(&mut rand::rngs::OsRng);
156        self.append_with_keypair(&keypair, block_builder)
157    }
158
159    /// returns the list of context elements of each block
160    ///
161    /// the context is a free form text field in which application specific data
162    /// can be stored
163    pub fn context(&self) -> Vec<Option<String>> {
164        let mut res = vec![self.authority.context.clone()];
165
166        for b in self.blocks.iter() {
167            res.push(b.context.clone());
168        }
169
170        res
171    }
172
173    /// returns an (optional) root key identifier. It provides a hint for public key selection during verification
174    pub fn root_key_id(&self) -> Option<u32> {
175        self.root_key_id
176    }
177
178    /// returns a list of revocation identifiers for each block, in order
179    ///
180    /// revocation identifiers are unique: tokens generated separately with
181    /// the same contents will have different revocation ids
182    pub fn revocation_identifiers(&self) -> Vec<Vec<u8>> {
183        let mut res = vec![self.container.authority.signature.to_bytes().to_vec()];
184
185        for block in self.container.blocks.iter() {
186            res.push(block.signature.to_bytes().to_vec());
187        }
188
189        res
190    }
191
192    /// returns a list of external key for each block, in order
193    ///
194    /// Blocks carrying an external public key are _third-party blocks_
195    /// and their contents can be trusted as coming from the holder of
196    /// the corresponding private key
197    pub fn external_public_keys(&self) -> Vec<Option<PublicKey>> {
198        let mut res = vec![None];
199
200        for block in self.container.blocks.iter() {
201            res.push(block.external_signature.as_ref().map(|sig| sig.public_key));
202        }
203
204        res
205    }
206
207    /// pretty printer for this token
208    pub fn print(&self) -> String {
209        format!("{}", &self)
210    }
211
212    /// prints the content of a block as Datalog source code
213    pub fn print_block_source(&self, index: usize) -> Result<String, error::Token> {
214        self.block(index).map(|block| {
215            let symbols = if block.external_key.is_some() {
216                &block.symbols
217            } else {
218                &self.symbols
219            };
220            block.print_source(symbols)
221        })
222    }
223
224    /// creates a new token, using a provided CSPRNG
225    ///
226    /// the public part of the root keypair must be used for verification
227    pub(crate) fn new_with_rng<T: RngCore + CryptoRng>(
228        rng: &mut T,
229        root_key_id: Option<u32>,
230        root: &KeyPair,
231        mut symbols: SymbolTable,
232        authority: Block,
233    ) -> Result<Biscuit, error::Token> {
234        if !symbols.is_disjoint(&authority.symbols) {
235            return Err(error::Token::Format(error::Format::SymbolTableOverlap));
236        }
237
238        symbols.extend(&authority.symbols)?;
239
240        let blocks = vec![];
241
242        let next_keypair = KeyPair::new_with_rng(rng);
243        let container = SerializedBiscuit::new(root_key_id, root, &next_keypair, &authority)?;
244
245        symbols.public_keys.extend(&authority.public_keys)?;
246
247        let authority = schema::Block::decode(&container.authority.data[..]).map_err(|e| {
248            error::Token::Format(error::Format::BlockDeserializationError(format!(
249                "error deserializing block: {:?}",
250                e
251            )))
252        })?;
253
254        Ok(Biscuit {
255            root_key_id,
256            authority,
257            blocks,
258            symbols,
259            container,
260        })
261    }
262
263    /// deserializes a token and validates the signature using the root public key, with a custom symbol table
264    fn from_with_symbols<KP>(
265        slice: &[u8],
266        key_provider: KP,
267        symbols: SymbolTable,
268    ) -> Result<Self, error::Token>
269    where
270        KP: RootKeyProvider,
271    {
272        let container =
273            SerializedBiscuit::from_slice(slice, key_provider).map_err(error::Token::Format)?;
274
275        Biscuit::from_serialized_container(container, symbols)
276    }
277
278    fn from_serialized_container(
279        container: SerializedBiscuit,
280        mut symbols: SymbolTable,
281    ) -> Result<Self, error::Token> {
282        let (authority, blocks) = container.extract_blocks(&mut symbols)?;
283
284        let root_key_id = container.root_key_id;
285
286        Ok(Biscuit {
287            root_key_id,
288            authority,
289            blocks,
290            symbols,
291            container,
292        })
293    }
294
295    /// deserializes a token and validates the signature using the root public key, with a custom symbol table
296    fn from_base64_with_symbols<T, KP>(
297        slice: T,
298        key_provider: KP,
299        symbols: SymbolTable,
300    ) -> Result<Self, error::Token>
301    where
302        T: AsRef<[u8]>,
303        KP: RootKeyProvider,
304    {
305        let decoded = base64::decode_config(slice, base64::URL_SAFE)?;
306        Biscuit::from_with_symbols(&decoded, key_provider, symbols)
307    }
308
309    /// returns the internal representation of the token
310    pub fn container(&self) -> &SerializedBiscuit {
311        &self.container
312    }
313
314    /// adds a new block to the token, using the provided CSPRNG
315    ///
316    /// since the public key is integrated into the token, the keypair can be
317    /// discarded right after calling this function
318    pub fn append_with_keypair(
319        &self,
320        keypair: &KeyPair,
321        block_builder: BlockBuilder,
322    ) -> Result<Self, error::Token> {
323        let block = block_builder.build(self.symbols.clone());
324
325        if !self.symbols.is_disjoint(&block.symbols) {
326            return Err(error::Token::Format(error::Format::SymbolTableOverlap));
327        }
328
329        let authority = self.authority.clone();
330        let mut blocks = self.blocks.clone();
331        let mut symbols = self.symbols.clone();
332
333        let container = self.container.append(keypair, &block, None)?;
334
335        symbols.extend(&block.symbols)?;
336        symbols.public_keys.extend(&block.public_keys)?;
337
338        let deser = schema::Block::decode(
339            &container
340                .blocks
341                .last()
342                .expect("a new block was just added so the list is not empty")
343                .data[..],
344        )
345        .map_err(|e| {
346            error::Token::Format(error::Format::BlockDeserializationError(format!(
347                "error deserializing block: {:?}",
348                e
349            )))
350        })?;
351        blocks.push(deser);
352
353        Ok(Biscuit {
354            root_key_id: self.root_key_id,
355            authority,
356            blocks,
357            symbols,
358            container,
359        })
360    }
361
362    pub fn third_party_request(&self) -> Result<ThirdPartyRequest, error::Token> {
363        ThirdPartyRequest::from_container(&self.container)
364    }
365
366    pub fn append_third_party(
367        &self,
368        external_key: PublicKey,
369        response: ThirdPartyBlock,
370    ) -> Result<Self, error::Token> {
371        let next_keypair = KeyPair::new_with_rng(&mut rand::rngs::OsRng);
372
373        self.append_third_party_with_keypair(external_key, response, next_keypair)
374    }
375    pub fn append_third_party_with_keypair(
376        &self,
377        external_key: PublicKey,
378        response: ThirdPartyBlock,
379        next_keypair: KeyPair,
380    ) -> Result<Self, error::Token> {
381        let ThirdPartyBlockContents {
382            payload,
383            external_signature,
384        } = response.0;
385
386        if external_signature.public_key.algorithm != schema::public_key::Algorithm::Ed25519 as i32
387        {
388            return Err(error::Token::Format(error::Format::DeserializationError(
389                format!(
390                    "deserialization error: unexpected key algorithm {}",
391                    external_signature.public_key.algorithm
392                ),
393            )));
394        }
395        let bytes: [u8; 64] = (&external_signature.signature[..])
396            .try_into()
397            .map_err(|_| error::Format::InvalidSignatureSize(external_signature.signature.len()))?;
398
399        let signature = ed25519_dalek::Signature::from_bytes(&bytes);
400        let previous_key = self
401            .container
402            .blocks
403            .last()
404            .unwrap_or(&self.container.authority)
405            .next_key;
406        let mut to_verify = payload.clone();
407        to_verify
408            .extend(&(crate::format::schema::public_key::Algorithm::Ed25519 as i32).to_le_bytes());
409        to_verify.extend(&previous_key.to_bytes());
410
411        external_key
412            .0
413            .verify_strict(&to_verify, &signature)
414            .map_err(|s| s.to_string())
415            .map_err(error::Signature::InvalidSignature)
416            .map_err(error::Format::Signature)?;
417
418        let block = schema::Block::decode(&payload[..]).map_err(|e| {
419            error::Token::Format(error::Format::DeserializationError(format!(
420                "deserialization error: {:?}",
421                e
422            )))
423        })?;
424
425        let external_signature = crypto::ExternalSignature {
426            public_key: external_key,
427            signature,
428        };
429
430        let symbols = self.symbols.clone();
431        let mut blocks = self.blocks.clone();
432
433        let container =
434            self.container
435                .append_serialized(&next_keypair, payload, Some(external_signature))?;
436
437        blocks.push(block);
438
439        Ok(Biscuit {
440            root_key_id: self.root_key_id,
441            authority: self.authority.clone(),
442            blocks,
443            symbols,
444            container,
445        })
446    }
447
448    /// gets the list of symbols from a block
449    pub fn block_symbols(&self, index: usize) -> Result<Vec<String>, error::Token> {
450        let block = if index == 0 {
451            &self.authority
452        } else {
453            match self.blocks.get(index - 1) {
454                None => return Err(error::Token::Format(error::Format::InvalidBlockId(index))),
455                Some(block) => block,
456            }
457        };
458
459        Ok(block.symbols.clone())
460    }
461
462    /// gets the list of public keys from a block
463    pub fn block_public_keys(&self, index: usize) -> Result<PublicKeys, error::Token> {
464        let block = if index == 0 {
465            &self.authority
466        } else {
467            match self.blocks.get(index - 1) {
468                None => return Err(error::Token::Format(error::Format::InvalidBlockId(index))),
469                Some(block) => block,
470            }
471        };
472
473        let mut public_keys = PublicKeys::new();
474
475        for pk in &block.public_keys {
476            public_keys.insert(&PublicKey::from_proto(pk)?);
477        }
478        Ok(public_keys)
479    }
480
481    /// gets the list of public keys from a block
482    pub fn block_external_key(&self, index: usize) -> Result<Option<PublicKey>, error::Token> {
483        let block = if index == 0 {
484            &self.container.authority
485        } else {
486            match self.container.blocks.get(index - 1) {
487                None => return Err(error::Token::Format(error::Format::InvalidBlockId(index))),
488                Some(block) => block,
489            }
490        };
491
492        Ok(block
493            .external_signature
494            .as_ref()
495            .map(|signature| signature.public_key))
496    }
497
498    /// returns the number of blocks (at least 1)
499    pub fn block_count(&self) -> usize {
500        1 + self.blocks.len()
501    }
502
503    pub(crate) fn block(&self, index: usize) -> Result<Block, error::Token> {
504        let block = if index == 0 {
505            proto_block_to_token_block(
506                &self.authority,
507                self.container
508                    .authority
509                    .external_signature
510                    .as_ref()
511                    .map(|ex| ex.public_key),
512            )
513            .map_err(error::Token::Format)?
514        } else {
515            if index > self.blocks.len() + 1 {
516                return Err(error::Token::Format(
517                    error::Format::BlockDeserializationError("invalid block index".to_string()),
518                ));
519            }
520
521            proto_block_to_token_block(
522                &self.blocks[index - 1],
523                self.container.blocks[index - 1]
524                    .external_signature
525                    .as_ref()
526                    .map(|ex| ex.public_key),
527            )
528            .map_err(error::Token::Format)?
529        };
530
531        Ok(block)
532    }
533}
534
535impl Display for Biscuit {
536    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
537        let authority = self
538            .block(0)
539            .as_ref()
540            .map(|block| print_block(&self.symbols, block))
541            .unwrap_or_else(|_| String::new());
542        let blocks: Vec<_> = (1..self.block_count())
543            .map(|i| {
544                self.block(i)
545                    .as_ref()
546                    .map(|block| print_block(&self.symbols, block))
547                    .unwrap_or_else(|_| String::new())
548            })
549            .collect();
550
551        write!(f, "Biscuit {{\n    symbols: {:?}\n    public keys: {:?}\n    authority: {}\n    blocks: [\n        {}\n    ]\n}}",
552        self.symbols.strings(),
553        self.symbols.public_keys.keys.iter().map(|pk| hex::encode(pk.to_bytes())).collect::<Vec<_>>(),
554        authority,
555        blocks.join(",\n\t")
556    )
557    }
558}
559fn print_block(symbols: &SymbolTable, block: &Block) -> String {
560    let facts: Vec<_> = block.facts.iter().map(|f| symbols.print_fact(f)).collect();
561    let rules: Vec<_> = block.rules.iter().map(|r| symbols.print_rule(r)).collect();
562    let checks: Vec<_> = block
563        .checks
564        .iter()
565        .map(|r| symbols.print_check(r))
566        .collect();
567
568    let facts = if facts.is_empty() {
569        String::new()
570    } else {
571        format!(
572            "\n                {}\n            ",
573            facts.join(",\n                ")
574        )
575    };
576    let rules = if rules.is_empty() {
577        String::new()
578    } else {
579        format!(
580            "\n                {}\n            ",
581            rules.join(",\n                ")
582        )
583    };
584    let checks = if checks.is_empty() {
585        String::new()
586    } else {
587        format!(
588            "\n                {}\n            ",
589            checks.join(",\n                ")
590        )
591    };
592
593    format!(
594        "Block {{\n            symbols: {:?}\n            version: {}\n            context: \"{}\"\n            external key: {}\n            public keys: {:?}\n            scopes: {:?}\n            facts: [{}]\n            rules: [{}]\n            checks: [{}]\n        }}",
595        block.symbols.strings(),
596        block.version,
597        block.context.as_deref().unwrap_or(""),
598        block.external_key.as_ref().map(|k| hex::encode(k.to_bytes())).unwrap_or_default(),
599        block.public_keys.keys.iter().map(|k | hex::encode(k.to_bytes())).collect::<Vec<_>>(),
600        block.scopes,
601        facts,
602        rules,
603        checks,
604    )
605}
606
607#[derive(Clone, Debug, Hash, PartialEq, Eq)]
608pub enum Scope {
609    Authority,
610    Previous,
611    // index of the public key in the symbol table
612    PublicKey(u64),
613}
614
615/// Chooses a root public key to verify the token
616///
617/// In case of key rotation, it is possible to add a root key id
618/// to the token with [`BiscuitBuilder::set_root_key_id`]. This
619/// value will be passed to the implementor of `RootKeyProvider`
620/// to choose which key will be used.
621pub trait RootKeyProvider {
622    fn choose(&self, key_id: Option<u32>) -> Result<PublicKey, error::Format>;
623}
624
625impl RootKeyProvider for Box<dyn RootKeyProvider> {
626    fn choose(&self, key_id: Option<u32>) -> Result<PublicKey, error::Format> {
627        self.as_ref().choose(key_id)
628    }
629}
630
631impl RootKeyProvider for std::rc::Rc<dyn RootKeyProvider> {
632    fn choose(&self, key_id: Option<u32>) -> Result<PublicKey, error::Format> {
633        self.as_ref().choose(key_id)
634    }
635}
636
637impl RootKeyProvider for std::sync::Arc<dyn RootKeyProvider> {
638    fn choose(&self, key_id: Option<u32>) -> Result<PublicKey, error::Format> {
639        self.as_ref().choose(key_id)
640    }
641}
642
643impl RootKeyProvider for PublicKey {
644    fn choose(&self, _: Option<u32>) -> Result<PublicKey, error::Format> {
645        Ok(*self)
646    }
647}
648
649impl RootKeyProvider for &PublicKey {
650    fn choose(&self, _: Option<u32>) -> Result<PublicKey, error::Format> {
651        Ok(**self)
652    }
653}
654
655impl<F: Fn(Option<u32>) -> Result<PublicKey, error::Format>> RootKeyProvider for F {
656    fn choose(&self, root_key_id: Option<u32>) -> Result<PublicKey, error::Format> {
657        self(root_key_id)
658    }
659}
660
661#[cfg(test)]
662mod tests {
663    use super::builder::{check, fact, pred, rule, string, var};
664    use super::builder_ext::BuilderExt;
665    use super::*;
666    use crate::builder::CheckKind;
667    use crate::crypto::KeyPair;
668    use crate::{error::*, AuthorizerLimits};
669    use rand::prelude::*;
670    use std::time::{Duration, SystemTime};
671
672    #[test]
673    fn basic() {
674        let mut rng: StdRng = SeedableRng::seed_from_u64(0);
675        let root = KeyPair::new_with_rng(&mut rng);
676
677        let serialized1 = {
678            let mut builder = Biscuit::builder();
679
680            builder.add_fact("right(\"file1\", \"read\")").unwrap();
681            builder.add_fact("right(\"file2\", \"read\")").unwrap();
682            builder.add_fact("right(\"file1\", \"write\")").unwrap();
683
684            let biscuit1 = builder
685                .build_with_rng(&root, default_symbol_table(), &mut rng)
686                .unwrap();
687
688            println!("biscuit1 (authority): {}", biscuit1);
689
690            biscuit1.to_vec().unwrap()
691        };
692
693        //println!("generated biscuit token: {} bytes:\n{}", serialized1.len(), serialized1.to_hex(16));
694        println!("generated biscuit token: {} bytes", serialized1.len());
695        //panic!();
696
697        /*
698        for i in 0..9 {
699            let biscuit1_deser = Biscuit::from(&serialized1, root.public).unwrap();
700
701            // new check: can only have read access1
702            let mut block2 = BlockBuilder::new();
703
704            block2.add_check(&rule(
705                "check1",
706                &[var(0)],
707                &[
708                    pred("resource", &[var(0)]),
709                    pred("operation", &[string("read")]),
710                    pred("right", &[var(0), string("read")]),
711                ],
712            ));
713
714            let keypair2 = KeyPair::new_with_rng(&mut rng);
715            let biscuit2 = biscuit1_deser.append(&keypair2, block2.to_block()).unwrap();
716
717            println!("biscuit2 (1 check): {}", biscuit2);
718
719            serialized1 = biscuit2.to_vec().unwrap();
720
721        }
722        println!("generated biscuit token 2: {} bytes", serialized1.len());
723        panic!();
724        */
725
726        let serialized2 = {
727            let biscuit1_deser = Biscuit::from(&serialized1, root.public()).unwrap();
728
729            // new check: can only have read access1
730            let mut block2 = BlockBuilder::new();
731
732            block2
733                .add_check(rule(
734                    "check1",
735                    &[var("resource")],
736                    &[
737                        pred("resource", &[var("resource")]),
738                        pred("operation", &[string("read")]),
739                        pred("right", &[var("resource"), string("read")]),
740                    ],
741                ))
742                .unwrap();
743
744            let keypair2 = KeyPair::new_with_rng(&mut rng);
745            let biscuit2 = biscuit1_deser
746                .append_with_keypair(&keypair2, block2)
747                .unwrap();
748
749            println!("biscuit2 (1 check): {}", biscuit2);
750
751            biscuit2.to_vec().unwrap()
752        };
753
754        //println!("generated biscuit token 2: {} bytes\n{}", serialized2.len(), serialized2.to_hex(16));
755        println!("generated biscuit token 2: {} bytes", serialized2.len());
756
757        let serialized3 = {
758            let biscuit2_deser = Biscuit::from(&serialized2, root.public()).unwrap();
759
760            // new check: can only access file1
761            let mut block3 = BlockBuilder::new();
762
763            block3
764                .add_check(rule(
765                    "check2",
766                    &[string("file1")],
767                    &[pred("resource", &[string("file1")])],
768                ))
769                .unwrap();
770
771            let keypair3 = KeyPair::new_with_rng(&mut rng);
772            let biscuit3 = biscuit2_deser
773                .append_with_keypair(&keypair3, block3)
774                .unwrap();
775
776            biscuit3.to_vec().unwrap()
777        };
778
779        //println!("generated biscuit token 3: {} bytes\n{}", serialized3.len(), serialized3.to_hex(16));
780        println!("generated biscuit token 3: {} bytes", serialized3.len());
781        //panic!();
782
783        let final_token = Biscuit::from(&serialized3, root.public()).unwrap();
784        println!("final token:\n{}", final_token);
785        {
786            let mut authorizer = final_token.authorizer().unwrap();
787
788            let mut facts = vec![
789                fact("resource", &[string("file1")]),
790                fact("operation", &[string("read")]),
791            ];
792
793            for fact in facts.drain(..) {
794                authorizer.add_fact(fact).unwrap();
795            }
796
797            //println!("final token: {:#?}", final_token);
798            authorizer.allow().unwrap();
799
800            let res = authorizer.authorize();
801            println!("res1: {:?}", res);
802            res.unwrap();
803        }
804
805        {
806            let mut authorizer = final_token.authorizer().unwrap();
807
808            let mut facts = vec![
809                fact("resource", &[string("file2")]),
810                fact("operation", &[string("write")]),
811            ];
812
813            for fact in facts.drain(..) {
814                authorizer.add_fact(fact).unwrap();
815            }
816
817            authorizer.allow().unwrap();
818
819            let res = authorizer.authorize_with_limits(AuthorizerLimits {
820                max_time: Duration::from_secs(10),
821                ..Default::default()
822            });
823            println!("res2: {:#?}", res);
824            assert_eq!(res,
825              Err(Token::FailedLogic(Logic::Unauthorized {
826                  policy: MatchedPolicy::Allow(0),
827                  checks: vec![
828                FailedCheck::Block(FailedBlockCheck { block_id: 1, check_id: 0, rule: String::from("check if resource($resource), operation(\"read\"), right($resource, \"read\")") }),
829                FailedCheck::Block(FailedBlockCheck { block_id: 2, check_id: 0, rule: String::from("check if resource(\"file1\")") })
830              ]
831              })));
832        }
833    }
834
835    #[test]
836    fn folders() {
837        let mut rng: StdRng = SeedableRng::seed_from_u64(0);
838        let root = KeyPair::new_with_rng(&mut rng);
839
840        let mut builder = Biscuit::builder();
841
842        builder.add_right("/folder1/file1", "read");
843        builder.add_right("/folder1/file1", "write");
844        builder.add_right("/folder1/file2", "read");
845        builder.add_right("/folder1/file2", "write");
846        builder.add_right("/folder2/file3", "read");
847
848        let biscuit1 = builder
849            .build_with_rng(&root, default_symbol_table(), &mut rng)
850            .unwrap();
851
852        println!("biscuit1 (authority): {}", biscuit1);
853
854        let mut block2 = BlockBuilder::new();
855
856        block2.check_resource_prefix("/folder1/");
857        block2.check_right("read");
858
859        let keypair2 = KeyPair::new_with_rng(&mut rng);
860        let biscuit2 = biscuit1.append_with_keypair(&keypair2, block2).unwrap();
861
862        {
863            let mut authorizer = biscuit2.authorizer().unwrap();
864            authorizer.add_fact("resource(\"/folder1/file1\")").unwrap();
865            authorizer.add_fact("operation(\"read\")").unwrap();
866            authorizer.allow().unwrap();
867
868            let res = authorizer.authorize_with_limits(AuthorizerLimits {
869                max_time: Duration::from_secs(10),
870                ..Default::default()
871            });
872            println!("res1: {:?}", res);
873            println!("authorizer:\n{}", authorizer.print_world());
874            res.unwrap();
875        }
876
877        {
878            let mut authorizer = biscuit2.authorizer().unwrap();
879            authorizer.add_fact("resource(\"/folder2/file3\")").unwrap();
880            authorizer.add_fact("operation(\"read\")").unwrap();
881            authorizer.allow().unwrap();
882
883            let res = authorizer.authorize_with_limits(AuthorizerLimits {
884                max_time: Duration::from_secs(10),
885                ..Default::default()
886            });
887            println!("res2: {:?}", res);
888            assert_eq!(
889                res,
890                Err(Token::FailedLogic(Logic::Unauthorized {
891                    policy: MatchedPolicy::Allow(0),
892                    checks: vec![FailedCheck::Block(FailedBlockCheck {
893                        block_id: 1,
894                        check_id: 0,
895                        rule: String::from(
896                            "check if resource($resource), $resource.starts_with(\"/folder1/\")"
897                        )
898                    }),]
899                }))
900            );
901        }
902
903        {
904            let mut authorizer = biscuit2.authorizer().unwrap();
905            authorizer.add_fact("resource(\"/folder2/file1\")").unwrap();
906            authorizer.add_fact("operation(\"write\")").unwrap();
907
908            let res = authorizer.authorize();
909            println!("res3: {:?}", res);
910            assert_eq!(res,
911              Err(Token::FailedLogic(Logic::NoMatchingPolicy {
912                  checks: vec![
913                FailedCheck::Block(FailedBlockCheck { block_id: 1, check_id: 0, rule: String::from("check if resource($resource), $resource.starts_with(\"/folder1/\")") }),
914                FailedCheck::Block(FailedBlockCheck { block_id: 1, check_id: 1, rule: String::from("check if resource($resource_name), operation(\"read\"), right($resource_name, \"read\")") }),
915              ]})));
916        }
917    }
918
919    #[test]
920    fn constraints() {
921        let mut rng: StdRng = SeedableRng::seed_from_u64(0);
922        let root = KeyPair::new_with_rng(&mut rng);
923
924        let mut builder = Biscuit::builder();
925
926        builder.add_right("file1", "read");
927        builder.add_right("file2", "read");
928
929        let biscuit1 = builder
930            .build_with_rng(&root, default_symbol_table(), &mut rng)
931            .unwrap();
932
933        println!("biscuit1 (authority): {}", biscuit1);
934
935        let mut block2 = BlockBuilder::new();
936
937        block2.check_expiration_date(SystemTime::now() + Duration::from_secs(30));
938        block2.add_fact("key(1234)").unwrap();
939
940        let keypair2 = KeyPair::new_with_rng(&mut rng);
941        let biscuit2 = biscuit1.append_with_keypair(&keypair2, block2).unwrap();
942
943        {
944            let mut authorizer = biscuit2.authorizer().unwrap();
945            authorizer.add_fact("resource(\"file1\")").unwrap();
946            authorizer.add_fact("operation(\"read\")").unwrap();
947            authorizer.set_time();
948            authorizer.allow().unwrap();
949
950            let res = authorizer.authorize_with_limits(AuthorizerLimits {
951                max_time: Duration::from_secs(10),
952                ..Default::default()
953            });
954            println!("res1: {:?}", res);
955            res.unwrap();
956        }
957
958        {
959            println!("biscuit2: {}", biscuit2);
960            let mut authorizer = biscuit2.authorizer().unwrap();
961            authorizer.add_fact("resource(\"file1\")").unwrap();
962            authorizer.add_fact("operation(\"read\")").unwrap();
963            authorizer.set_time();
964            authorizer.allow().unwrap();
965
966            let res = authorizer.authorize_with_limits(AuthorizerLimits {
967                max_time: Duration::from_secs(10),
968                ..Default::default()
969            });
970            println!("res3: {:?}", res);
971
972            // error message should be like this:
973            //"authorizer check 0 failed: check if revocation_id($0), $0 not in [2, 1234, 1, 5, 0]"
974            assert!(res.is_ok());
975        }
976    }
977
978    #[test]
979    fn sealed_token() {
980        let mut rng: StdRng = SeedableRng::seed_from_u64(0);
981        let root = KeyPair::new_with_rng(&mut rng);
982        let mut builder = Biscuit::builder();
983
984        builder.add_right("/folder1/file1", "read");
985        builder.add_right("/folder1/file1", "write");
986        builder.add_right("/folder1/file2", "read");
987        builder.add_right("/folder1/file2", "write");
988        builder.add_right("/folder2/file3", "read");
989
990        let biscuit1 = builder
991            .build_with_rng(&root, default_symbol_table(), &mut rng)
992            .unwrap();
993
994        println!("biscuit1 (authority): {}", biscuit1);
995
996        let mut block2 = BlockBuilder::new();
997
998        block2.check_resource_prefix("/folder1/");
999        block2.check_right("read");
1000
1001        let keypair2 = KeyPair::new_with_rng(&mut rng);
1002        let biscuit2 = biscuit1.append_with_keypair(&keypair2, block2).unwrap();
1003
1004        //println!("biscuit2:\n{:#?}", biscuit2);
1005        //panic!();
1006        {
1007            let mut authorizer = biscuit2.authorizer().unwrap();
1008            authorizer.add_fact("resource(\"/folder1/file1\")").unwrap();
1009            authorizer.add_fact("operation(\"read\")").unwrap();
1010            authorizer.allow().unwrap();
1011
1012            let res = authorizer.authorize_with_limits(AuthorizerLimits {
1013                max_time: Duration::from_secs(10),
1014                ..Default::default()
1015            });
1016            println!("res1: {:?}", res);
1017            res.unwrap();
1018        }
1019
1020        let _serialized = biscuit2.to_vec().unwrap();
1021        //println!("biscuit2 serialized ({} bytes):\n{}", serialized.len(), serialized.to_hex(16));
1022
1023        let sealed = biscuit2.seal().unwrap().to_vec().unwrap();
1024        //println!("biscuit2 sealed ({} bytes):\n{}", sealed.len(), sealed.to_hex(16));
1025
1026        let biscuit3 = Biscuit::from(sealed, root.public()).unwrap();
1027
1028        {
1029            let mut authorizer = biscuit3.authorizer().unwrap();
1030            authorizer.add_fact("resource(\"/folder1/file1\")").unwrap();
1031            authorizer.add_fact("operation(\"read\")").unwrap();
1032            authorizer.allow().unwrap();
1033
1034            let res = authorizer.authorize();
1035            println!("res1: {:?}", res);
1036            res.unwrap();
1037        }
1038    }
1039
1040    #[test]
1041    fn verif_no_blocks() {
1042        use crate::token::builder::*;
1043
1044        let mut rng: StdRng = SeedableRng::seed_from_u64(1234);
1045        let root = KeyPair::new_with_rng(&mut rng);
1046
1047        let mut builder = Biscuit::builder();
1048
1049        builder
1050            .add_fact(fact("right", &[string("file1"), string("read")]))
1051            .unwrap();
1052        builder
1053            .add_fact(fact("right", &[string("file2"), string("read")]))
1054            .unwrap();
1055        builder
1056            .add_fact(fact("right", &[string("file1"), string("write")]))
1057            .unwrap();
1058
1059        let biscuit1 = builder
1060            .build_with_rng(&root, default_symbol_table(), &mut rng)
1061            .unwrap();
1062        println!("{}", biscuit1);
1063
1064        let mut v = biscuit1.authorizer().expect("omg authorizer");
1065
1066        v.add_check(rule(
1067            "right",
1068            &[string("right")],
1069            &[pred("right", &[string("file2"), string("write")])],
1070        ))
1071        .unwrap();
1072
1073        //assert!(v.verify().is_err());
1074        let res = v.authorize_with_limits(AuthorizerLimits {
1075            max_time: Duration::from_secs(10),
1076            ..Default::default()
1077        });
1078        println!("res: {:?}", res);
1079        assert_eq!(
1080            res,
1081            Err(Token::FailedLogic(Logic::NoMatchingPolicy {
1082                checks: vec![FailedCheck::Authorizer(FailedAuthorizerCheck {
1083                    check_id: 0,
1084                    rule: String::from("check if right(\"file2\", \"write\")")
1085                }),]
1086            }))
1087        );
1088    }
1089
1090    #[test]
1091    fn authorizer_queries() {
1092        let mut rng: StdRng = SeedableRng::seed_from_u64(0);
1093        let root = KeyPair::new_with_rng(&mut rng);
1094
1095        let mut builder = Biscuit::builder();
1096
1097        builder.add_right("file1", "read");
1098        builder.add_right("file2", "read");
1099        builder.add_fact("key(0000)").unwrap();
1100
1101        let biscuit1 = builder
1102            .build_with_rng(&root, default_symbol_table(), &mut rng)
1103            .unwrap();
1104
1105        println!("biscuit1 (authority): {}", biscuit1);
1106
1107        let mut block2 = BlockBuilder::new();
1108
1109        block2.check_expiration_date(SystemTime::now() + Duration::from_secs(30));
1110        block2.add_fact("key(1234)").unwrap();
1111
1112        let keypair2 = KeyPair::new_with_rng(&mut rng);
1113        let biscuit2 = biscuit1.append_with_keypair(&keypair2, block2).unwrap();
1114
1115        let mut block3 = BlockBuilder::new();
1116
1117        block3.check_expiration_date(SystemTime::now() + Duration::from_secs(10));
1118        block3.add_fact("key(5678)").unwrap();
1119
1120        let keypair3 = KeyPair::new_with_rng(&mut rng);
1121        let biscuit3 = biscuit2.append_with_keypair(&keypair3, block3).unwrap();
1122        {
1123            println!("biscuit3: {}", biscuit3);
1124
1125            let mut authorizer = biscuit3.authorizer().unwrap();
1126            authorizer.add_fact("resource(\"file1\")").unwrap();
1127            authorizer.add_fact("operation(\"read\")").unwrap();
1128            authorizer.set_time();
1129
1130            // test that cloning correctly embeds the first block's facts
1131            let mut other_authorizer = authorizer.clone();
1132
1133            let authorization_res = authorizer.authorize_with_limits(AuthorizerLimits {
1134                max_time: Duration::from_secs(10),
1135                ..Default::default()
1136            });
1137            println!("authorization result: {:?}", authorization_res);
1138
1139            println!("world:\n{}", authorizer.print_world());
1140            let res2: Result<Vec<builder::Fact>, crate::error::Token> = authorizer
1141                .query_all_with_limits(
1142                    "key_verif($id) <- key($id)",
1143                    AuthorizerLimits {
1144                        max_time: Duration::from_secs(10),
1145                        ..Default::default()
1146                    },
1147                );
1148
1149            println!("res2: {:?}", res2);
1150            let mut res2 = res2
1151                .unwrap()
1152                .iter()
1153                .map(|f| f.to_string())
1154                .collect::<Vec<_>>();
1155            res2.sort();
1156            assert_eq!(
1157                res2,
1158                vec![
1159                    "key_verif(0)".to_string(),
1160                    "key_verif(1234)".to_string(),
1161                    "key_verif(5678)".to_string(),
1162                ]
1163            );
1164
1165            let res1: Result<Vec<builder::Fact>, crate::error::Token> =
1166                other_authorizer.query("key_verif($id) <- key($id)");
1167            println!("res1: {:?}", res1);
1168            assert_eq!(
1169                res1.unwrap()
1170                    .into_iter()
1171                    .map(|f| f.to_string())
1172                    .collect::<Vec<_>>(),
1173                vec!["key_verif(0)".to_string()]
1174            );
1175        }
1176    }
1177
1178    #[test]
1179    fn check_head_name() {
1180        let mut rng: StdRng = SeedableRng::seed_from_u64(0);
1181        let root = KeyPair::new_with_rng(&mut rng);
1182
1183        let mut builder = Biscuit::builder();
1184
1185        builder
1186            .add_check(check(
1187                &[pred("resource", &[string("hello")])],
1188                CheckKind::One,
1189            ))
1190            .unwrap();
1191
1192        let biscuit1 = builder
1193            .build_with_rng(&root, default_symbol_table(), &mut rng)
1194            .unwrap();
1195
1196        println!("biscuit1 (authority): {}", biscuit1);
1197
1198        // new check: can only have read access1
1199        let mut block2 = BlockBuilder::new();
1200        block2.add_fact(fact("check1", &[string("test")])).unwrap();
1201
1202        let keypair2 = KeyPair::new_with_rng(&mut rng);
1203        let biscuit2 = biscuit1.append_with_keypair(&keypair2, block2).unwrap();
1204
1205        println!("biscuit2: {}", biscuit2);
1206
1207        //println!("generated biscuit token 2: {} bytes\n{}", serialized2.len(), serialized2.to_hex(16));
1208        {
1209            let mut authorizer = biscuit2.authorizer().unwrap();
1210            authorizer.add_fact("resource(\"file1\")").unwrap();
1211            authorizer.add_fact("operation(\"read\")").unwrap();
1212            println!("symbols before time: {:?}", authorizer.symbols);
1213            authorizer.set_time();
1214
1215            println!("world:\n{}", authorizer.print_world());
1216            println!("symbols: {:?}", authorizer.symbols);
1217
1218            let res = authorizer.authorize_with_limits(AuthorizerLimits {
1219                max_time: Duration::from_secs(10),
1220                ..Default::default()
1221            });
1222            println!("res1: {:?}", res);
1223
1224            assert_eq!(
1225                res,
1226                Err(Token::FailedLogic(Logic::NoMatchingPolicy {
1227                    checks: vec![FailedCheck::Block(FailedBlockCheck {
1228                        block_id: 0,
1229                        check_id: 0,
1230                        rule: String::from("check if resource(\"hello\")"),
1231                    }),]
1232                }))
1233            );
1234        }
1235    }
1236
1237    /*
1238    #[test]
1239    fn check_requires_fact_in_future_block() {
1240        let mut rng: StdRng = SeedableRng::seed_from_u64(0);
1241        let root = KeyPair::new_with_rng(&mut rng);
1242
1243        let mut builder = Biscuit::builder(&root);
1244
1245        builder
1246            .add_authority_check(check(&[pred("name", &[var("name")])]))
1247            .unwrap();
1248
1249        let biscuit1 = builder.build_with_rng(&mut rng).unwrap();
1250
1251        println!("biscuit1 (authority): {}", biscuit1);
1252        let mut authorizer1 = biscuit1.verify().unwrap();
1253        authorizer1.allow().unwrap();
1254        let res1 = authorizer1.verify();
1255        println!("res1: {:?}", res1);
1256        assert_eq!(
1257            res1,
1258            Err(Token::FailedLogic(Logic::FailedChecks(vec![
1259                FailedCheck::Block(FailedBlockCheck {
1260                    block_id: 0,
1261                    check_id: 0,
1262                    rule: String::from("check if name($name)"),
1263                }),
1264            ])))
1265        );
1266
1267        let mut block2 = BlockBuilder::new();
1268        block2.add_fact(fact("name", &[string("test")])).unwrap();
1269
1270        let keypair2 = KeyPair::new_with_rng(&mut rng);
1271        let biscuit2 = biscuit1
1272            .append_with_keypair(&keypair2, block2)
1273            .unwrap();
1274
1275        println!("biscuit2 (with name fact): {}", biscuit2);
1276        let mut authorizer2 = biscuit2.verify().unwrap();
1277        authorizer2.allow().unwrap();
1278        let res2 = authorizer2.verify();
1279        assert_eq!(res2, Ok(0));
1280    }*/
1281
1282    #[test]
1283    fn bytes_constraints() {
1284        let mut rng: StdRng = SeedableRng::seed_from_u64(0);
1285        let root = KeyPair::new_with_rng(&mut rng);
1286
1287        let mut builder = Biscuit::builder();
1288        builder.add_fact("bytes(hex:0102AB)").unwrap();
1289        let biscuit1 = builder
1290            .build_with_rng(&root, default_symbol_table(), &mut rng)
1291            .unwrap();
1292
1293        println!("biscuit1 (authority): {}", biscuit1);
1294
1295        let mut block2 = BlockBuilder::new();
1296        block2
1297            .add_rule("has_bytes($0) <- bytes($0), [ hex:00000000, hex:0102AB ].contains($0)")
1298            .unwrap();
1299        let keypair2 = KeyPair::new_with_rng(&mut rng);
1300        let biscuit2 = biscuit1.append_with_keypair(&keypair2, block2).unwrap();
1301
1302        let mut authorizer = biscuit2.authorizer().unwrap();
1303        authorizer
1304            .add_check("check if bytes($0), [ hex:00000000, hex:0102AB ].contains($0)")
1305            .unwrap();
1306        authorizer.allow().unwrap();
1307
1308        let res = authorizer.authorize_with_limits(AuthorizerLimits {
1309            max_time: Duration::from_secs(10),
1310            ..Default::default()
1311        });
1312        println!("res1: {:?}", res);
1313        res.unwrap();
1314
1315        let res: Vec<(Vec<u8>,)> = authorizer
1316            .query_with_limits(
1317                "data($0) <- bytes($0)",
1318                AuthorizerLimits {
1319                    max_time: Duration::from_secs(10),
1320                    ..Default::default()
1321                },
1322            )
1323            .unwrap();
1324        println!("query result: {:x?}", res);
1325        println!("query result: {:?}", res[0]);
1326    }
1327
1328    #[test]
1329    fn block1_generates_authority_or_ambient() {
1330        let mut rng: StdRng = SeedableRng::seed_from_u64(0);
1331        let root = KeyPair::new_with_rng(&mut rng);
1332
1333        let serialized1 = {
1334            let mut builder = Biscuit::builder();
1335
1336            builder
1337                .add_fact("right(\"/folder1/file1\", \"read\")")
1338                .unwrap();
1339            builder
1340                .add_fact("right(\"/folder1/file1\", \"write\")")
1341                .unwrap();
1342            builder
1343                .add_fact("right(\"/folder2/file1\", \"read\")")
1344                .unwrap();
1345            builder.add_check("check if operation(\"read\")").unwrap();
1346
1347            let biscuit1 = builder
1348                .build_with_rng(&root, default_symbol_table(), &mut rng)
1349                .unwrap();
1350
1351            println!("biscuit1 (authority): {}", biscuit1);
1352
1353            biscuit1.to_vec().unwrap()
1354        };
1355
1356        //println!("generated biscuit token: {} bytes:\n{}", serialized1.len(), serialized1.to_hex(16));
1357        println!("generated biscuit token: {} bytes", serialized1.len());
1358        //panic!();
1359
1360        let serialized2 = {
1361            let biscuit1_deser = Biscuit::from(&serialized1, |_| Ok(root.public())).unwrap();
1362
1363            // new check: can only have read access1
1364            let mut block2 = BlockBuilder::new();
1365
1366            // Bypass `check if operation("read")` from authority block
1367            block2
1368                .add_rule("operation(\"read\") <- operation($any)")
1369                .unwrap();
1370
1371            // Bypass `check if resource($file), $file.starts_with("/folder1/")` from block #1
1372            block2
1373                .add_rule("resource(\"/folder1/\") <- resource($any)")
1374                .unwrap();
1375
1376            // Add missing rights
1377            block2.add_rule("right($file, $right) <- right($any1, $any2), resource($file), operation($right)")
1378                .unwrap();
1379
1380            let keypair2 = KeyPair::new_with_rng(&mut rng);
1381            let biscuit2 = biscuit1_deser
1382                .append_with_keypair(&keypair2, block2)
1383                .unwrap();
1384
1385            println!("biscuit2 (1 check): {}", biscuit2);
1386
1387            biscuit2.to_vec().unwrap()
1388        };
1389
1390        //println!("generated biscuit token 2: {} bytes\n{}", serialized2.len(), serialized2.to_hex(16));
1391        println!("generated biscuit token 2: {} bytes", serialized2.len());
1392
1393        let final_token = Biscuit::from(&serialized2, root.public()).unwrap();
1394        println!("final token:\n{}", final_token);
1395
1396        let mut authorizer = final_token.authorizer().unwrap();
1397        authorizer.add_fact("resource(\"/folder2/file1\")").unwrap();
1398        authorizer.add_fact("operation(\"write\")").unwrap();
1399        authorizer
1400            .add_policy("allow if resource($file), operation($op), right($file, $op)")
1401            .unwrap();
1402        authorizer.deny().unwrap();
1403
1404        let res = authorizer.authorize_with_limits(crate::token::authorizer::AuthorizerLimits {
1405            max_time: Duration::from_secs(1),
1406            ..Default::default()
1407        });
1408        println!("res1: {:?}", res);
1409        println!("authorizer:\n{}", authorizer.print_world());
1410
1411        assert!(res.is_err());
1412    }
1413
1414    #[test]
1415    fn check_all() {
1416        let mut rng: StdRng = SeedableRng::seed_from_u64(0);
1417        let root = KeyPair::new_with_rng(&mut rng);
1418
1419        let mut builder = Biscuit::builder();
1420
1421        builder.add_check("check if fact($v), $v < 1").unwrap();
1422
1423        let biscuit1 = builder
1424            .build_with_rng(&root, default_symbol_table(), &mut rng)
1425            .unwrap();
1426
1427        println!("biscuit1 (authority): {}", biscuit1);
1428
1429        let mut builder = Biscuit::builder();
1430
1431        builder.add_check("check all fact($v), $v < 1").unwrap();
1432
1433        let biscuit2 = builder
1434            .build_with_rng(&root, default_symbol_table(), &mut rng)
1435            .unwrap();
1436
1437        println!("biscuit2 (authority): {}", biscuit2);
1438
1439        {
1440            let mut authorizer = biscuit1.authorizer().unwrap();
1441            authorizer.add_fact("fact(0)").unwrap();
1442            authorizer.add_fact("fact(1)").unwrap();
1443
1444            //println!("final token: {:#?}", final_token);
1445            authorizer.allow().unwrap();
1446
1447            let res = authorizer.authorize_with_limits(AuthorizerLimits {
1448                max_time: Duration::from_secs(10),
1449                ..Default::default()
1450            });
1451            println!("res1: {:?}", res);
1452            res.unwrap();
1453        }
1454
1455        {
1456            let mut authorizer = biscuit2.authorizer().unwrap();
1457            authorizer.add_fact("fact(0)").unwrap();
1458            authorizer.add_fact("fact(1)").unwrap();
1459
1460            //println!("final token: {:#?}", final_token);
1461            authorizer.allow().unwrap();
1462
1463            let res = authorizer.authorize_with_limits(AuthorizerLimits {
1464                max_time: Duration::from_secs(10),
1465                ..Default::default()
1466            });
1467            println!("res2: {:?}", res);
1468
1469            assert_eq!(
1470                res,
1471                Err(Token::FailedLogic(Logic::Unauthorized {
1472                    policy: MatchedPolicy::Allow(0),
1473                    checks: vec![FailedCheck::Block(FailedBlockCheck {
1474                        block_id: 0,
1475                        check_id: 0,
1476                        rule: String::from("check all fact($v), $v < 1"),
1477                    }),]
1478                }))
1479            );
1480        }
1481    }
1482}