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
29fn verify_raw_biscuit(
30 biscuit: Biscuit,
31 subject: String,
32 resource: String,
33) -> Result<(), TokenError> {
34 let authz = build_base_authorizer(subject, resource)?;
35 if authz.build(&biscuit)?.authorize().is_ok() {
36 Ok(())
37 } else {
38 Err(TokenError::authorization_error(
39 "Token does not grant required access rights",
40 ))
41 }
42}
43
44pub fn verify_biscuit_local(
69 token: Vec<u8>,
70 public_key: PublicKey,
71 subject: String,
72 resource: String,
73) -> Result<(), TokenError> {
74 let biscuit = Biscuit::from(&token, public_key)?;
75 verify_raw_biscuit(biscuit, subject, resource)
76}
77
78pub fn verify_token_local(
103 token: &str,
104 public_key: PublicKey,
105 subject: &str,
106 resource: &str,
107) -> Result<(), TokenError> {
108 let biscuit = Biscuit::from_base64(token, public_key)?;
109 verify_raw_biscuit(biscuit, subject.to_string(), resource.to_string())
110}
111
112pub fn biscuit_key_from_string(key: String) -> Result<PublicKey, TokenError> {
115 println!("Key: {:?}", key);
116 let parts = key.split('/').collect::<Vec<&str>>();
118 if parts.len() != 2 {
119 return Err(TokenError::invalid_key_format(
120 "Key must be in format 'algorithm/hexkey'",
121 ));
122 }
123
124 let alg = match parts[0] {
125 "ed25519" => Algorithm::Ed25519,
126 "secp256r1" => Algorithm::Secp256r1,
127 _ => {
128 return Err(TokenError::invalid_key_format(
129 "Unsupported algorithm, must be ed25519 or secp256r1",
130 ))
131 }
132 };
133
134 let key_bytes = hex::decode(parts[1])?;
136
137 let key = PublicKey::from_bytes(&key_bytes, alg)
139 .map_err(|e| TokenError::invalid_key_format(e.to_string()))?;
140
141 Ok(key)
142}
143
144#[derive(Debug, Deserialize, Clone)]
145pub struct ServiceNode {
146 pub component: String,
147 pub public_key: String,
148}
149
150fn verify_raw_service_chain_biscuit(
151 biscuit: Biscuit,
152 subject: String,
153 resource: String,
154 service_nodes: Vec<ServiceNode>,
155 component: Option<String>,
156) -> Result<(), TokenError> {
157 let mut authz = build_base_authorizer(subject, resource.clone())?;
158
159 let mut component_found = false;
160 if component.is_none() {
161 component_found = true;
162 }
163 for service_node in service_nodes {
164 if let Some(ref component) = component {
165 if component == &service_node.component {
166 component_found = true;
167 break;
168 }
169 }
170 let service = resource.clone();
171 let node_name = service_node.component;
172 let node_key = biscuit_key_from_string(service_node.public_key)?;
173 authz = authz.check(check!(
174 r#"
175 check if node({service}, {node_name}) trusting authority, {node_key};
176 "#
177 ))?;
178 }
179
180 if let Some(ref component) = component {
181 if !component_found {
182 return Err(TokenError::authorization_error(format!(
183 "Token does not grant required access rights. missing {}",
184 component.clone()
185 )));
186 }
187 }
188
189 if authz.build(&biscuit)?.authorize().is_ok() {
190 Ok(())
191 } else {
192 Err(TokenError::authorization_error(
193 "Token does not grant required access rights",
194 ))
195 }
196}
197
198pub fn verify_service_chain_biscuit_local(
199 token: Vec<u8>,
200 public_key: PublicKey,
201 subject: String,
202 resource: String,
203 service_nodes: Vec<ServiceNode>,
204 component: Option<String>,
205) -> Result<(), TokenError> {
206 let biscuit = Biscuit::from(&token, public_key).map_err(TokenError::biscuit_error)?;
207 verify_raw_service_chain_biscuit(biscuit, subject, resource, service_nodes, component)
208}
209
210pub fn verify_service_chain_token_local(
211 token: &str,
212 public_key: PublicKey,
213 subject: &str,
214 resource: &str,
215 service_nodes: Vec<ServiceNode>,
216 component: Option<String>,
217) -> Result<(), TokenError> {
218 let biscuit = Biscuit::from_base64(token, public_key).map_err(TokenError::biscuit_error)?;
219 verify_raw_service_chain_biscuit(
220 biscuit,
221 subject.to_string(),
222 resource.to_string(),
223 service_nodes,
224 component,
225 )
226}