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