1use std::fmt::Display;
3use std::iter::once;
4
5use builder::{BiscuitBuilder, BlockBuilder};
6use prost::Message;
7use rand_core::{CryptoRng, RngCore};
8
9use self::public_keys::PublicKeys;
10use super::crypto::{KeyPair, PublicKey, Signature};
11use super::datalog::SymbolTable;
12use super::error;
13use super::format::SerializedBiscuit;
14use crate::crypto::{self};
15use crate::format::convert::proto_block_to_token_block;
16use crate::format::schema::{self, ThirdPartyBlockContents};
17use crate::format::{ThirdPartyVerificationMode, THIRD_PARTY_SIGNATURE_VERSION};
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;
27pub use block::Block;
28pub use third_party::*;
29
30pub const MIN_SCHEMA_VERSION: u32 = 3;
32pub const MAX_SCHEMA_VERSION: u32 = 6;
34pub const DATALOG_3_1: u32 = 4;
36pub const DATALOG_3_2: u32 = 5;
38pub const DATALOG_3_3: u32 = 6;
40
41pub fn default_symbol_table() -> SymbolTable {
44 SymbolTable::new()
45}
46
47#[derive(Clone, Debug)]
80pub struct Biscuit {
81 pub(crate) root_key_id: Option<u32>,
82 pub(crate) authority: schema::Block,
83 pub(crate) blocks: Vec<schema::Block>,
84 pub(crate) symbols: SymbolTable,
85 pub(crate) container: SerializedBiscuit,
86}
87
88impl Biscuit {
89 pub fn builder() -> BiscuitBuilder {
93 BiscuitBuilder::new()
94 }
95
96 pub fn from<T, KP>(slice: T, key_provider: KP) -> Result<Self, error::Token>
98 where
99 T: AsRef<[u8]>,
100 KP: RootKeyProvider,
101 {
102 Biscuit::from_with_symbols(slice.as_ref(), key_provider, default_symbol_table())
103 }
104
105 pub fn from_base64<T, KP>(slice: T, key_provider: KP) -> Result<Self, error::Token>
107 where
108 T: AsRef<[u8]>,
109 KP: RootKeyProvider,
110 {
111 Biscuit::from_base64_with_symbols(slice, key_provider, default_symbol_table())
112 }
113
114 pub fn unsafe_deprecated_deserialize<T, KP>(
118 slice: T,
119 key_provider: KP,
120 ) -> Result<Self, error::Token>
121 where
122 T: AsRef<[u8]>,
123 KP: RootKeyProvider,
124 {
125 let container = SerializedBiscuit::unsafe_from_slice(slice.as_ref(), key_provider)
126 .map_err(error::Token::Format)?;
127
128 Biscuit::from_serialized_container(container, default_symbol_table())
129 }
130
131 pub fn to_vec(&self) -> Result<Vec<u8>, error::Token> {
133 self.container.to_vec().map_err(error::Token::Format)
134 }
135
136 pub fn to_base64(&self) -> Result<String, error::Token> {
138 self.container
139 .to_vec()
140 .map_err(error::Token::Format)
141 .map(|v| base64::encode_config(v, base64::URL_SAFE))
142 }
143
144 pub fn serialized_size(&self) -> Result<usize, error::Token> {
146 Ok(self.container.serialized_size())
147 }
148
149 pub fn seal(&self) -> Result<Biscuit, error::Token> {
153 let container = self.container.seal()?;
154
155 let mut token = self.clone();
156 token.container = container;
157
158 Ok(token)
159 }
160
161 pub fn authorizer(&self) -> Result<Authorizer, error::Token> {
163 Authorizer::from_token(self)
164 }
165
166 pub fn append(&self, block_builder: BlockBuilder) -> Result<Self, error::Token> {
171 let keypair = KeyPair::new_with_rng(builder::Algorithm::Ed25519, &mut rand::rngs::OsRng);
172 self.append_with_keypair(&keypair, block_builder)
173 }
174
175 pub fn context(&self) -> Vec<Option<String>> {
180 let mut res = vec![self.authority.context.clone()];
181
182 for b in self.blocks.iter() {
183 res.push(b.context.clone());
184 }
185
186 res
187 }
188
189 pub fn root_key_id(&self) -> Option<u32> {
191 self.root_key_id
192 }
193
194 pub fn revocation_identifiers(&self) -> Vec<Vec<u8>> {
199 let mut res = vec![self.container.authority.signature.to_bytes().to_vec()];
200
201 for block in self.container.blocks.iter() {
202 res.push(block.signature.to_bytes().to_vec());
203 }
204
205 res
206 }
207
208 pub fn external_public_keys(&self) -> Vec<Option<PublicKey>> {
214 let mut res = vec![None];
215
216 for block in self.container.blocks.iter() {
217 res.push(block.external_signature.as_ref().map(|sig| sig.public_key));
218 }
219
220 res
221 }
222
223 pub fn print(&self) -> String {
225 format!("{}", &self)
226 }
227
228 pub fn print_block_source(&self, index: usize) -> Result<String, error::Token> {
230 self.block(index).map(|block| {
231 let symbols = if block.external_key.is_some() {
232 &block.symbols
233 } else {
234 &self.symbols
235 };
236 block.print_source(symbols)
237 })
238 }
239
240 pub fn block_version(&self, index: usize) -> Result<u32, error::Token> {
242 self.block(index).map(|block| block.version)
243 }
244
245 pub(crate) fn new_with_rng<T: RngCore + CryptoRng>(
249 rng: &mut T,
250 root_key_id: Option<u32>,
251 root: &KeyPair,
252 symbols: SymbolTable,
253 authority: Block,
254 ) -> Result<Biscuit, error::Token> {
255 Self::new_with_key_pair(
256 root_key_id,
257 root,
258 &KeyPair::new_with_rng(builder::Algorithm::Ed25519, rng),
259 symbols,
260 authority,
261 )
262 }
263
264 pub(crate) fn new_with_key_pair(
268 root_key_id: Option<u32>,
269 root: &KeyPair,
270 next_keypair: &KeyPair,
271 mut symbols: SymbolTable,
272 authority: Block,
273 ) -> Result<Biscuit, error::Token> {
274 if !symbols.is_disjoint(&authority.symbols) {
275 return Err(error::Token::Format(error::Format::SymbolTableOverlap));
276 }
277
278 symbols.extend(&authority.symbols)?;
279
280 let blocks = vec![];
281
282 let container = SerializedBiscuit::new(root_key_id, root, next_keypair, &authority)?;
283
284 symbols.public_keys.extend(&authority.public_keys)?;
285
286 let authority = schema::Block::decode(&container.authority.data[..]).map_err(|e| {
287 error::Token::Format(error::Format::BlockDeserializationError(format!(
288 "error deserializing block: {:?}",
289 e
290 )))
291 })?;
292
293 Ok(Biscuit {
294 root_key_id,
295 authority,
296 blocks,
297 symbols,
298 container,
299 })
300 }
301
302 fn from_with_symbols<KP>(
304 slice: &[u8],
305 key_provider: KP,
306 symbols: SymbolTable,
307 ) -> Result<Self, error::Token>
308 where
309 KP: RootKeyProvider,
310 {
311 let container =
312 SerializedBiscuit::from_slice(slice, key_provider).map_err(error::Token::Format)?;
313
314 Biscuit::from_serialized_container(container, symbols)
315 }
316
317 fn from_serialized_container(
318 container: SerializedBiscuit,
319 mut symbols: SymbolTable,
320 ) -> Result<Self, error::Token> {
321 let (authority, blocks) = container.extract_blocks(&mut symbols)?;
322
323 let root_key_id = container.root_key_id;
324
325 Ok(Biscuit {
326 root_key_id,
327 authority,
328 blocks,
329 symbols,
330 container,
331 })
332 }
333
334 fn from_base64_with_symbols<T, KP>(
336 slice: T,
337 key_provider: KP,
338 symbols: SymbolTable,
339 ) -> Result<Self, error::Token>
340 where
341 T: AsRef<[u8]>,
342 KP: RootKeyProvider,
343 {
344 let decoded = base64::decode_config(slice, base64::URL_SAFE)?;
345 Biscuit::from_with_symbols(&decoded, key_provider, symbols)
346 }
347
348 pub fn container(&self) -> &SerializedBiscuit {
350 &self.container
351 }
352
353 pub fn append_with_keypair(
358 &self,
359 keypair: &KeyPair,
360 block_builder: BlockBuilder,
361 ) -> Result<Self, error::Token> {
362 let block = block_builder.build(self.symbols.clone());
363
364 if !self.symbols.is_disjoint(&block.symbols) {
365 return Err(error::Token::Format(error::Format::SymbolTableOverlap));
366 }
367
368 let authority = self.authority.clone();
369 let mut blocks = self.blocks.clone();
370 let mut symbols = self.symbols.clone();
371
372 let container = self.container.append(keypair, &block, None)?;
373
374 symbols.extend(&block.symbols)?;
375 symbols.public_keys.extend(&block.public_keys)?;
376
377 let deser = schema::Block::decode(
378 &container
379 .blocks
380 .last()
381 .expect("a new block was just added so the list is not empty")
382 .data[..],
383 )
384 .map_err(|e| {
385 error::Token::Format(error::Format::BlockDeserializationError(format!(
386 "error deserializing block: {:?}",
387 e
388 )))
389 })?;
390 blocks.push(deser);
391
392 Ok(Biscuit {
393 root_key_id: self.root_key_id,
394 authority,
395 blocks,
396 symbols,
397 container,
398 })
399 }
400
401 pub fn third_party_request(&self) -> Result<ThirdPartyRequest, error::Token> {
402 ThirdPartyRequest::from_container(&self.container)
403 }
404
405 pub fn append_third_party(
406 &self,
407 external_key: PublicKey,
408 response: ThirdPartyBlock,
409 ) -> Result<Self, error::Token> {
410 let next_keypair =
411 KeyPair::new_with_rng(builder::Algorithm::Ed25519, &mut rand::rngs::OsRng);
412
413 self.append_third_party_with_keypair(external_key, response, next_keypair)
414 }
415 pub fn append_third_party_with_keypair(
416 &self,
417 external_key: PublicKey,
418 response: ThirdPartyBlock,
419 next_keypair: KeyPair,
420 ) -> Result<Self, error::Token> {
421 let ThirdPartyBlockContents {
422 payload,
423 external_signature,
424 } = response.0;
425
426 let provided_key = PublicKey::from_proto(&external_signature.public_key)?;
427 if external_key != provided_key {
428 return Err(error::Token::Format(error::Format::DeserializationError(
429 format!(
430 "deserialization error: unexpected key {}",
431 provided_key.print()
432 ),
433 )));
434 }
435
436 let signature = Signature::from_vec(external_signature.signature);
437
438 let previous_key = self
439 .container
440 .blocks
441 .last()
442 .unwrap_or(&self.container.authority)
443 .next_key;
444
445 let external_signature = crypto::ExternalSignature {
446 public_key: external_key,
447 signature,
448 };
449 crypto::verify_external_signature(
450 &payload,
451 &previous_key,
452 &self
453 .container
454 .blocks
455 .last()
456 .unwrap_or(&self.container.authority)
457 .signature,
458 &external_signature,
459 THIRD_PARTY_SIGNATURE_VERSION,
460 ThirdPartyVerificationMode::PreviousSignatureHashing,
461 )?;
462
463 let block = schema::Block::decode(&payload[..]).map_err(|e| {
464 error::Token::Format(error::Format::DeserializationError(format!(
465 "deserialization error: {:?}",
466 e
467 )))
468 })?;
469
470 let symbols = self.symbols.clone();
471 let mut blocks = self.blocks.clone();
472
473 let container =
474 self.container
475 .append_serialized(&next_keypair, payload, Some(external_signature))?;
476
477 blocks.push(block);
478
479 Ok(Biscuit {
480 root_key_id: self.root_key_id,
481 authority: self.authority.clone(),
482 blocks,
483 symbols,
484 container,
485 })
486 }
487
488 pub fn block_symbols(&self, index: usize) -> Result<Vec<String>, error::Token> {
490 let block = if index == 0 {
491 &self.authority
492 } else {
493 match self.blocks.get(index - 1) {
494 None => return Err(error::Token::Format(error::Format::InvalidBlockId(index))),
495 Some(block) => block,
496 }
497 };
498
499 Ok(block.symbols.clone())
500 }
501
502 pub fn block_public_keys(&self, index: usize) -> Result<PublicKeys, error::Token> {
504 let block = if index == 0 {
505 &self.authority
506 } else {
507 match self.blocks.get(index - 1) {
508 None => return Err(error::Token::Format(error::Format::InvalidBlockId(index))),
509 Some(block) => block,
510 }
511 };
512
513 let mut public_keys = PublicKeys::new();
514
515 for pk in &block.public_keys {
516 public_keys.insert(&PublicKey::from_proto(pk)?);
517 }
518 Ok(public_keys)
519 }
520
521 pub fn block_external_key(&self, index: usize) -> Result<Option<PublicKey>, error::Token> {
523 let block = if index == 0 {
524 &self.container.authority
525 } else {
526 match self.container.blocks.get(index - 1) {
527 None => return Err(error::Token::Format(error::Format::InvalidBlockId(index))),
528 Some(block) => block,
529 }
530 };
531
532 Ok(block
533 .external_signature
534 .as_ref()
535 .map(|signature| signature.public_key))
536 }
537
538 pub fn block_count(&self) -> usize {
540 1 + self.blocks.len()
541 }
542
543 pub(crate) fn block(&self, index: usize) -> Result<Block, error::Token> {
544 let block = if index == 0 {
545 proto_block_to_token_block(
546 &self.authority,
547 self.container
548 .authority
549 .external_signature
550 .as_ref()
551 .map(|ex| ex.public_key),
552 )
553 .map_err(error::Token::Format)?
554 } else {
555 if index > self.blocks.len() + 1 {
556 return Err(error::Token::Format(
557 error::Format::BlockDeserializationError("invalid block index".to_string()),
558 ));
559 }
560
561 proto_block_to_token_block(
562 &self.blocks[index - 1],
563 self.container.blocks[index - 1]
564 .external_signature
565 .as_ref()
566 .map(|ex| ex.public_key),
567 )
568 .map_err(error::Token::Format)?
569 };
570
571 Ok(block)
572 }
573
574 pub(crate) fn blocks(&self) -> impl Iterator<Item = Result<Block, error::Token>> + use<'_> {
575 once(
576 proto_block_to_token_block(
577 &self.authority,
578 self.container
579 .authority
580 .external_signature
581 .as_ref()
582 .map(|ex| ex.public_key),
583 )
584 .map_err(error::Token::Format),
585 )
586 .chain(self.blocks.iter().zip(self.container.blocks.iter()).map(
587 |(block, container)| {
588 proto_block_to_token_block(
589 block,
590 container
591 .external_signature
592 .as_ref()
593 .map(|ex| ex.public_key),
594 )
595 .map_err(error::Token::Format)
596 },
597 ))
598 }
599}
600
601impl Display for Biscuit {
602 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
603 let authority = self
604 .block(0)
605 .as_ref()
606 .map(|block| print_block(&self.symbols, block))
607 .unwrap_or_else(|_| String::new());
608 let blocks: Vec<_> = (1..self.block_count())
609 .map(|i| {
610 self.block(i)
611 .as_ref()
612 .map(|block| print_block(&self.symbols, block))
613 .unwrap_or_else(|_| String::new())
614 })
615 .collect();
616
617 write!(f, "Biscuit {{\n symbols: {:?}\n public keys: {:?}\n authority: {}\n blocks: [\n {}\n ]\n}}",
618 self.symbols.strings(),
619 self.symbols.public_keys.keys.iter().map(|pk| hex::encode(pk.to_bytes())).collect::<Vec<_>>(),
620 authority,
621 blocks.join(",\n\t")
622 )
623 }
624}
625fn print_block(symbols: &SymbolTable, block: &Block) -> String {
626 let facts: Vec<_> = block.facts.iter().map(|f| symbols.print_fact(f)).collect();
627 let rules: Vec<_> = block.rules.iter().map(|r| symbols.print_rule(r)).collect();
628 let checks: Vec<_> = block
629 .checks
630 .iter()
631 .map(|r| symbols.print_check(r))
632 .collect();
633
634 let facts = if facts.is_empty() {
635 String::new()
636 } else {
637 format!(
638 "\n {}\n ",
639 facts.join(",\n ")
640 )
641 };
642 let rules = if rules.is_empty() {
643 String::new()
644 } else {
645 format!(
646 "\n {}\n ",
647 rules.join(",\n ")
648 )
649 };
650 let checks = if checks.is_empty() {
651 String::new()
652 } else {
653 format!(
654 "\n {}\n ",
655 checks.join(",\n ")
656 )
657 };
658
659 format!(
660 "Block {{\n symbols: {:?}\n version: {}\n context: \"{}\"\n external key: {}\n public keys: {:?}\n scopes: {:?}\n facts: [{}]\n rules: [{}]\n checks: [{}]\n }}",
661 block.symbols.strings(),
662 block.version,
663 block.context.as_deref().unwrap_or(""),
664 block.external_key.as_ref().map(|k| hex::encode(k.to_bytes())).unwrap_or_default(),
665 block.public_keys.keys.iter().map(|k | hex::encode(k.to_bytes())).collect::<Vec<_>>(),
666 block.scopes,
667 facts,
668 rules,
669 checks,
670 )
671}
672
673#[derive(Clone, Debug, Hash, PartialEq, Eq)]
674pub enum Scope {
675 Authority,
676 Previous,
677 PublicKey(u64),
679}
680
681pub trait RootKeyProvider {
688 fn choose(&self, key_id: Option<u32>) -> Result<PublicKey, error::Format>;
689}
690
691impl RootKeyProvider for Box<dyn RootKeyProvider> {
692 fn choose(&self, key_id: Option<u32>) -> Result<PublicKey, error::Format> {
693 self.as_ref().choose(key_id)
694 }
695}
696
697impl RootKeyProvider for std::rc::Rc<dyn RootKeyProvider> {
698 fn choose(&self, key_id: Option<u32>) -> Result<PublicKey, error::Format> {
699 self.as_ref().choose(key_id)
700 }
701}
702
703impl RootKeyProvider for std::sync::Arc<dyn RootKeyProvider> {
704 fn choose(&self, key_id: Option<u32>) -> Result<PublicKey, error::Format> {
705 self.as_ref().choose(key_id)
706 }
707}
708
709impl RootKeyProvider for PublicKey {
710 fn choose(&self, _: Option<u32>) -> Result<PublicKey, error::Format> {
711 Ok(*self)
712 }
713}
714
715impl RootKeyProvider for &PublicKey {
716 fn choose(&self, _: Option<u32>) -> Result<PublicKey, error::Format> {
717 Ok(**self)
718 }
719}
720
721impl<F: Fn(Option<u32>) -> Result<PublicKey, error::Format>> RootKeyProvider for F {
722 fn choose(&self, root_key_id: Option<u32>) -> Result<PublicKey, error::Format> {
723 self(root_key_id)
724 }
725}
726
727#[cfg(test)]
728mod tests {
729 use super::builder::{check, fact, pred, rule, string, var};
730 use super::builder_ext::BuilderExt;
731 use super::*;
732 use crate::builder::CheckKind;
733 use crate::crypto::KeyPair;
734 use crate::{error::*, AuthorizerLimits, UnverifiedBiscuit};
735 use builder::AuthorizerBuilder;
736 use builder_ext::AuthorizerExt;
737 use rand::prelude::*;
738 use std::time::{Duration, SystemTime};
739
740 #[test]
741 fn basic() {
742 let mut rng: StdRng = SeedableRng::seed_from_u64(0);
743 let root = KeyPair::new_with_rng(builder::Algorithm::Ed25519, &mut rng);
744
745 let serialized1 = {
746 let biscuit1 = Biscuit::builder()
747 .fact("right(\"file1\", \"read\")")
748 .unwrap()
749 .fact("right(\"file2\", \"read\")")
750 .unwrap()
751 .fact("right(\"file1\", \"write\")")
752 .unwrap()
753 .build_with_rng(&root, default_symbol_table(), &mut rng)
754 .unwrap();
755
756 println!("biscuit1 (authority): {}", biscuit1);
757
758 biscuit1.to_vec().unwrap()
759 };
760
761 println!("generated biscuit token: {} bytes", serialized1.len());
763 let serialized2 = {
795 let biscuit1_deser = Biscuit::from(&serialized1, root.public()).unwrap();
796
797 let block2 = BlockBuilder::new()
799 .check(rule(
800 "check1",
801 &[var("resource")],
802 &[
803 pred("resource", &[var("resource")]),
804 pred("operation", &[string("read")]),
805 pred("right", &[var("resource"), string("read")]),
806 ],
807 ))
808 .unwrap();
809
810 let keypair2 = KeyPair::new_with_rng(builder::Algorithm::Ed25519, &mut rng);
811 let biscuit2 = biscuit1_deser
812 .append_with_keypair(&keypair2, block2)
813 .unwrap();
814
815 println!("biscuit2 (1 check): {}", biscuit2);
816
817 biscuit2.to_vec().unwrap()
818 };
819
820 println!("generated biscuit token 2: {} bytes", serialized2.len());
822
823 let serialized3 = {
824 let biscuit2_deser = Biscuit::from(&serialized2, root.public()).unwrap();
825
826 let block3 = BlockBuilder::new()
828 .check(rule(
829 "check2",
830 &[string("file1")],
831 &[pred("resource", &[string("file1")])],
832 ))
833 .unwrap();
834
835 let keypair3 = KeyPair::new_with_rng(builder::Algorithm::Ed25519, &mut rng);
836 let biscuit3 = biscuit2_deser
837 .append_with_keypair(&keypair3, block3)
838 .unwrap();
839
840 biscuit3.to_vec().unwrap()
841 };
842
843 println!("generated biscuit token 3: {} bytes", serialized3.len());
845 let final_token = Biscuit::from(&serialized3, root.public()).unwrap();
848 println!("final token:\n{}", final_token);
849 {
850 let mut builder = AuthorizerBuilder::new();
851
852 let mut facts = vec![
853 fact("resource", &[string("file1")]),
854 fact("operation", &[string("read")]),
855 ];
856
857 for fact in facts.drain(..) {
858 builder = builder.fact(fact).unwrap();
859 }
860
861 let mut authorizer = builder.allow_all().build(&final_token).unwrap();
864
865 let res = authorizer.authorize();
866 println!("res1: {:?}", res);
867 res.unwrap();
868 }
869
870 {
871 let mut builder = AuthorizerBuilder::new();
872
873 let mut facts = vec![
874 fact("resource", &[string("file2")]),
875 fact("operation", &[string("write")]),
876 ];
877
878 for fact in facts.drain(..) {
879 builder = builder.fact(fact).unwrap();
880 }
881 builder = builder.allow_all();
882
883 let mut authorizer = builder.build(&final_token).unwrap();
884
885 let res = authorizer.authorize_with_limits(AuthorizerLimits {
886 max_time: Duration::from_secs(10),
887 ..Default::default()
888 });
889 println!("res2: {:#?}", res);
890 assert_eq!(res,
891 Err(Token::FailedLogic(Logic::Unauthorized {
892 policy: MatchedPolicy::Allow(0),
893 checks: vec![
894 FailedCheck::Block(FailedBlockCheck { block_id: 1, check_id: 0, rule: String::from("check if resource($resource), operation(\"read\"), right($resource, \"read\")") }),
895 FailedCheck::Block(FailedBlockCheck { block_id: 2, check_id: 0, rule: String::from("check if resource(\"file1\")") })
896 ]
897 })));
898 }
899 }
900
901 #[test]
902 fn folders() {
903 let mut rng: StdRng = SeedableRng::seed_from_u64(0);
904 let root = KeyPair::new_with_rng(builder::Algorithm::Ed25519, &mut rng);
905
906 let biscuit1 = Biscuit::builder()
907 .right("/folder1/file1", "read")
908 .right("/folder1/file1", "write")
909 .right("/folder1/file2", "read")
910 .right("/folder1/file2", "write")
911 .right("/folder2/file3", "read")
912 .build_with_rng(&root, default_symbol_table(), &mut rng)
913 .unwrap();
914
915 println!("biscuit1 (authority): {}", biscuit1);
916
917 let block2 = BlockBuilder::new()
918 .check_resource_prefix("/folder1/")
919 .check_right("read")
920 .unwrap();
921
922 let keypair2 = KeyPair::new_with_rng(builder::Algorithm::Ed25519, &mut rng);
923 let biscuit2 = biscuit1.append_with_keypair(&keypair2, block2).unwrap();
924
925 {
926 let mut authorizer = AuthorizerBuilder::new()
927 .fact("resource(\"/folder1/file1\")")
928 .unwrap()
929 .fact("operation(\"read\")")
930 .unwrap()
931 .allow_all()
932 .build(&biscuit2)
933 .unwrap();
934
935 let res = authorizer.authorize_with_limits(AuthorizerLimits {
936 max_time: Duration::from_secs(10),
937 ..Default::default()
938 });
939 println!("res1: {:?}", res);
940 println!("authorizer:\n{}", authorizer.print_world());
941 res.unwrap();
942 }
943
944 {
945 let mut authorizer = AuthorizerBuilder::new()
946 .fact("resource(\"/folder2/file3\")")
947 .unwrap()
948 .fact("operation(\"read\")")
949 .unwrap()
950 .allow_all()
951 .build(&biscuit2)
952 .unwrap();
953
954 let res = authorizer.authorize_with_limits(AuthorizerLimits {
955 max_time: Duration::from_secs(10),
956 ..Default::default()
957 });
958 println!("res2: {:?}", res);
959 assert_eq!(
960 res,
961 Err(Token::FailedLogic(Logic::Unauthorized {
962 policy: MatchedPolicy::Allow(0),
963 checks: vec![FailedCheck::Block(FailedBlockCheck {
964 block_id: 1,
965 check_id: 0,
966 rule: String::from(
967 "check if resource($resource), $resource.starts_with(\"/folder1/\")"
968 )
969 }),]
970 }))
971 );
972 }
973
974 {
975 let mut authorizer = AuthorizerBuilder::new()
976 .fact("resource(\"/folder2/file1\")")
977 .unwrap()
978 .fact("operation(\"write\")")
979 .unwrap()
980 .build(&biscuit2)
981 .unwrap();
982
983 let res = authorizer.authorize();
984 println!("res3: {:?}", res);
985 assert_eq!(res,
986 Err(Token::FailedLogic(Logic::NoMatchingPolicy {
987 checks: vec![
988 FailedCheck::Block(FailedBlockCheck { block_id: 1, check_id: 0, rule: String::from("check if resource($resource), $resource.starts_with(\"/folder1/\")") }),
989 FailedCheck::Block(FailedBlockCheck { block_id: 1, check_id: 1, rule: String::from("check if resource($resource_name), operation(\"read\"), right($resource_name, \"read\")") }),
990 ]})));
991 }
992 }
993
994 #[test]
995 fn constraints() {
996 let mut rng: StdRng = SeedableRng::seed_from_u64(0);
997 let root = KeyPair::new_with_rng(builder::Algorithm::Ed25519, &mut rng);
998
999 let biscuit1 = Biscuit::builder()
1000 .right("file1", "read")
1001 .right("file2", "read")
1002 .build_with_rng(&root, default_symbol_table(), &mut rng)
1003 .unwrap();
1004
1005 println!("biscuit1 (authority): {}", biscuit1);
1006
1007 let block2 = BlockBuilder::new()
1008 .check_expiration_date(SystemTime::now() + Duration::from_secs(30))
1009 .fact("key(1234)")
1010 .unwrap();
1011
1012 let keypair2 = KeyPair::new_with_rng(builder::Algorithm::Ed25519, &mut rng);
1013 let biscuit2 = biscuit1.append_with_keypair(&keypair2, block2).unwrap();
1014
1015 {
1016 let mut authorizer = AuthorizerBuilder::new()
1017 .fact("resource(\"file1\")")
1018 .unwrap()
1019 .fact("operation(\"read\")")
1020 .unwrap()
1021 .time()
1022 .allow_all()
1023 .build(&biscuit2)
1024 .unwrap();
1025
1026 let res = authorizer.authorize_with_limits(AuthorizerLimits {
1027 max_time: Duration::from_secs(10),
1028 ..Default::default()
1029 });
1030 println!("res1: {:?}", res);
1031 res.unwrap();
1032 }
1033
1034 {
1035 println!("biscuit2: {}", biscuit2);
1036 let mut authorizer = AuthorizerBuilder::new()
1037 .fact("resource(\"file1\")")
1038 .unwrap()
1039 .fact("operation(\"read\")")
1040 .unwrap()
1041 .time()
1042 .allow_all()
1043 .build(&biscuit2)
1044 .unwrap();
1045
1046 let res = authorizer.authorize_with_limits(AuthorizerLimits {
1047 max_time: Duration::from_secs(10),
1048 ..Default::default()
1049 });
1050 println!("res3: {:?}", res);
1051
1052 assert!(res.is_ok());
1055 }
1056 }
1057
1058 #[test]
1059 fn sealed_token() {
1060 let mut rng: StdRng = SeedableRng::seed_from_u64(0);
1061 let root = KeyPair::new_with_rng(builder::Algorithm::Ed25519, &mut rng);
1062 let biscuit1 = Biscuit::builder()
1063 .right("/folder1/file1", "read")
1064 .right("/folder1/file1", "write")
1065 .right("/folder1/file2", "read")
1066 .right("/folder1/file2", "write")
1067 .right("/folder2/file3", "read")
1068 .build_with_rng(&root, default_symbol_table(), &mut rng)
1069 .unwrap();
1070
1071 println!("biscuit1 (authority): {}", biscuit1);
1072
1073 let block2 = BlockBuilder::new()
1074 .check_resource_prefix("/folder1/")
1075 .check_right("read")
1076 .unwrap();
1077
1078 let keypair2 = KeyPair::new_with_rng(builder::Algorithm::Ed25519, &mut rng);
1079 let biscuit2 = biscuit1.append_with_keypair(&keypair2, block2).unwrap();
1080
1081 {
1084 let mut authorizer = AuthorizerBuilder::new()
1085 .fact("resource(\"/folder1/file1\")")
1086 .unwrap()
1087 .fact("operation(\"read\")")
1088 .unwrap()
1089 .allow_all()
1090 .build(&biscuit2)
1091 .unwrap();
1092
1093 let res = authorizer.authorize_with_limits(AuthorizerLimits {
1094 max_time: Duration::from_secs(10),
1095 ..Default::default()
1096 });
1097 println!("res1: {:?}", res);
1098 res.unwrap();
1099 }
1100
1101 let _serialized = biscuit2.to_vec().unwrap();
1102 let sealed = biscuit2.seal().unwrap().to_vec().unwrap();
1105 let biscuit3 = Biscuit::from(sealed, root.public()).unwrap();
1108
1109 {
1110 let mut authorizer = AuthorizerBuilder::new()
1111 .fact("resource(\"/folder1/file1\")")
1112 .unwrap()
1113 .fact("operation(\"read\")")
1114 .unwrap()
1115 .allow_all()
1116 .build(&biscuit3)
1117 .unwrap();
1118
1119 let res = authorizer.authorize();
1120 println!("res1: {:?}", res);
1121 res.unwrap();
1122 }
1123 }
1124
1125 #[test]
1126 fn verif_no_blocks() {
1127 use crate::token::builder::*;
1128
1129 let mut rng: StdRng = SeedableRng::seed_from_u64(1234);
1130 let root = KeyPair::new_with_rng(builder::Algorithm::Ed25519, &mut rng);
1131
1132 let biscuit1 = Biscuit::builder()
1133 .fact(fact("right", &[string("file1"), string("read")]))
1134 .unwrap()
1135 .fact(fact("right", &[string("file2"), string("read")]))
1136 .unwrap()
1137 .fact(fact("right", &[string("file1"), string("write")]))
1138 .unwrap()
1139 .build_with_rng(&root, default_symbol_table(), &mut rng)
1140 .unwrap();
1141 println!("{}", biscuit1);
1142
1143 let mut authorizer = AuthorizerBuilder::new()
1144 .check(rule(
1145 "right",
1146 &[string("right")],
1147 &[pred("right", &[string("file2"), string("write")])],
1148 ))
1149 .unwrap()
1150 .build(&biscuit1)
1151 .unwrap();
1152
1153 let res = authorizer.authorize_with_limits(AuthorizerLimits {
1155 max_time: Duration::from_secs(10),
1156 ..Default::default()
1157 });
1158 println!("res: {:?}", res);
1159 assert_eq!(
1160 res,
1161 Err(Token::FailedLogic(Logic::NoMatchingPolicy {
1162 checks: vec![FailedCheck::Authorizer(FailedAuthorizerCheck {
1163 check_id: 0,
1164 rule: String::from("check if right(\"file2\", \"write\")")
1165 }),]
1166 }))
1167 );
1168 }
1169
1170 #[test]
1171 fn authorizer_queries() {
1172 let mut rng: StdRng = SeedableRng::seed_from_u64(0);
1173 let root = KeyPair::new_with_rng(builder::Algorithm::Ed25519, &mut rng);
1174
1175 let biscuit1 = Biscuit::builder()
1176 .right("file1", "read")
1177 .right("file2", "read")
1178 .fact("key(0000)")
1179 .unwrap()
1180 .build_with_rng(&root, default_symbol_table(), &mut rng)
1181 .unwrap();
1182
1183 println!("biscuit1 (authority): {}", biscuit1);
1184
1185 let block2 = BlockBuilder::new()
1186 .check_expiration_date(SystemTime::now() + Duration::from_secs(30))
1187 .fact("key(1234)")
1188 .unwrap();
1189
1190 let keypair2 = KeyPair::new_with_rng(builder::Algorithm::Ed25519, &mut rng);
1191 let biscuit2 = biscuit1.append_with_keypair(&keypair2, block2).unwrap();
1192
1193 let block3 = BlockBuilder::new()
1194 .check_expiration_date(SystemTime::now() + Duration::from_secs(10))
1195 .fact("key(5678)")
1196 .unwrap();
1197
1198 let keypair3 = KeyPair::new_with_rng(builder::Algorithm::Ed25519, &mut rng);
1199 let biscuit3 = biscuit2.append_with_keypair(&keypair3, block3).unwrap();
1200 {
1201 println!("biscuit3: {}", biscuit3);
1202
1203 let mut authorizer = AuthorizerBuilder::new()
1204 .fact("resource(\"file1\")")
1205 .unwrap()
1206 .fact("operation(\"read\")")
1207 .unwrap()
1208 .time()
1209 .build(&biscuit3)
1210 .unwrap();
1211
1212 let mut other_authorizer = authorizer.clone();
1214
1215 let authorization_res = authorizer.authorize_with_limits(AuthorizerLimits {
1216 max_time: Duration::from_secs(10),
1217 ..Default::default()
1218 });
1219 println!("authorization result: {:?}", authorization_res);
1220
1221 println!("world:\n{}", authorizer.print_world());
1222 let res2: Result<Vec<builder::Fact>, crate::error::Token> = authorizer
1223 .query_all_with_limits(
1224 "key_verif($id) <- key($id)",
1225 AuthorizerLimits {
1226 max_time: Duration::from_secs(10),
1227 ..Default::default()
1228 },
1229 );
1230
1231 println!("res2: {:?}", res2);
1232 let mut res2 = res2
1233 .unwrap()
1234 .iter()
1235 .map(|f| f.to_string())
1236 .collect::<Vec<_>>();
1237 res2.sort();
1238 assert_eq!(
1239 res2,
1240 vec![
1241 "key_verif(0)".to_string(),
1242 "key_verif(1234)".to_string(),
1243 "key_verif(5678)".to_string(),
1244 ]
1245 );
1246
1247 let res1: Result<Vec<builder::Fact>, crate::error::Token> =
1248 other_authorizer.query("key_verif($id) <- key($id)");
1249 println!("res1: {:?}", res1);
1250 assert_eq!(
1251 res1.unwrap()
1252 .into_iter()
1253 .map(|f| f.to_string())
1254 .collect::<Vec<_>>(),
1255 vec!["key_verif(0)".to_string()]
1256 );
1257 }
1258 }
1259
1260 #[test]
1261 fn check_head_name() {
1262 let mut rng: StdRng = SeedableRng::seed_from_u64(0);
1263 let root = KeyPair::new_with_rng(builder::Algorithm::Ed25519, &mut rng);
1264
1265 let biscuit1 = Biscuit::builder()
1266 .check(check(
1267 &[pred("resource", &[string("hello")])],
1268 CheckKind::One,
1269 ))
1270 .unwrap()
1271 .build_with_rng(&root, default_symbol_table(), &mut rng)
1272 .unwrap();
1273
1274 println!("biscuit1 (authority): {}", biscuit1);
1275
1276 let block2 = BlockBuilder::new()
1278 .fact(fact("check1", &[string("test")]))
1279 .unwrap();
1280
1281 let keypair2 = KeyPair::new_with_rng(builder::Algorithm::Ed25519, &mut rng);
1282 let biscuit2 = biscuit1.append_with_keypair(&keypair2, block2).unwrap();
1283
1284 println!("biscuit2: {}", biscuit2);
1285
1286 {
1288 let mut authorizer = AuthorizerBuilder::new()
1289 .fact("resource(\"file1\")")
1290 .unwrap()
1291 .fact("operation(\"read\")")
1292 .unwrap()
1293 .time()
1294 .build(&biscuit2)
1295 .unwrap();
1296
1297 println!("world:\n{}", authorizer.print_world());
1298 println!("symbols: {:?}", authorizer.symbols);
1299
1300 let res = authorizer.authorize_with_limits(AuthorizerLimits {
1301 max_time: Duration::from_secs(10),
1302 ..Default::default()
1303 });
1304 println!("res1: {:?}", res);
1305
1306 assert_eq!(
1307 res,
1308 Err(Token::FailedLogic(Logic::NoMatchingPolicy {
1309 checks: vec![FailedCheck::Block(FailedBlockCheck {
1310 block_id: 0,
1311 check_id: 0,
1312 rule: String::from("check if resource(\"hello\")"),
1313 }),]
1314 }))
1315 );
1316 }
1317 }
1318
1319 #[test]
1365 fn bytes_constraints() {
1366 let mut rng: StdRng = SeedableRng::seed_from_u64(0);
1367 let root = KeyPair::new_with_rng(builder::Algorithm::Ed25519, &mut rng);
1368
1369 let biscuit1 = Biscuit::builder()
1370 .fact("bytes(hex:0102AB)")
1371 .unwrap()
1372 .build_with_rng(&root, default_symbol_table(), &mut rng)
1373 .unwrap();
1374
1375 println!("biscuit1 (authority): {}", biscuit1);
1376
1377 let block2 = BlockBuilder::new()
1378 .rule("has_bytes($0) <- bytes($0), { hex:00000000, hex:0102AB }.contains($0)")
1379 .unwrap();
1380 let keypair2 = KeyPair::new_with_rng(builder::Algorithm::Ed25519, &mut rng);
1381 let biscuit2 = biscuit1.append_with_keypair(&keypair2, block2).unwrap();
1382
1383 let mut authorizer = AuthorizerBuilder::new()
1384 .check("check if bytes($0), { hex:00000000, hex:0102AB }.contains($0)")
1385 .unwrap()
1386 .allow_all()
1387 .set_limits(AuthorizerLimits {
1388 max_time: Duration::from_secs(10),
1389 ..Default::default()
1390 })
1391 .build(&biscuit2)
1392 .unwrap();
1393
1394 let res = authorizer.authorize_with_limits(AuthorizerLimits {
1395 max_time: Duration::from_secs(10),
1396 ..Default::default()
1397 });
1398 println!("res1: {:?}", res);
1399 res.unwrap();
1400
1401 let res: Vec<(Vec<u8>,)> = authorizer
1402 .query_with_limits(
1403 "data($0) <- bytes($0)",
1404 AuthorizerLimits {
1405 max_time: Duration::from_secs(10),
1406 ..Default::default()
1407 },
1408 )
1409 .unwrap();
1410 println!("query result: {:x?}", res);
1411 println!("query result: {:?}", res[0]);
1412 }
1413
1414 #[test]
1415 fn block1_generates_authority_or_ambient() {
1416 let mut rng: StdRng = SeedableRng::seed_from_u64(0);
1417 let root = KeyPair::new_with_rng(builder::Algorithm::Ed25519, &mut rng);
1418
1419 let serialized1 = {
1420 let biscuit1 = Biscuit::builder()
1421 .fact("right(\"/folder1/file1\", \"read\")")
1422 .unwrap()
1423 .fact("right(\"/folder1/file1\", \"write\")")
1424 .unwrap()
1425 .fact("right(\"/folder2/file1\", \"read\")")
1426 .unwrap()
1427 .check("check if operation(\"read\")")
1428 .unwrap()
1429 .build_with_rng(&root, default_symbol_table(), &mut rng)
1430 .unwrap();
1431
1432 println!("biscuit1 (authority): {}", biscuit1);
1433
1434 biscuit1.to_vec().unwrap()
1435 };
1436
1437 println!("generated biscuit token: {} bytes", serialized1.len());
1439 let serialized2 = {
1442 let biscuit1_deser = Biscuit::from(&serialized1, |_| Ok(root.public())).unwrap();
1443
1444 let block2 = BlockBuilder::new()
1446
1447 .rule("operation(\"read\") <- operation($any)")
1449 .unwrap()
1450
1451 .rule("resource(\"/folder1/\") <- resource($any)")
1453 .unwrap()
1454
1455 .rule("right($file, $right) <- right($any1, $any2), resource($file), operation($right)")
1457 .unwrap();
1458
1459 let keypair2 = KeyPair::new_with_rng(builder::Algorithm::Ed25519, &mut rng);
1460 let biscuit2 = biscuit1_deser
1461 .append_with_keypair(&keypair2, block2)
1462 .unwrap();
1463
1464 println!("biscuit2 (1 check): {}", biscuit2);
1465
1466 biscuit2.to_vec().unwrap()
1467 };
1468
1469 println!("generated biscuit token 2: {} bytes", serialized2.len());
1471
1472 let final_token = Biscuit::from(&serialized2, root.public()).unwrap();
1473 println!("final token:\n{}", final_token);
1474
1475 let mut authorizer = AuthorizerBuilder::new()
1476 .fact("resource(\"/folder2/file1\")")
1477 .unwrap()
1478 .fact("operation(\"write\")")
1479 .unwrap()
1480 .policy("allow if resource($file), operation($op), right($file, $op)")
1481 .unwrap()
1482 .deny_all()
1483 .build(&final_token)
1484 .unwrap();
1485
1486 let res = authorizer.authorize_with_limits(crate::token::authorizer::AuthorizerLimits {
1487 max_time: Duration::from_secs(1),
1488 ..Default::default()
1489 });
1490 println!("res1: {:?}", res);
1491 println!("authorizer:\n{}", authorizer.print_world());
1492
1493 assert!(res.is_err());
1494 }
1495
1496 #[test]
1497 fn check_all() {
1498 let mut rng: StdRng = SeedableRng::seed_from_u64(0);
1499 let root = KeyPair::new_with_rng(builder::Algorithm::Ed25519, &mut rng);
1500
1501 let biscuit1 = Biscuit::builder()
1502 .check("check if fact($v), $v < 1")
1503 .unwrap()
1504 .build_with_rng(&root, default_symbol_table(), &mut rng)
1505 .unwrap();
1506
1507 println!("biscuit1 (authority): {}", biscuit1);
1508
1509 let biscuit2 = Biscuit::builder()
1510 .check("check all fact($v), $v < 1")
1511 .unwrap()
1512 .build_with_rng(&root, default_symbol_table(), &mut rng)
1513 .unwrap();
1514
1515 println!("biscuit2 (authority): {}", biscuit2);
1516
1517 {
1518 let mut authorizer = AuthorizerBuilder::new()
1519 .fact("fact(0)")
1520 .unwrap()
1521 .fact("fact(1)")
1522 .unwrap()
1523 .allow_all()
1525 .build(&biscuit1)
1526 .unwrap();
1527
1528 let res = authorizer.authorize_with_limits(AuthorizerLimits {
1529 max_time: Duration::from_secs(10),
1530 ..Default::default()
1531 });
1532 println!("res1: {:?}", res);
1533 res.unwrap();
1534 }
1535
1536 {
1537 let mut authorizer = AuthorizerBuilder::new()
1538 .fact("fact(0)")
1539 .unwrap()
1540 .fact("fact(1)")
1541 .unwrap()
1542 .allow_all()
1544 .build(&biscuit2)
1545 .unwrap();
1546
1547 let res = authorizer.authorize_with_limits(AuthorizerLimits {
1548 max_time: Duration::from_secs(10),
1549 ..Default::default()
1550 });
1551 println!("res2: {:?}", res);
1552
1553 assert_eq!(
1554 res,
1555 Err(Token::FailedLogic(Logic::Unauthorized {
1556 policy: MatchedPolicy::Allow(0),
1557 checks: vec![FailedCheck::Block(FailedBlockCheck {
1558 block_id: 0,
1559 check_id: 0,
1560 rule: String::from("check all fact($v), $v < 1"),
1561 }),]
1562 }))
1563 );
1564 }
1565 }
1566
1567 #[test]
1569 fn third_party_unsafe_deserialize() {
1570 let token_bytes = include_bytes!("../../tests/fixtures/unsafe_third_party.bc");
1572 let _ = UnverifiedBiscuit::unsafe_deprecated_deserialize(token_bytes).unwrap();
1573 assert_eq!(
1574 UnverifiedBiscuit::from(token_bytes).unwrap_err(),
1575 error::Token::Format(error::Format::DeserializationError(
1576 "Unsupported third party block version".to_string()
1577 ))
1578 );
1579
1580 let root_key = PublicKey::from_bytes_hex(
1581 "1055c750b1a1505937af1537c626ba3263995c33a64758aaafb1275b0312e284",
1582 builder::Algorithm::Ed25519,
1583 )
1584 .unwrap();
1585 let _ = Biscuit::unsafe_deprecated_deserialize(token_bytes, root_key).unwrap();
1586 assert_eq!(
1587 Biscuit::from(token_bytes, root_key).unwrap_err(),
1588 error::Token::Format(error::Format::DeserializationError(
1589 "Unsupported third party block version".to_string()
1590 ))
1591 );
1592 }
1593
1594 #[test]
1596 fn authority_signature_v1() {
1597 let mut rng: StdRng = SeedableRng::seed_from_u64(0);
1598 let root = KeyPair::new_with_rng(builder::Algorithm::Ed25519, &mut rng);
1599
1600 let authority_block = Block {
1601 symbols: default_symbol_table(),
1602 facts: vec![],
1603 rules: vec![],
1604 checks: vec![],
1605 context: None,
1606 version: 0,
1607 external_key: None,
1608 public_keys: PublicKeys::new(),
1609 scopes: vec![],
1610 };
1611
1612 let next_keypair = KeyPair::new_with_rng(builder::Algorithm::Ed25519, &mut rng);
1613 let token =
1614 SerializedBiscuit::new_inner(None, &root, &next_keypair, &authority_block, 1).unwrap();
1615 let serialized = token.to_vec().unwrap();
1616
1617 let _ = Biscuit::from(&serialized, root.public()).unwrap();
1618 }
1619
1620 #[test]
1621 fn verified_unverified_consistency() {
1622 let mut rng: StdRng = SeedableRng::seed_from_u64(0);
1623 let root = KeyPair::new_with_rng(builder::Algorithm::Ed25519, &mut rng);
1624 let biscuit1 = Biscuit::builder()
1625 .fact("right(\"file1\", \"read\")")
1626 .unwrap()
1627 .fact("right(\"file2\", \"read\")")
1628 .unwrap()
1629 .fact("right(\"file1\", \"write\")")
1630 .unwrap()
1631 .build_with_rng(&root, default_symbol_table(), &mut rng)
1632 .unwrap();
1633
1634 println!("biscuit1 (authority): {}", biscuit1);
1635
1636 let serialized = biscuit1.to_vec().unwrap();
1637
1638 let parsed = UnverifiedBiscuit::from(serialized).unwrap();
1639
1640 for i in 0..parsed.block_count() {
1641 assert_eq!(parsed.print_block_source(i), biscuit1.print_block_source(i));
1642 assert_eq!(parsed.block_version(i), biscuit1.block_version(i));
1643 }
1644 }
1645}