1extern crate biscuit_auth as biscuit;
2
3use biscuit::macros::{authorizer, check};
4use biscuit::{Algorithm, Biscuit, PublicKey};
5use chrono::Utc;
6use serde::Deserialize;
7
8use crate::error::TokenError;
9
10fn build_base_authorizer(
11 subject: String,
12 resource: String,
13) -> Result<biscuit::AuthorizerBuilder, TokenError> {
14 let now = Utc::now().timestamp();
15
16 let authz = authorizer!(
17 r#"
18 time({now});
19 resource({resource});
20 subject({subject});
21 operation("read");
22 operation("write");
23 allow if subject($sub), resource($res), operation($op), right($sub, $res, $op);
24 "#
25 );
26 Ok(authz)
27}
28
29pub fn verify_biscuit_local(
54 token: Vec<u8>,
55 public_key: PublicKey,
56 subject: String,
57 resource: String,
58) -> Result<(), TokenError> {
59 let biscuit = Biscuit::from(&token, public_key)?;
60
61 let authz = build_base_authorizer(subject, resource)?;
62 if authz.build(&biscuit)?.authorize().is_ok() {
63 Ok(())
64 } else {
65 Err(TokenError::authorization_error(
66 "Token does not grant required access rights",
67 ))
68 }
69}
70
71pub fn biscuit_key_from_string(key: String) -> Result<PublicKey, TokenError> {
74 println!("Key: {:?}", key);
75 let parts = key.split('/').collect::<Vec<&str>>();
77 if parts.len() != 2 {
78 return Err(TokenError::invalid_key_format(
79 "Key must be in format 'algorithm/hexkey'",
80 ));
81 }
82
83 let alg = match parts[0] {
84 "ed25519" => Algorithm::Ed25519,
85 "secp256r1" => Algorithm::Secp256r1,
86 _ => {
87 return Err(TokenError::invalid_key_format(
88 "Unsupported algorithm, must be ed25519 or secp256r1",
89 ))
90 }
91 };
92
93 let key_bytes = hex::decode(parts[1])?;
95
96 let key = PublicKey::from_bytes(&key_bytes, alg)
98 .map_err(|e| TokenError::invalid_key_format(e.to_string()))?;
99
100 Ok(key)
101}
102
103#[derive(Debug, Deserialize, Clone)]
104pub struct ServiceNode {
105 pub component: String,
106 pub public_key: String,
107}
108
109pub fn verify_service_chain_biscuit_local(
110 token: Vec<u8>,
111 public_key: PublicKey,
112 subject: String,
113 resource: String,
114 service_nodes: Vec<ServiceNode>,
115 component: Option<String>,
116) -> Result<(), TokenError> {
117 let biscuit = Biscuit::from(&token, public_key).map_err(TokenError::biscuit_error)?;
118
119 let mut authz = build_base_authorizer(subject, resource.clone())?;
120
121 for service_node in service_nodes {
122 if let Some(ref component) = component {
123 if component == &service_node.component {
124 break;
125 }
126 }
127 let service = resource.clone();
128 let node_name = service_node.component;
129 let node_key = biscuit_key_from_string(service_node.public_key)?;
130 authz = authz.check(check!(
131 r#"
132 check if node({service}, {node_name}) trusting authority, {node_key};
133 "#
134 ))?;
135 }
136
137 if authz.build(&biscuit)?.authorize().is_ok() {
138 Ok(())
139 } else {
140 Err(TokenError::authorization_error(
141 "Token does not grant required access rights",
142 ))
143 }
144}