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