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