1use 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
31pub const MIN_SCHEMA_VERSION: u32 = 3;
33pub const MAX_SCHEMA_VERSION: u32 = 5;
35
36pub fn default_symbol_table() -> SymbolTable {
39 SymbolTable::new()
40}
41
42#[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 pub fn builder() -> BiscuitBuilder {
87 BiscuitBuilder::new()
88 }
89
90 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 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 pub fn to_vec(&self) -> Result<Vec<u8>, error::Token> {
110 self.container.to_vec().map_err(error::Token::Format)
111 }
112
113 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 pub fn serialized_size(&self) -> Result<usize, error::Token> {
123 Ok(self.container.serialized_size())
124 }
125
126 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 pub fn authorizer(&self) -> Result<Authorizer, error::Token> {
140 Authorizer::from_token(self)
141 }
142
143 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 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 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 pub fn root_key_id(&self) -> Option<u32> {
175 self.root_key_id
176 }
177
178 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 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 pub fn print(&self) -> String {
209 format!("{}", &self)
210 }
211
212 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 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 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 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 pub fn container(&self) -> &SerializedBiscuit {
311 &self.container
312 }
313
314 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 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 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 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 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 PublicKey(u64),
613}
614
615pub 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", serialized1.len());
695 let serialized2 = {
727 let biscuit1_deser = Biscuit::from(&serialized1, root.public()).unwrap();
728
729 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", serialized2.len());
756
757 let serialized3 = {
758 let biscuit2_deser = Biscuit::from(&serialized2, root.public()).unwrap();
759
760 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", serialized3.len());
781 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 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 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 {
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 let sealed = biscuit2.seal().unwrap().to_vec().unwrap();
1024 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 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 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 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 {
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 #[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", serialized1.len());
1358 let serialized2 = {
1361 let biscuit1_deser = Biscuit::from(&serialized1, |_| Ok(root.public())).unwrap();
1362
1363 let mut block2 = BlockBuilder::new();
1365
1366 block2
1368 .add_rule("operation(\"read\") <- operation($any)")
1369 .unwrap();
1370
1371 block2
1373 .add_rule("resource(\"/folder1/\") <- resource($any)")
1374 .unwrap();
1375
1376 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", 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 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 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}