biscuit_auth/token/builder/
authorizer.rs

1/*
2 * Copyright (c) 2019 Geoffroy Couprie <contact@geoffroycouprie.com> and Contributors to the Eclipse Foundation.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5use std::{
6    collections::HashMap,
7    convert::TryInto,
8    fmt::{self, Write},
9    time::{Duration, SystemTime},
10};
11
12use biscuit_parser::parser::parse_source;
13use prost::Message;
14
15use crate::{
16    builder::Convert,
17    builder_ext::{AuthorizerExt, BuilderExt},
18    datalog::{ExternFunc, Origin, RunLimits, SymbolTable, TrustedOrigins, World},
19    error,
20    format::{
21        convert::{
22            policy_to_proto_policy, proto_policy_to_policy, proto_snapshot_block_to_token_block,
23            token_block_to_proto_snapshot_block,
24        },
25        schema,
26    },
27    token::{self, default_symbol_table, Block, MAX_SCHEMA_VERSION, MIN_SCHEMA_VERSION},
28    Authorizer, AuthorizerLimits, Biscuit, PublicKey,
29};
30
31use super::{date, fact, BlockBuilder, Check, Fact, Policy, Rule, Scope, Term};
32
33#[derive(Clone, Debug, Default)]
34pub struct AuthorizerBuilder {
35    authorizer_block_builder: BlockBuilder,
36    policies: Vec<Policy>,
37    extern_funcs: HashMap<String, ExternFunc>,
38    pub(crate) limits: AuthorizerLimits,
39}
40
41impl AuthorizerBuilder {
42    pub fn new() -> AuthorizerBuilder {
43        AuthorizerBuilder::default()
44    }
45
46    /// merge datalog contents (facts, rules, checks) from a `BlockBuilder` into
47    pub fn merge_block(mut self, other: BlockBuilder) -> Self {
48        self.authorizer_block_builder = self.authorizer_block_builder.merge(other);
49        self
50    }
51
52    /// merge datalog contents (facts, rules, checks, policies) from another `AuthorizerBuilder` into `self`, as well as registered extern functions.
53    ///
54    /// If a registered extern function is defined on both sides, the one from `self` is kept.
55    ///
56    /// `AuthorizerLimits` from `self` are kept, those from `other` are discarded
57    pub fn merge(mut self, mut other: AuthorizerBuilder) -> Self {
58        self.policies.append(&mut other.policies);
59        self.extern_funcs.extend(other.extern_funcs);
60        self.authorizer_block_builder = self
61            .authorizer_block_builder
62            .merge(other.authorizer_block_builder);
63        self
64    }
65
66    pub fn fact<F: TryInto<Fact>>(mut self, fact: F) -> Result<Self, error::Token>
67    where
68        error::Token: From<<F as TryInto<Fact>>::Error>,
69    {
70        self.authorizer_block_builder = self.authorizer_block_builder.fact(fact)?;
71        Ok(self)
72    }
73
74    pub fn rule<R: TryInto<Rule>>(mut self, rule: R) -> Result<Self, error::Token>
75    where
76        error::Token: From<<R as TryInto<Rule>>::Error>,
77    {
78        self.authorizer_block_builder = self.authorizer_block_builder.rule(rule)?;
79        Ok(self)
80    }
81
82    pub fn check<C: TryInto<Check>>(mut self, check: C) -> Result<Self, error::Token>
83    where
84        error::Token: From<<C as TryInto<Check>>::Error>,
85    {
86        self.authorizer_block_builder = self.authorizer_block_builder.check(check)?;
87        Ok(self)
88    }
89
90    /// adds some datalog code to the authorizer
91    ///
92    /// ```rust
93    /// extern crate biscuit_auth as biscuit;
94    ///
95    /// use biscuit::builder::AuthorizerBuilder;
96    ///
97    /// let mut authorizer = AuthorizerBuilder::new()
98    ///     .code(r#"
99    ///       resource("/file1.txt");
100    ///
101    ///       check if user(1234);
102    ///
103    ///       // default allow
104    ///       allow if true;
105    ///     "#)
106    ///     .expect("should parse correctly")
107    ///     .build_unauthenticated();
108    /// ```
109    pub fn code<T: AsRef<str>>(self, source: T) -> Result<Self, error::Token> {
110        self.code_with_params(source, HashMap::new(), HashMap::new())
111    }
112
113    /// Add datalog code to the builder, performing parameter subsitution as required
114    /// Unknown parameters are ignored
115    pub fn code_with_params<T: AsRef<str>>(
116        mut self,
117        source: T,
118        params: HashMap<String, Term>,
119        scope_params: HashMap<String, PublicKey>,
120    ) -> Result<Self, error::Token> {
121        let source = source.as_ref();
122
123        let source_result = parse_source(source).map_err(|e| {
124            let e2: biscuit_parser::error::LanguageError = e.into();
125            e2
126        })?;
127
128        for (_, fact) in source_result.facts.into_iter() {
129            let mut fact: Fact = fact.into();
130            for (name, value) in &params {
131                let res = match fact.set(name, value) {
132                    Ok(_) => Ok(()),
133                    Err(error::Token::Language(
134                        biscuit_parser::error::LanguageError::Parameters {
135                            missing_parameters, ..
136                        },
137                    )) if missing_parameters.is_empty() => Ok(()),
138                    Err(e) => Err(e),
139                };
140                res?;
141            }
142            fact.validate()?;
143            self.authorizer_block_builder.facts.push(fact);
144        }
145
146        for (_, rule) in source_result.rules.into_iter() {
147            let mut rule: Rule = rule.into();
148            for (name, value) in &params {
149                let res = match rule.set(name, value) {
150                    Ok(_) => Ok(()),
151                    Err(error::Token::Language(
152                        biscuit_parser::error::LanguageError::Parameters {
153                            missing_parameters, ..
154                        },
155                    )) if missing_parameters.is_empty() => Ok(()),
156                    Err(e) => Err(e),
157                };
158                res?;
159            }
160            for (name, value) in &scope_params {
161                let res = match rule.set_scope(name, *value) {
162                    Ok(_) => Ok(()),
163                    Err(error::Token::Language(
164                        biscuit_parser::error::LanguageError::Parameters {
165                            missing_parameters, ..
166                        },
167                    )) if missing_parameters.is_empty() => Ok(()),
168                    Err(e) => Err(e),
169                };
170                res?;
171            }
172            rule.validate_parameters()?;
173            self.authorizer_block_builder.rules.push(rule);
174        }
175
176        for (_, check) in source_result.checks.into_iter() {
177            let mut check: Check = check.into();
178            for (name, value) in &params {
179                let res = match check.set(name, value) {
180                    Ok(_) => Ok(()),
181                    Err(error::Token::Language(
182                        biscuit_parser::error::LanguageError::Parameters {
183                            missing_parameters, ..
184                        },
185                    )) if missing_parameters.is_empty() => Ok(()),
186                    Err(e) => Err(e),
187                };
188                res?;
189            }
190            for (name, value) in &scope_params {
191                let res = match check.set_scope(name, *value) {
192                    Ok(_) => Ok(()),
193                    Err(error::Token::Language(
194                        biscuit_parser::error::LanguageError::Parameters {
195                            missing_parameters, ..
196                        },
197                    )) if missing_parameters.is_empty() => Ok(()),
198                    Err(e) => Err(e),
199                };
200                res?;
201            }
202            check.validate_parameters()?;
203            self.authorizer_block_builder.checks.push(check);
204        }
205        for (_, policy) in source_result.policies.into_iter() {
206            let mut policy: Policy = policy.into();
207            for (name, value) in &params {
208                let res = match policy.set(name, value) {
209                    Ok(_) => Ok(()),
210                    Err(error::Token::Language(
211                        biscuit_parser::error::LanguageError::Parameters {
212                            missing_parameters, ..
213                        },
214                    )) if missing_parameters.is_empty() => Ok(()),
215                    Err(e) => Err(e),
216                };
217                res?;
218            }
219            for (name, value) in &scope_params {
220                let res = match policy.set_scope(name, *value) {
221                    Ok(_) => Ok(()),
222                    Err(error::Token::Language(
223                        biscuit_parser::error::LanguageError::Parameters {
224                            missing_parameters, ..
225                        },
226                    )) if missing_parameters.is_empty() => Ok(()),
227                    Err(e) => Err(e),
228                };
229                res?;
230            }
231            policy.validate_parameters()?;
232            self.policies.push(policy);
233        }
234
235        Ok(self)
236    }
237
238    pub fn scope(mut self, scope: Scope) -> Self {
239        self.authorizer_block_builder = self.authorizer_block_builder.scope(scope);
240        self
241    }
242
243    /// add a policy to the authorizer
244    pub fn policy<P: TryInto<Policy>>(mut self, policy: P) -> Result<Self, error::Token>
245    where
246        error::Token: From<<P as TryInto<Policy>>::Error>,
247    {
248        let policy = policy.try_into()?;
249        policy.validate_parameters()?;
250        self.policies.push(policy);
251        Ok(self)
252    }
253
254    /// adds a fact with the current time
255    pub fn time(mut self) -> Self {
256        let fact = fact("time", &[date(&SystemTime::now())]);
257        self.authorizer_block_builder = self.authorizer_block_builder.fact(fact).unwrap();
258        self
259    }
260
261    /// Sets the runtime limits of the authorizer
262    ///
263    /// Those limits cover all the executions under the `authorize`, `query` and `query_all` methods
264    pub fn set_limits(mut self, limits: AuthorizerLimits) -> Self {
265        self.limits = limits;
266        self
267    }
268
269    pub fn limits(&self) -> &AuthorizerLimits {
270        &self.limits
271    }
272
273    /// Replaces the registered external functions
274    pub fn set_extern_funcs(mut self, extern_funcs: HashMap<String, ExternFunc>) -> Self {
275        self.extern_funcs = extern_funcs;
276        self
277    }
278
279    /// Registers the provided external functions (possibly replacing already registered functions)
280    pub fn register_extern_funcs(mut self, extern_funcs: HashMap<String, ExternFunc>) -> Self {
281        self.extern_funcs.extend(extern_funcs);
282        self
283    }
284
285    /// Registers the provided external function (possibly replacing an already registered function)
286    pub fn register_extern_func(mut self, name: String, func: ExternFunc) -> Self {
287        self.extern_funcs.insert(name, func);
288        self
289    }
290
291    pub fn dump_code(&self) -> String {
292        let mut f = String::new();
293        for fact in &self.authorizer_block_builder.facts {
294            let _ = writeln!(f, "{fact};");
295        }
296        if !self.authorizer_block_builder.facts.is_empty() {
297            let _ = writeln!(f);
298        }
299
300        for rule in &self.authorizer_block_builder.rules {
301            let _ = writeln!(f, "{rule};");
302        }
303        if !self.authorizer_block_builder.rules.is_empty() {
304            let _ = writeln!(f);
305        }
306
307        for check in &self.authorizer_block_builder.checks {
308            let _ = writeln!(f, "{check};");
309        }
310        if !self.authorizer_block_builder.checks.is_empty() {
311            let _ = writeln!(f);
312        }
313
314        for policy in &self.policies {
315            let _ = writeln!(f, "{policy};");
316        }
317        f
318    }
319
320    /// builds the authorizer from a token
321    pub fn build(self, token: &Biscuit) -> Result<Authorizer, error::Token> {
322        self.build_inner(Some(token))
323    }
324
325    /// builds the authorizer without a token
326    pub fn build_unauthenticated(self) -> Result<Authorizer, error::Token> {
327        self.build_inner(None)
328    }
329
330    fn build_inner(self, token: Option<&Biscuit>) -> Result<Authorizer, error::Token> {
331        let mut world = World::new();
332        world.extern_funcs = self.extern_funcs;
333
334        let mut symbols = SymbolTable::new();
335        let mut public_key_to_block_id: HashMap<usize, Vec<usize>> = HashMap::new();
336        let mut token_origins = TrustedOrigins::default();
337        let mut blocks: Option<Vec<Block>> = None;
338
339        // load the token if present
340        if let Some(token) = token {
341            for (i, block) in token.container.blocks.iter().enumerate() {
342                if let Some(sig) = block.external_signature.as_ref() {
343                    let new_key_id = symbols.public_keys.insert(&sig.public_key);
344
345                    public_key_to_block_id
346                        .entry(new_key_id as usize)
347                        .or_default()
348                        .push(i + 1);
349                }
350            }
351
352            blocks = Some(
353                token
354                    .blocks()
355                    .enumerate()
356                    .map(|(i, block)| {
357                        block.and_then(|mut b| {
358                            load_and_translate_block(
359                                &mut b,
360                                i,
361                                &token.symbols,
362                                &mut symbols,
363                                &mut public_key_to_block_id,
364                                &mut world,
365                            )?;
366                            Ok(b)
367                        })
368                    })
369                    .collect::<Result<Vec<_>, _>>()?,
370            );
371
372            token_origins = TrustedOrigins::from_scopes(
373                &[token::Scope::Previous],
374                &TrustedOrigins::default(),
375                token.block_count(),
376                &public_key_to_block_id,
377            );
378        }
379        let mut authorizer_origin = Origin::default();
380        authorizer_origin.insert(usize::MAX);
381
382        let authorizer_scopes: Vec<token::Scope> = self
383            .authorizer_block_builder
384            .scopes
385            .clone()
386            .iter()
387            .map(|s| s.convert(&mut symbols))
388            .collect();
389
390        let authorizer_trusted_origins = TrustedOrigins::from_scopes(
391            &authorizer_scopes,
392            &TrustedOrigins::default(),
393            usize::MAX,
394            &public_key_to_block_id,
395        );
396        for fact in &self.authorizer_block_builder.facts {
397            world
398                .facts
399                .insert(&authorizer_origin, fact.convert(&mut symbols));
400        }
401
402        for rule in &self.authorizer_block_builder.rules {
403            let rule = rule.convert(&mut symbols);
404
405            let rule_trusted_origins = TrustedOrigins::from_scopes(
406                &rule.scopes,
407                &authorizer_trusted_origins,
408                usize::MAX,
409                &public_key_to_block_id,
410            );
411
412            world.rules.insert(usize::MAX, &rule_trusted_origins, rule);
413        }
414
415        /*
416        let start = Instant::now();
417        world.run_with_limits(&symbols, self.limits.clone())?;
418        let execution_time = start.elapsed();
419        */
420
421        Ok(Authorizer {
422            authorizer_block_builder: self.authorizer_block_builder,
423            world,
424            symbols,
425            token_origins,
426            policies: self.policies,
427            blocks,
428            public_key_to_block_id,
429            limits: self.limits,
430            execution_time: None,
431        })
432    }
433}
434
435impl fmt::Display for AuthorizerBuilder {
436    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
437        self.authorizer_block_builder.fmt(f)?;
438        for mut policy in self.policies.clone().into_iter() {
439            policy.apply_parameters();
440            writeln!(f, "{policy};")?;
441        }
442
443        Ok(())
444    }
445}
446
447/// we need to modify the block loaded from the token, because the authorizer's and the token's symbol table can differ
448pub(crate) fn load_and_translate_block(
449    block: &mut Block,
450    i: usize,
451    token_symbols: &SymbolTable,
452    authorizer_symbols: &mut SymbolTable,
453    public_key_to_block_id: &mut HashMap<usize, Vec<usize>>,
454    world: &mut World,
455) -> Result<(), error::Token> {
456    // if it is a 3rd party block, it should not affect the main symbol table
457    let block_symbols = if i == 0 || block.external_key.is_none() {
458        token_symbols.clone()
459    } else {
460        block.symbols.clone()
461    };
462
463    let mut block_origin = Origin::default();
464    block_origin.insert(i);
465
466    for scope in block.scopes.iter_mut() {
467        *scope = crate::token::builder::Scope::convert_from(scope, &block_symbols)
468            .map(|s| s.convert(authorizer_symbols))?;
469    }
470
471    let block_trusted_origins = TrustedOrigins::from_scopes(
472        &block.scopes,
473        &TrustedOrigins::default(),
474        i,
475        public_key_to_block_id,
476    );
477
478    for fact in block.facts.iter_mut() {
479        *fact = Fact::convert_from(fact, &block_symbols)?.convert(authorizer_symbols);
480        world.facts.insert(&block_origin, fact.clone());
481    }
482
483    for rule in block.rules.iter_mut() {
484        if let Err(_message) = rule.validate_variables(&block_symbols) {
485            return Err(error::Logic::InvalidBlockRule(0, block_symbols.print_rule(rule)).into());
486        }
487        *rule = rule.translate(&block_symbols, authorizer_symbols)?;
488
489        let rule_trusted_origins = TrustedOrigins::from_scopes(
490            &rule.scopes,
491            &block_trusted_origins,
492            i,
493            public_key_to_block_id,
494        );
495
496        world.rules.insert(i, &rule_trusted_origins, rule.clone());
497    }
498
499    for check in block.checks.iter_mut() {
500        let c = Check::convert_from(check, &block_symbols)?;
501        *check = c.convert(authorizer_symbols);
502    }
503
504    Ok(())
505}
506
507impl BuilderExt for AuthorizerBuilder {
508    fn resource(mut self, name: &str) -> Self {
509        self.authorizer_block_builder = self.authorizer_block_builder.resource(name);
510        self
511    }
512    fn check_resource(mut self, name: &str) -> Self {
513        self.authorizer_block_builder = self.authorizer_block_builder.check_resource(name);
514        self
515    }
516    fn operation(mut self, name: &str) -> Self {
517        self.authorizer_block_builder = self.authorizer_block_builder.operation(name);
518        self
519    }
520    fn check_operation(mut self, name: &str) -> Self {
521        self.authorizer_block_builder = self.authorizer_block_builder.check_operation(name);
522        self
523    }
524    fn check_resource_prefix(mut self, prefix: &str) -> Self {
525        self.authorizer_block_builder = self.authorizer_block_builder.check_resource_prefix(prefix);
526        self
527    }
528
529    fn check_resource_suffix(mut self, suffix: &str) -> Self {
530        self.authorizer_block_builder = self.authorizer_block_builder.check_resource_suffix(suffix);
531        self
532    }
533
534    fn check_expiration_date(mut self, exp: SystemTime) -> Self {
535        self.authorizer_block_builder = self.authorizer_block_builder.check_expiration_date(exp);
536        self
537    }
538}
539
540impl AuthorizerExt for AuthorizerBuilder {
541    fn allow_all(self) -> Self {
542        self.policy("allow if true").unwrap()
543    }
544    fn deny_all(self) -> Self {
545        self.policy("deny if true").unwrap()
546    }
547}
548
549impl AuthorizerBuilder {
550    pub fn from_snapshot(input: schema::AuthorizerSnapshot) -> Result<Self, error::Token> {
551        let schema::AuthorizerSnapshot {
552            limits,
553            execution_time,
554            world,
555        } = input;
556
557        let limits = RunLimits {
558            max_facts: limits.max_facts,
559            max_iterations: limits.max_iterations,
560            max_time: Duration::from_nanos(limits.max_time),
561        };
562
563        let version = world.version.unwrap_or(0);
564        if !(MIN_SCHEMA_VERSION..=MAX_SCHEMA_VERSION).contains(&version) {
565            return Err(error::Format::Version {
566                minimum: crate::token::MIN_SCHEMA_VERSION,
567                maximum: crate::token::MAX_SCHEMA_VERSION,
568                actual: version,
569            }
570            .into());
571        }
572
573        if !world.blocks.is_empty() {
574            return Err(error::Format::DeserializationError(
575                "cannot deserialize an AuthorizerBuilder fro a snapshot with blocks".to_string(),
576            )
577            .into());
578        }
579
580        if !world.generated_facts.is_empty() {
581            return Err(error::Format::DeserializationError(
582                "cannot deserialize an AuthorizerBuilder from a snapshot with generated facts"
583                    .to_string(),
584            )
585            .into());
586        }
587
588        if world.iterations != 0 {
589            return Err(error::Format::DeserializationError(
590                "cannot deserialize an AuthorizerBuilder from a snapshot with non-zero iterations"
591                    .to_string(),
592            )
593            .into());
594        }
595
596        if execution_time != 0 {
597            return Err(error::Format::DeserializationError(
598                "cannot deserialize an AuthorizerBuilder from a snapshot with non-zero execution time".to_string(),
599            )
600            .into());
601        }
602
603        let mut symbols = default_symbol_table();
604        for symbol in world.symbols {
605            symbols.insert(&symbol);
606        }
607        for public_key in world.public_keys {
608            symbols
609                .public_keys
610                .insert(&PublicKey::from_proto(&public_key)?);
611        }
612
613        let authorizer_block = proto_snapshot_block_to_token_block(&world.authorizer_block)?;
614
615        let authorizer_block_builder = BlockBuilder::convert_from(&authorizer_block, &symbols)?;
616        let policies = world
617            .authorizer_policies
618            .iter()
619            .map(|policy| proto_policy_to_policy(policy, &symbols, version))
620            .collect::<Result<Vec<Policy>, error::Format>>()?;
621
622        let mut authorizer = AuthorizerBuilder::new();
623        authorizer.authorizer_block_builder = authorizer_block_builder;
624        authorizer.policies = policies;
625        authorizer.limits = limits;
626
627        Ok(authorizer)
628    }
629
630    pub fn from_raw_snapshot(input: &[u8]) -> Result<Self, error::Token> {
631        let snapshot = schema::AuthorizerSnapshot::decode(input).map_err(|e| {
632            error::Format::DeserializationError(format!("deserialization error: {:?}", e))
633        })?;
634        Self::from_snapshot(snapshot)
635    }
636
637    pub fn from_base64_snapshot(input: &str) -> Result<Self, error::Token> {
638        let bytes = base64::decode_config(input, base64::URL_SAFE)?;
639        Self::from_raw_snapshot(&bytes)
640    }
641
642    pub fn snapshot(&self) -> Result<schema::AuthorizerSnapshot, error::Format> {
643        let mut symbols = default_symbol_table();
644
645        let authorizer_policies = self
646            .policies
647            .iter()
648            .map(|policy| policy_to_proto_policy(policy, &mut symbols))
649            .collect();
650
651        let authorizer_block = self.authorizer_block_builder.clone().build(symbols.clone());
652        symbols.extend(&authorizer_block.symbols)?;
653        symbols.public_keys.extend(&authorizer_block.public_keys)?;
654
655        let authorizer_block = token_block_to_proto_snapshot_block(&authorizer_block);
656
657        let blocks = vec![];
658
659        let generated_facts = vec![];
660
661        let world = schema::AuthorizerWorld {
662            version: Some(MAX_SCHEMA_VERSION),
663            symbols: symbols.strings(),
664            public_keys: symbols
665                .public_keys
666                .into_inner()
667                .into_iter()
668                .map(|key| key.to_proto())
669                .collect(),
670            blocks,
671            authorizer_block,
672            authorizer_policies,
673            generated_facts,
674            iterations: 0,
675        };
676
677        Ok(schema::AuthorizerSnapshot {
678            world,
679            execution_time: 0u64,
680            limits: schema::RunLimits {
681                max_facts: self.limits.max_facts,
682                max_iterations: self.limits.max_iterations,
683                max_time: self.limits.max_time.as_nanos() as u64,
684            },
685        })
686    }
687
688    pub fn to_raw_snapshot(&self) -> Result<Vec<u8>, error::Format> {
689        let snapshot = self.snapshot()?;
690        let mut bytes = Vec::new();
691        snapshot.encode(&mut bytes).map_err(|e| {
692            error::Format::SerializationError(format!("serialization error: {:?}", e))
693        })?;
694        Ok(bytes)
695    }
696
697    pub fn to_base64_snapshot(&self) -> Result<String, error::Format> {
698        let snapshot_bytes = self.to_raw_snapshot()?;
699        Ok(base64::encode_config(snapshot_bytes, base64::URL_SAFE))
700    }
701}