1extern crate biscuit_auth as biscuit;
2
3use crate::verify::{biscuit_key_from_string, ServiceNode};
4
5use biscuit::macros::{biscuit, check, rule};
6use biscuit::BiscuitBuilder;
7use chrono::Utc;
8use hessra_token_core::{Biscuit, KeyPair, TokenTimeConfig};
9use std::error::Error;
10use tracing::info;
11
12pub struct HessraAuthorization {
77 token_type: TokenType,
78 subject: Option<String>,
80 resource: Option<String>,
81 operation: Option<String>,
82 latent_rights: Option<Vec<(String, String)>>,
84 activator_public_key: Option<String>,
85 time_config: TokenTimeConfig,
87 service_chain_nodes: Option<Vec<ServiceNode>>,
88 multi_party_nodes: Option<Vec<ServiceNode>>,
89 domain: Option<String>,
90}
91
92#[derive(Debug, Clone, PartialEq)]
94enum TokenType {
95 Singleton,
96 Latent,
97}
98
99impl HessraAuthorization {
100 pub fn new(
111 subject: String,
112 resource: String,
113 operation: String,
114 time_config: TokenTimeConfig,
115 ) -> Self {
116 Self {
117 token_type: TokenType::Singleton,
118 subject: Some(subject),
119 resource: Some(resource),
120 operation: Some(operation),
121 latent_rights: None,
122 activator_public_key: None,
123 time_config,
124 service_chain_nodes: None,
125 multi_party_nodes: None,
126 domain: None,
127 }
128 }
129
130 pub fn new_latent(
168 latent_rights: Vec<(String, String)>,
169 activator_public_key: String,
170 time_config: TokenTimeConfig,
171 ) -> Self {
172 Self {
173 token_type: TokenType::Latent,
174 subject: None,
175 resource: None,
176 operation: None,
177 latent_rights: Some(latent_rights),
178 activator_public_key: Some(activator_public_key),
179 time_config,
180 service_chain_nodes: None,
181 multi_party_nodes: None,
182 domain: None,
183 }
184 }
185
186 pub fn service_chain(mut self, nodes: Vec<ServiceNode>) -> Self {
197 self.service_chain_nodes = Some(nodes);
198 self
199 }
200
201 pub fn multi_party(mut self, nodes: Vec<ServiceNode>) -> Self {
213 self.multi_party_nodes = Some(nodes);
214 self
215 }
216
217 pub fn domain_restricted(mut self, domain: String) -> Self {
227 self.domain = Some(domain);
228 self
229 }
230
231 pub fn issue(self, keypair: &KeyPair) -> Result<String, Box<dyn Error>> {
242 let start_time = self
243 .time_config
244 .start_time
245 .unwrap_or_else(|| Utc::now().timestamp());
246 let expiration = start_time + self.time_config.duration;
247
248 let domain = self.domain;
249
250 let mut biscuit_builder = match self.token_type {
252 TokenType::Singleton => {
253 let subject = self.subject.ok_or("Singleton token requires subject")?;
255 let resource = self.resource.ok_or("Singleton token requires resource")?;
256 let operation = self.operation.ok_or("Singleton token requires operation")?;
257
258 biscuit!(
260 r#"
261 right({subject}, {resource}, {operation});
262 check if subject($sub), resource($res), operation($op), right($sub, $res, $op);
263 check if time($time), $time < {expiration};
264 "#
265 )
266 }
267 TokenType::Latent => {
268 let latent_rights = self
270 .latent_rights
271 .ok_or("Latent token requires latent_rights")?;
272 let activator_public_key_str = self
273 .activator_public_key
274 .ok_or("Latent token requires activator_public_key")?;
275 let activator_public_key = biscuit_key_from_string(activator_public_key_str)?;
276
277 let mut builder = BiscuitBuilder::new();
279
280 for (resource, operation) in latent_rights.clone() {
282 builder = builder.fact(biscuit::macros::fact!(
283 r#"latent_right({resource}, {operation})"#
284 ))?;
285 }
286
287 builder = builder.rule(rule!(
289 r#"
290 right($subject, $resource, $operation) <-
291 delegate($subject),
292 right($resource, $operation),
293 latent_right($resource, $operation)
294 trusting {activator_public_key};
295 "#
296 ))?;
297
298 builder = builder.check(check!(
300 r#"
301 check if subject($sub), resource($res), operation($op),
302 right($sub, $res, $op)
303 trusting {activator_public_key};
304 "#
305 ))?;
306
307 builder = builder.check(check!(
309 r#"
310 check if resource($res), operation($op), latent_right($res, $op);
311 "#
312 ))?;
313
314 builder = builder.check(check!(
316 r#"
317 check if time($time), $time < {expiration};
318 "#
319 ))?;
320
321 builder
322 }
323 };
324
325 if let Some(domain) = domain {
327 biscuit_builder = biscuit_builder.check(check!(
328 r#"
329 check if domain({domain});
330 "#
331 ))?;
332 }
333
334 if let Some(nodes) = self.service_chain_nodes {
336 for node in nodes {
337 let component = node.component;
338 let public_key = biscuit_key_from_string(node.public_key)?;
339 biscuit_builder = biscuit_builder.rule(rule!(
340 r#"
341 node($s, {component}) <- service($s) trusting {public_key};
342 "#
343 ))?;
344 }
345 }
346
347 if let Some(nodes) = self.multi_party_nodes {
349 for node in nodes {
350 let component = node.component;
351 let public_key = biscuit_key_from_string(node.public_key)?;
352 biscuit_builder = biscuit_builder.check(check!(
353 r#"
354 check if namespace({component}) trusting {public_key};
355 "#
356 ))?;
357 }
358 }
359
360 let biscuit = biscuit_builder.build(keypair)?;
362 info!("biscuit (authority): {}", biscuit);
363 let token = biscuit.to_base64()?;
364 Ok(token)
365 }
366}
367
368fn _create_base_biscuit_builder(
384 subject: String,
385 resource: String,
386 operation: String,
387) -> Result<BiscuitBuilder, Box<dyn Error>> {
388 create_base_biscuit_builder_with_time(subject, resource, operation, TokenTimeConfig::default())
389}
390
391fn create_base_biscuit_builder_with_time(
408 subject: String,
409 resource: String,
410 operation: String,
411 time_config: TokenTimeConfig,
412) -> Result<BiscuitBuilder, Box<dyn Error>> {
413 let start_time = time_config
414 .start_time
415 .unwrap_or_else(|| Utc::now().timestamp());
416 let expiration = start_time + time_config.duration;
417
418 let biscuit_builder = biscuit!(
419 r#"
420 right({subject}, {resource}, {operation});
421 check if subject($sub), resource($res), operation($op), right($sub, $res, $op);
422 check if time($time), $time < {expiration};
423 "#
424 );
425
426 Ok(biscuit_builder)
427}
428
429pub fn create_raw_biscuit(
449 subject: String,
450 resource: String,
451 operation: String,
452 key: KeyPair,
453 time_config: TokenTimeConfig,
454) -> Result<Biscuit, Box<dyn Error>> {
455 let biscuit = create_base_biscuit_builder_with_time(subject, resource, operation, time_config)?
456 .build(&key)?;
457
458 info!("biscuit (authority): {}", biscuit);
459
460 Ok(biscuit)
461}
462
463pub fn create_biscuit(
481 subject: String,
482 resource: String,
483 operation: String,
484 key: KeyPair,
485 time_config: TokenTimeConfig,
486) -> Result<Vec<u8>, Box<dyn Error>> {
487 let biscuit = create_raw_biscuit(subject, resource, operation, key, time_config)?;
488 let token = biscuit.to_vec()?;
489 Ok(token)
490}
491
492fn create_base64_biscuit(
510 subject: String,
511 resource: String,
512 operation: String,
513 key: KeyPair,
514 time_config: TokenTimeConfig,
515) -> Result<String, Box<dyn Error>> {
516 let biscuit = create_raw_biscuit(subject, resource, operation, key, time_config)?;
517 let token = biscuit.to_base64()?;
518 Ok(token)
519}
520
521pub fn create_token(
539 subject: String,
540 resource: String,
541 operation: String,
542 key: KeyPair,
543) -> Result<String, Box<dyn Error>> {
544 create_base64_biscuit(
545 subject,
546 resource,
547 operation,
548 key,
549 TokenTimeConfig::default(),
550 )
551}
552
553pub fn create_token_with_time(
571 subject: String,
572 resource: String,
573 operation: String,
574 key: KeyPair,
575 time_config: TokenTimeConfig,
576) -> Result<String, Box<dyn Error>> {
577 create_base64_biscuit(subject, resource, operation, key, time_config)
578}
579
580pub fn create_service_chain_biscuit(
599 subject: String,
600 resource: String,
601 operation: String,
602 key: KeyPair,
603 nodes: &Vec<ServiceNode>,
604 time_config: TokenTimeConfig,
605) -> Result<Vec<u8>, Box<dyn Error>> {
606 let biscuit =
607 create_raw_service_chain_biscuit(subject, resource, operation, key, nodes, time_config)?;
608 let token = biscuit.to_vec()?;
609 Ok(token)
610}
611
612fn create_base64_service_chain_biscuit(
631 subject: String,
632 resource: String,
633 operation: String,
634 key: KeyPair,
635 nodes: &Vec<ServiceNode>,
636 time_config: TokenTimeConfig,
637) -> Result<String, Box<dyn Error>> {
638 let biscuit =
639 create_raw_service_chain_biscuit(subject, resource, operation, key, nodes, time_config)?;
640 let token = biscuit.to_base64()?;
641 Ok(token)
642}
643
644pub fn create_raw_service_chain_biscuit(
664 subject: String,
665 resource: String,
666 operation: String,
667 key: KeyPair,
668 nodes: &Vec<ServiceNode>,
669 time_config: TokenTimeConfig,
670) -> Result<Biscuit, Box<dyn Error>> {
671 create_service_chain_biscuit_with_time(subject, resource, operation, key, nodes, time_config)
672}
673
674pub fn create_service_chain_token(
694 subject: String,
695 resource: String,
696 operation: String,
697 key: KeyPair,
698 nodes: &Vec<ServiceNode>,
699) -> Result<String, Box<dyn Error>> {
700 create_base64_service_chain_biscuit(
701 subject,
702 resource,
703 operation,
704 key,
705 nodes,
706 TokenTimeConfig::default(),
707 )
708}
709
710pub fn create_service_chain_biscuit_with_time(
729 subject: String,
730 resource: String,
731 operation: String,
732 key: KeyPair,
733 nodes: &Vec<ServiceNode>,
734 time_config: TokenTimeConfig,
735) -> Result<Biscuit, Box<dyn Error>> {
736 let service = resource.clone();
737 let mut biscuit_builder =
738 create_base_biscuit_builder_with_time(subject, service, operation, time_config)?;
739
740 for node in nodes {
742 let component = node.component.clone();
743 let public_key = biscuit_key_from_string(node.public_key.clone())?;
744 biscuit_builder = biscuit_builder.rule(rule!(
745 r#"
746 node($s, {component}) <- service($s) trusting {public_key};
747 "#
748 ))?;
749 }
750
751 let biscuit = biscuit_builder.build(&key)?;
752
753 info!("biscuit (authority): {}", biscuit);
754
755 Ok(biscuit)
756}
757
758pub fn create_service_chain_token_with_time(
778 subject: String,
779 resource: String,
780 operation: String,
781 key: KeyPair,
782 nodes: &Vec<ServiceNode>,
783 time_config: TokenTimeConfig,
784) -> Result<String, Box<dyn Error>> {
785 let biscuit = create_service_chain_biscuit_with_time(
786 subject,
787 resource,
788 operation,
789 key,
790 nodes,
791 time_config,
792 )?;
793 let token = biscuit.to_base64()?;
794 Ok(token)
795}
796
797pub fn create_raw_multi_party_biscuit(
813 subject: String,
814 resource: String,
815 operation: String,
816 key: KeyPair,
817 multi_party_nodes: &Vec<ServiceNode>,
818) -> Result<Biscuit, Box<dyn Error>> {
819 create_multi_party_biscuit_with_time(
820 subject,
821 resource,
822 operation,
823 key,
824 multi_party_nodes,
825 TokenTimeConfig::default(),
826 )
827}
828
829pub fn create_multi_party_biscuit(
850 subject: String,
851 resource: String,
852 operation: String,
853 key: KeyPair,
854 multi_party_nodes: &Vec<ServiceNode>,
855) -> Result<Vec<u8>, Box<dyn Error>> {
856 let biscuit =
857 create_raw_multi_party_biscuit(subject, resource, operation, key, multi_party_nodes)?;
858 let token = biscuit.to_vec()?;
859 Ok(token)
860}
861
862fn create_base64_multi_party_biscuit(
883 subject: String,
884 resource: String,
885 operation: String,
886 key: KeyPair,
887 multi_party_nodes: &Vec<ServiceNode>,
888 time_config: TokenTimeConfig,
889) -> Result<String, Box<dyn Error>> {
890 let biscuit = create_multi_party_biscuit_with_time(
891 subject,
892 resource,
893 operation,
894 key,
895 multi_party_nodes,
896 time_config,
897 )?;
898 let token = biscuit.to_base64()?;
899 Ok(token)
900}
901
902pub fn create_multi_party_token(
923 subject: String,
924 resource: String,
925 operation: String,
926 key: KeyPair,
927 multi_party_nodes: &Vec<ServiceNode>,
928) -> Result<String, Box<dyn Error>> {
929 create_base64_multi_party_biscuit(
930 subject,
931 resource,
932 operation,
933 key,
934 multi_party_nodes,
935 TokenTimeConfig::default(),
936 )
937}
938
939pub fn create_multi_party_biscuit_with_time(
961 subject: String,
962 resource: String,
963 operation: String,
964 key: KeyPair,
965 multi_party_nodes: &Vec<ServiceNode>,
966 time_config: TokenTimeConfig,
967) -> Result<Biscuit, Box<dyn Error>> {
968 let mut biscuit_builder =
969 create_base_biscuit_builder_with_time(subject, resource, operation, time_config)?;
970
971 for node in multi_party_nodes {
972 let component = node.component.clone();
973 let public_key = biscuit_key_from_string(node.public_key.clone())?;
974 biscuit_builder = biscuit_builder.check(check!(
975 r#"
976 check if namespace({component}) trusting {public_key};
977 "#
978 ))?;
979 }
980
981 let biscuit = biscuit_builder.build(&key)?;
982
983 info!("biscuit (authority): {}", biscuit);
984
985 Ok(biscuit)
986}
987
988pub fn create_multi_party_token_with_time(
989 subject: String,
990 resource: String,
991 operation: String,
992 key: KeyPair,
993 multi_party_nodes: &Vec<ServiceNode>,
994 time_config: TokenTimeConfig,
995) -> Result<String, Box<dyn Error>> {
996 let biscuit = create_multi_party_biscuit_with_time(
997 subject,
998 resource,
999 operation,
1000 key,
1001 multi_party_nodes,
1002 time_config,
1003 )?;
1004 let token = biscuit.to_base64()?;
1005 Ok(token)
1006}
1007
1008#[cfg(test)]
1009mod tests {
1010 use super::*;
1011 use crate::attenuate::{activate_latent_token, activate_latent_token_from_string};
1012 use crate::verify::{verify_biscuit_local, verify_service_chain_biscuit_local};
1013 use biscuit::macros::block;
1014 use biscuit::Biscuit;
1015 #[test]
1016 fn test_create_biscuit() {
1017 let subject = "test@test.com".to_owned();
1018 let resource: String = "res1".to_string();
1019 let operation = "read".to_string();
1020 let root = KeyPair::new();
1021 let public_key = root.public();
1022 let token = create_biscuit(
1023 subject.clone(),
1024 resource.clone(),
1025 operation.clone(),
1026 root,
1027 TokenTimeConfig::default(),
1028 )
1029 .unwrap();
1030
1031 let res = verify_biscuit_local(token, public_key, subject, resource, operation);
1032 assert!(res.is_ok());
1033 }
1034
1035 #[test]
1036 fn test_biscuit_operations() {
1037 let subject = "test@test.com".to_owned();
1038 let resource = "res1".to_string();
1039 let operation = "read".to_string();
1040 let root = KeyPair::new();
1041 let public_key = root.public();
1042
1043 let read_token = create_biscuit(
1045 subject.clone(),
1046 resource.clone(),
1047 operation.clone(),
1048 root,
1049 TokenTimeConfig::default(),
1050 )
1051 .unwrap();
1052
1053 let res = verify_biscuit_local(
1054 read_token.clone(),
1055 public_key,
1056 subject.clone(),
1057 resource.clone(),
1058 operation.clone(),
1059 );
1060 assert!(res.is_ok());
1061
1062 let root = KeyPair::new();
1063 let public_key = root.public();
1064
1065 let write_token = create_biscuit(
1067 subject.clone(),
1068 resource.clone(),
1069 "write".to_string(),
1070 root,
1071 TokenTimeConfig::default(),
1072 )
1073 .unwrap();
1074
1075 let res = verify_biscuit_local(
1076 write_token.clone(),
1077 public_key,
1078 subject.clone(),
1079 resource.clone(),
1080 "write".to_string(),
1081 );
1082 assert!(res.is_ok());
1083
1084 let res = verify_biscuit_local(
1086 read_token,
1087 public_key,
1088 subject.clone(),
1089 resource.clone(),
1090 "write".to_string(),
1091 );
1092 assert!(res.is_err());
1093
1094 let res = verify_biscuit_local(
1096 write_token,
1097 public_key,
1098 subject.clone(),
1099 resource.clone(),
1100 "read".to_string(),
1101 );
1102 assert!(res.is_err());
1103 }
1104
1105 #[test]
1106 fn test_biscuit_expiration() {
1107 let subject = "test@test.com".to_owned();
1108 let resource = "res1".to_string();
1109 let operation = "read".to_string();
1110 let root = KeyPair::new();
1111 let public_key = root.public();
1112 let token = create_biscuit(
1114 subject.clone(),
1115 resource.clone(),
1116 operation.clone(),
1117 root,
1118 TokenTimeConfig::default(),
1119 )
1120 .unwrap();
1121
1122 let res = verify_biscuit_local(
1123 token.clone(),
1124 public_key,
1125 subject.clone(),
1126 resource.clone(),
1127 operation.clone(),
1128 );
1129 assert!(res.is_ok());
1130
1131 let root = KeyPair::new();
1133 let token = create_biscuit(
1134 subject.clone(),
1135 resource.clone(),
1136 operation.clone(),
1137 root,
1138 TokenTimeConfig {
1139 start_time: Some(Utc::now().timestamp() - 301),
1140 duration: 300,
1141 },
1142 )
1143 .unwrap();
1144 let res = verify_biscuit_local(token, public_key, subject, resource, operation);
1145 assert!(res.is_err());
1146 }
1147
1148 #[test]
1149 fn test_custom_token_time_config() {
1150 let subject = "test@test.com".to_owned();
1151 let resource = "res1".to_string();
1152 let operation = "read".to_string();
1153 let root = KeyPair::new();
1154 let public_key = root.public();
1155
1156 let past_time = Utc::now().timestamp() - 3600;
1158 let time_config = TokenTimeConfig {
1159 start_time: Some(past_time),
1160 duration: 7200, };
1162
1163 let token = create_biscuit(
1164 subject.clone(),
1165 resource.clone(),
1166 operation.clone(),
1167 root,
1168 time_config,
1169 )
1170 .unwrap();
1171
1172 let res = verify_biscuit_local(
1174 token.clone(),
1175 public_key,
1176 subject.clone(),
1177 resource.clone(),
1178 operation.clone(),
1179 );
1180 assert!(res.is_ok());
1181 }
1182
1183 #[test]
1184 fn test_service_chain_biscuit() {
1185 let subject = "test@test.com".to_owned();
1186 let resource = "res1".to_string();
1187 let operation = "read".to_string();
1188 let root = KeyPair::new();
1189 let public_key = root.public();
1190 let chain_key = KeyPair::new();
1191 let chain_public_key = hex::encode(chain_key.public().to_bytes());
1192 let chain_public_key = format!("ed25519/{}", chain_public_key);
1193 let chain_node = ServiceNode {
1194 component: "edge_function".to_string(),
1195 public_key: chain_public_key.clone(),
1196 };
1197 let nodes = vec![chain_node];
1198 let token = create_service_chain_biscuit(
1199 subject.clone(),
1200 resource.clone(),
1201 operation.clone(),
1202 root,
1203 &nodes,
1204 TokenTimeConfig::default(),
1205 );
1206 if let Err(e) = &token {
1207 println!("Error: {}", e);
1208 }
1209 assert!(token.is_ok());
1210 let token = token.unwrap();
1211 let res = verify_biscuit_local(
1212 token.clone(),
1213 public_key,
1214 subject.clone(),
1215 resource.clone(),
1216 operation.clone(),
1217 );
1218 assert!(res.is_ok());
1219 let biscuit = Biscuit::from(&token, public_key).unwrap();
1220 let third_party_request = biscuit.third_party_request().unwrap();
1221 let third_party_block = block!(
1222 r#"
1223 service("res1");
1224 "#
1225 );
1226 let third_party_block = third_party_request
1227 .create_block(&chain_key.private(), third_party_block)
1228 .unwrap();
1229 let attested_biscuit = biscuit
1230 .append_third_party(chain_key.public(), third_party_block)
1231 .unwrap();
1232 let attested_token = attested_biscuit.to_vec().unwrap();
1233 let res = verify_service_chain_biscuit_local(
1234 attested_token,
1235 public_key,
1236 subject.clone(),
1237 resource.clone(),
1238 operation.clone(),
1239 nodes,
1240 None,
1241 );
1242 assert!(res.is_ok());
1243 }
1244
1245 #[test]
1246 fn test_service_chain_biscuit_with_component_name() {
1247 let subject = "test@test.com".to_owned();
1248 let resource = "res1".to_string();
1249 let root = KeyPair::new();
1250 let public_key = root.public();
1251
1252 let chain_key1 = KeyPair::new();
1254 let chain_public_key1 = hex::encode(chain_key1.public().to_bytes());
1255 let chain_public_key1 = format!("ed25519/{}", chain_public_key1);
1256 let chain_node1 = ServiceNode {
1257 component: "edge_function".to_string(),
1258 public_key: chain_public_key1.clone(),
1259 };
1260
1261 let chain_key2 = KeyPair::new();
1262 let chain_public_key2 = hex::encode(chain_key2.public().to_bytes());
1263 let chain_public_key2 = format!("ed25519/{}", chain_public_key2);
1264 let chain_node2 = ServiceNode {
1265 component: "middleware".to_string(),
1266 public_key: chain_public_key2.clone(),
1267 };
1268
1269 let nodes = vec![chain_node1.clone(), chain_node2.clone()];
1270
1271 let token = create_service_chain_biscuit(
1273 subject.clone(),
1274 resource.clone(),
1275 "read".to_string(),
1276 root,
1277 &nodes,
1278 TokenTimeConfig::default(),
1279 );
1280 assert!(token.is_ok());
1281 let token = token.unwrap();
1282
1283 let biscuit = Biscuit::from(&token, public_key).unwrap();
1285 let third_party_request = biscuit.third_party_request().unwrap();
1286 let third_party_block = block!(
1287 r#"
1288 service("res1");
1289 "#
1290 );
1291 let third_party_block = third_party_request
1292 .create_block(&chain_key1.private(), third_party_block)
1293 .unwrap();
1294 let attested_biscuit = biscuit
1295 .append_third_party(chain_key1.public(), third_party_block)
1296 .unwrap();
1297 let attested_token = attested_biscuit.to_vec().unwrap();
1298
1299 let res = verify_service_chain_biscuit_local(
1303 attested_token.clone(),
1304 public_key,
1305 subject.clone(),
1306 resource.clone(),
1307 "read".to_string(),
1308 nodes.clone(),
1309 Some("edge_function".to_string()),
1310 );
1311 assert!(res.is_ok());
1313
1314 let nodes = vec![chain_node1.clone(), chain_node2.clone()];
1316
1317 let res = verify_service_chain_biscuit_local(
1319 attested_token.clone(),
1320 public_key,
1321 subject.clone(),
1322 resource.clone(),
1323 "read".to_string(),
1324 nodes.clone(),
1325 Some("middleware".to_string()),
1326 );
1327 assert!(res.is_ok());
1328 }
1329
1330 #[test]
1331 fn test_service_chain_biscuit_with_nonexistent_component() {
1332 let subject = "test@test.com".to_owned();
1333 let resource = "res1".to_string();
1334 let root = KeyPair::new();
1335 let public_key = root.public();
1336 let chain_key = KeyPair::new();
1337 let chain_public_key = hex::encode(chain_key.public().to_bytes());
1338 let chain_public_key = format!("ed25519/{}", chain_public_key);
1339 let chain_node = ServiceNode {
1340 component: "edge_function".to_string(),
1341 public_key: chain_public_key.clone(),
1342 };
1343 let nodes = vec![chain_node];
1344 let token = create_service_chain_biscuit(
1345 subject.clone(),
1346 resource.clone(),
1347 "read".to_string(),
1348 root,
1349 &nodes,
1350 TokenTimeConfig::default(),
1351 );
1352 assert!(token.is_ok());
1353 let token = token.unwrap();
1354
1355 let biscuit = Biscuit::from(&token, public_key).unwrap();
1356 let third_party_request = biscuit.third_party_request().unwrap();
1357 let third_party_block = block!(
1358 r#"
1359 service("res1");
1360 "#
1361 );
1362 let third_party_block = third_party_request
1363 .create_block(&chain_key.private(), third_party_block)
1364 .unwrap();
1365 let attested_biscuit = biscuit
1366 .append_third_party(chain_key.public(), third_party_block)
1367 .unwrap();
1368 let attested_token = attested_biscuit.to_vec().unwrap();
1369
1370 let res = verify_service_chain_biscuit_local(
1372 attested_token,
1373 public_key,
1374 subject.clone(),
1375 resource.clone(),
1376 "read".to_string(),
1377 nodes.clone(),
1378 Some("nonexistent_component".to_string()),
1379 );
1380 assert!(res.is_err());
1381
1382 let err = res.unwrap_err().to_string();
1384 assert!(err.contains("nonexistent_component"));
1385 }
1386
1387 #[test]
1388 fn test_service_chain_biscuit_with_multiple_nodes() {
1389 let subject = "test@test.com".to_owned();
1390 let resource = "res1".to_string();
1391 let root = KeyPair::new();
1392 let public_key = root.public();
1393
1394 let chain_key1 = KeyPair::new();
1396 let chain_public_key1 = hex::encode(chain_key1.public().to_bytes());
1397 let chain_public_key1 = format!("ed25519/{}", chain_public_key1);
1398 let chain_node1 = ServiceNode {
1399 component: "edge_function".to_string(),
1400 public_key: chain_public_key1.clone(),
1401 };
1402
1403 let chain_key2 = KeyPair::new();
1404 let chain_public_key2 = hex::encode(chain_key2.public().to_bytes());
1405 let chain_public_key2 = format!("ed25519/{}", chain_public_key2);
1406 let chain_node2 = ServiceNode {
1407 component: "middleware".to_string(),
1408 public_key: chain_public_key2.clone(),
1409 };
1410
1411 let chain_key3 = KeyPair::new();
1412 let chain_public_key3 = hex::encode(chain_key3.public().to_bytes());
1413 let chain_public_key3 = format!("ed25519/{}", chain_public_key3);
1414 let chain_node3 = ServiceNode {
1415 component: "backend".to_string(),
1416 public_key: chain_public_key3.clone(),
1417 };
1418
1419 let nodes = vec![
1421 chain_node1.clone(),
1422 chain_node2.clone(),
1423 chain_node3.clone(),
1424 ];
1425 let token = create_service_chain_biscuit(
1426 subject.clone(),
1427 resource.clone(),
1428 "read".to_string(),
1429 root,
1430 &nodes,
1431 TokenTimeConfig::default(),
1432 );
1433 assert!(token.is_ok());
1434 let token = token.unwrap();
1435
1436 println!("Created initial token");
1437
1438 let biscuit = Biscuit::from(&token, public_key).unwrap();
1440 let third_party_request1 = biscuit.third_party_request().unwrap();
1441 let third_party_block1 = block!(
1442 r#"
1443 service("res1");
1444 "#
1445 );
1446 let third_party_block1 = third_party_request1
1447 .create_block(&chain_key1.private(), third_party_block1)
1448 .unwrap();
1449 let attested_biscuit1 = biscuit
1450 .append_third_party(chain_key1.public(), third_party_block1)
1451 .unwrap();
1452
1453 let all_nodes = vec![
1455 chain_node1.clone(),
1456 chain_node2.clone(),
1457 chain_node3.clone(),
1458 ];
1459 let attested_token1 = attested_biscuit1.to_vec().unwrap();
1460
1461 let res = verify_service_chain_biscuit_local(
1464 attested_token1.clone(),
1465 public_key,
1466 subject.clone(),
1467 resource.clone(),
1468 "read".to_string(),
1469 all_nodes.clone(),
1470 Some("middleware".to_string()),
1471 );
1472 assert!(res.is_ok());
1473
1474 let res = verify_service_chain_biscuit_local(
1478 attested_token1.clone(),
1479 public_key,
1480 subject.clone(),
1481 resource.clone(),
1482 "read".to_string(),
1483 all_nodes.clone(),
1484 Some("backend".to_string()),
1485 );
1486 assert!(res.is_err());
1487 }
1488
1489 #[test]
1490 fn test_service_chain_biscuit_with_custom_time() {
1491 let subject = "test@test.com".to_owned();
1492 let resource = "res1".to_string();
1493 let root = KeyPair::new();
1494 let public_key = root.public();
1495 let chain_key = KeyPair::new();
1496 let chain_public_key = hex::encode(chain_key.public().to_bytes());
1497 let chain_public_key = format!("ed25519/{}", chain_public_key);
1498 let chain_node = ServiceNode {
1499 component: "edge_function".to_string(),
1500 public_key: chain_public_key.clone(),
1501 };
1502 let nodes = vec![chain_node];
1503
1504 let valid_token = create_service_chain_biscuit_with_time(
1506 subject.clone(),
1507 resource.clone(),
1508 "read".to_string(),
1509 root,
1510 &nodes,
1511 TokenTimeConfig::default(),
1512 );
1513 assert!(valid_token.is_ok());
1514 let valid_token = valid_token.unwrap().to_vec().unwrap();
1515
1516 let res = verify_biscuit_local(
1518 valid_token.clone(),
1519 public_key,
1520 subject.clone(),
1521 resource.clone(),
1522 "read".to_string(),
1523 );
1524 assert!(res.is_ok());
1525
1526 let expired_time_config = TokenTimeConfig {
1528 start_time: Some(Utc::now().timestamp() - 360), duration: 300, };
1531
1532 let root2 = KeyPair::new();
1534 let public_key2 = root2.public();
1535
1536 let expired_token = create_service_chain_biscuit_with_time(
1537 subject.clone(),
1538 resource.clone(),
1539 "read".to_string(),
1540 root2,
1541 &nodes,
1542 expired_time_config,
1543 );
1544 assert!(expired_token.is_ok());
1545 let expired_token = expired_token.unwrap().to_vec().unwrap();
1546
1547 let res = verify_biscuit_local(
1549 expired_token,
1550 public_key2,
1551 subject,
1552 resource,
1553 "read".to_string(),
1554 );
1555 assert!(res.is_err());
1556 }
1557
1558 #[test]
1559 fn test_multi_party_biscuit_helper_functions() {
1560 let subject = "test@test.com".to_owned();
1561 let resource = "res1".to_string();
1562 let operation = "read".to_string();
1563 let root = KeyPair::new();
1564
1565 let multi_party_key = KeyPair::new();
1567 let multi_party_public_key = hex::encode(multi_party_key.public().to_bytes());
1568 let multi_party_public_key = format!("ed25519/{}", multi_party_public_key);
1569 let multi_party_node = ServiceNode {
1570 component: "approval_service".to_string(),
1571 public_key: multi_party_public_key.clone(),
1572 };
1573 let nodes = vec![multi_party_node];
1574
1575 let token_string = create_multi_party_token(
1577 subject.clone(),
1578 resource.clone(),
1579 operation.clone(),
1580 root,
1581 &nodes,
1582 );
1583 assert!(token_string.is_ok());
1584
1585 let root2 = KeyPair::new();
1587 let binary_token = create_multi_party_biscuit(
1588 subject.clone(),
1589 resource.clone(),
1590 operation.clone(),
1591 root2,
1592 &nodes,
1593 );
1594 assert!(binary_token.is_ok());
1595
1596 let root3 = KeyPair::new();
1598 let raw_biscuit = create_raw_multi_party_biscuit(
1599 subject.clone(),
1600 resource.clone(),
1601 operation.clone(),
1602 root3,
1603 &nodes,
1604 );
1605 assert!(raw_biscuit.is_ok());
1606
1607 let custom_time_config = TokenTimeConfig {
1609 start_time: Some(Utc::now().timestamp()),
1610 duration: 600, };
1612 let root4 = KeyPair::new();
1613 let custom_time_token = create_multi_party_token_with_time(
1614 subject.clone(),
1615 resource.clone(),
1616 operation.clone(),
1617 root4,
1618 &nodes,
1619 custom_time_config,
1620 );
1621 assert!(custom_time_token.is_ok());
1622
1623 let root5 = KeyPair::new();
1625 let custom_time_biscuit = create_multi_party_biscuit_with_time(
1626 subject.clone(),
1627 resource.clone(),
1628 operation.clone(),
1629 root5,
1630 &nodes,
1631 custom_time_config,
1632 );
1633 assert!(custom_time_biscuit.is_ok());
1634 }
1635
1636 #[test]
1637 fn test_basic_authorization_with_domain_restriction() {
1638 let subject = "alice".to_string();
1639 let resource = "resource1".to_string();
1640 let operation = "read".to_string();
1641 let domain = "myapp.hessra.dev".to_string();
1642 let keypair = KeyPair::new();
1643 let public_key = keypair.public();
1644
1645 let token = HessraAuthorization::new(
1647 subject.clone(),
1648 resource.clone(),
1649 operation.clone(),
1650 TokenTimeConfig::default(),
1651 )
1652 .domain_restricted(domain.clone())
1653 .issue(&keypair);
1654
1655 assert!(token.is_ok(), "Failed to create domain-restricted token");
1656 let token = token.unwrap();
1657
1658 let biscuit = Biscuit::from_base64(&token, public_key).unwrap();
1660
1661 let authz = crate::verify::build_base_authorizer(
1663 subject.clone(),
1664 resource.clone(),
1665 operation.clone(),
1666 Some(domain.clone()),
1667 )
1668 .unwrap();
1669 assert!(
1670 authz.build(&biscuit).unwrap().authorize().is_ok(),
1671 "Token should verify with correct domain"
1672 );
1673
1674 let authz_no_domain = crate::verify::build_base_authorizer(
1676 subject.clone(),
1677 resource.clone(),
1678 operation.clone(),
1679 None,
1680 )
1681 .unwrap();
1682 assert!(
1683 authz_no_domain
1684 .build(&biscuit)
1685 .unwrap()
1686 .authorize()
1687 .is_err(),
1688 "Token should fail verification without domain fact"
1689 );
1690
1691 let authz_wrong_domain = crate::verify::build_base_authorizer(
1693 subject,
1694 resource,
1695 operation,
1696 Some("wrongdomain.com".to_string()),
1697 )
1698 .unwrap();
1699 assert!(
1700 authz_wrong_domain
1701 .build(&biscuit)
1702 .unwrap()
1703 .authorize()
1704 .is_err(),
1705 "Token should fail verification with wrong domain"
1706 );
1707 }
1708
1709 #[test]
1710 fn test_service_chain_with_domain_restriction() {
1711 let subject = "alice".to_string();
1712 let resource = "resource1".to_string();
1713 let operation = "read".to_string();
1714 let domain = "myapp.hessra.dev".to_string();
1715 let keypair = KeyPair::new();
1716 let public_key = keypair.public();
1717
1718 let chain_key = KeyPair::new();
1720 let chain_public_key = hex::encode(chain_key.public().to_bytes());
1721 let chain_public_key = format!("ed25519/{}", chain_public_key);
1722 let chain_node = ServiceNode {
1723 component: "edge_function".to_string(),
1724 public_key: chain_public_key.clone(),
1725 };
1726 let nodes = vec![chain_node];
1727
1728 let token = HessraAuthorization::new(
1730 subject.clone(),
1731 resource.clone(),
1732 operation.clone(),
1733 TokenTimeConfig::default(),
1734 )
1735 .service_chain(nodes.clone())
1736 .domain_restricted(domain.clone())
1737 .issue(&keypair);
1738
1739 assert!(
1740 token.is_ok(),
1741 "Failed to create domain-restricted service chain token"
1742 );
1743 let token = token.unwrap();
1744
1745 let biscuit = Biscuit::from_base64(&token, public_key).unwrap();
1747
1748 let authz = crate::verify::build_base_authorizer(
1750 subject.clone(),
1751 resource.clone(),
1752 operation.clone(),
1753 Some(domain),
1754 )
1755 .unwrap();
1756 assert!(
1757 authz.build(&biscuit).unwrap().authorize().is_ok(),
1758 "Service chain token should verify with correct domain"
1759 );
1760
1761 let authz_no_domain =
1763 crate::verify::build_base_authorizer(subject, resource, operation, None).unwrap();
1764 assert!(
1765 authz_no_domain
1766 .build(&biscuit)
1767 .unwrap()
1768 .authorize()
1769 .is_err(),
1770 "Service chain token should fail verification without domain fact"
1771 );
1772 }
1773
1774 #[test]
1775 fn test_multi_party_with_domain_restriction() {
1776 let subject = "alice".to_string();
1777 let resource = "resource1".to_string();
1778 let operation = "read".to_string();
1779 let domain = "myapp.hessra.dev".to_string();
1780 let keypair = KeyPair::new();
1781 let public_key = keypair.public();
1782
1783 let party_key = KeyPair::new();
1785 let party_public_key = hex::encode(party_key.public().to_bytes());
1786 let party_public_key = format!("ed25519/{}", party_public_key);
1787 let party_node = ServiceNode {
1788 component: "approval_service".to_string(),
1789 public_key: party_public_key.clone(),
1790 };
1791 let nodes = vec![party_node];
1792
1793 let token = HessraAuthorization::new(
1795 subject.clone(),
1796 resource.clone(),
1797 operation.clone(),
1798 TokenTimeConfig::default(),
1799 )
1800 .multi_party(nodes.clone())
1801 .domain_restricted(domain.clone())
1802 .issue(&keypair);
1803
1804 assert!(
1805 token.is_ok(),
1806 "Failed to create domain-restricted multi-party token"
1807 );
1808 let token = token.unwrap();
1809
1810 let biscuit = Biscuit::from_base64(&token, public_key).unwrap();
1812
1813 let _authz = crate::verify::build_base_authorizer(
1816 subject.clone(),
1817 resource.clone(),
1818 operation.clone(),
1819 Some(domain),
1820 )
1821 .unwrap();
1822 assert!(biscuit.to_base64().is_ok(), "Token should be valid biscuit");
1825
1826 let authz_no_domain =
1828 crate::verify::build_base_authorizer(subject, resource, operation, None).unwrap();
1829 assert!(
1830 authz_no_domain
1831 .build(&biscuit)
1832 .unwrap()
1833 .authorize()
1834 .is_err(),
1835 "Multi-party token should fail verification without domain fact or attestations"
1836 );
1837 }
1838
1839 #[test]
1840 fn test_authorization_verifier_with_domain() {
1841 use crate::verify::AuthorizationVerifier;
1842
1843 let subject = "alice".to_string();
1844 let resource = "resource1".to_string();
1845 let operation = "read".to_string();
1846 let domain = "myapp.hessra.dev".to_string();
1847 let keypair = KeyPair::new();
1848 let public_key = keypair.public();
1849
1850 let token = HessraAuthorization::new(
1852 subject.clone(),
1853 resource.clone(),
1854 operation.clone(),
1855 TokenTimeConfig::default(),
1856 )
1857 .domain_restricted(domain.clone())
1858 .issue(&keypair)
1859 .expect("Failed to create domain-restricted token");
1860
1861 assert!(
1863 AuthorizationVerifier::new(
1864 token.clone(),
1865 public_key,
1866 subject.clone(),
1867 resource.clone(),
1868 operation.clone(),
1869 )
1870 .with_domain(domain.clone())
1871 .verify()
1872 .is_ok(),
1873 "Token should verify with correct domain using builder"
1874 );
1875
1876 assert!(
1878 AuthorizationVerifier::new(
1879 token.clone(),
1880 public_key,
1881 subject.clone(),
1882 resource.clone(),
1883 operation.clone(),
1884 )
1885 .verify()
1886 .is_err(),
1887 "Token should fail verification without domain context"
1888 );
1889
1890 assert!(
1892 AuthorizationVerifier::new(
1893 token.clone(),
1894 public_key,
1895 subject.clone(),
1896 resource.clone(),
1897 operation.clone(),
1898 )
1899 .with_domain("wrongdomain.com".to_string())
1900 .verify()
1901 .is_err(),
1902 "Token should fail verification with wrong domain"
1903 );
1904
1905 let regular_token = HessraAuthorization::new(
1907 subject.clone(),
1908 resource.clone(),
1909 operation.clone(),
1910 TokenTimeConfig::default(),
1911 )
1912 .issue(&keypair)
1913 .expect("Failed to create regular token");
1914
1915 assert!(
1917 AuthorizationVerifier::new(
1918 regular_token.clone(),
1919 public_key,
1920 subject.clone(),
1921 resource.clone(),
1922 operation.clone(),
1923 )
1924 .verify()
1925 .is_ok(),
1926 "Regular token should verify without domain context"
1927 );
1928
1929 assert!(
1930 AuthorizationVerifier::new(regular_token, public_key, subject, resource, operation,)
1931 .with_domain(domain)
1932 .verify()
1933 .is_ok(),
1934 "Regular token should verify even with extra domain context"
1935 );
1936 }
1937
1938 #[test]
1939 fn test_service_chain_verifier_with_domain() {
1940 use crate::verify::{AuthorizationVerifier, ServiceNode};
1941
1942 let subject = "alice".to_string();
1943 let resource = "resource1".to_string();
1944 let operation = "read".to_string();
1945 let domain = "myapp.hessra.dev".to_string();
1946 let keypair = KeyPair::new();
1947 let public_key = keypair.public();
1948
1949 let node_keypair = KeyPair::new();
1951 let node_public_key = node_keypair.public();
1952 let node_key_string = format!("ed25519/{}", hex::encode(node_public_key.to_bytes()));
1953
1954 let service_nodes = vec![ServiceNode {
1955 component: "api-gateway".to_string(),
1956 public_key: node_key_string,
1957 }];
1958
1959 let token = HessraAuthorization::new(
1961 subject.clone(),
1962 resource.clone(),
1963 operation.clone(),
1964 TokenTimeConfig::default(),
1965 )
1966 .service_chain(service_nodes.clone())
1967 .domain_restricted(domain.clone())
1968 .issue(&keypair)
1969 .expect("Failed to create service chain token with domain");
1970
1971 let token_bytes = crate::decode_token(&token).expect("Failed to decode token");
1973
1974 let attested_token_bytes = crate::attest::add_service_node_attestation(
1976 token_bytes,
1977 public_key,
1978 &resource,
1979 &node_keypair,
1980 )
1981 .expect("Failed to add attestation");
1982
1983 assert!(
1985 AuthorizationVerifier::from_bytes(
1986 attested_token_bytes.clone(),
1987 public_key,
1988 subject.clone(),
1989 resource.clone(),
1990 operation.clone(),
1991 )
1992 .expect("Failed to create verifier")
1993 .with_service_chain(service_nodes.clone(), Some("api-gateway".to_string()))
1994 .with_domain(domain.clone())
1995 .verify()
1996 .is_ok(),
1997 "Service chain token should verify with domain"
1998 );
1999
2000 assert!(
2002 AuthorizationVerifier::from_bytes(
2003 attested_token_bytes.clone(),
2004 public_key,
2005 subject.clone(),
2006 resource.clone(),
2007 operation.clone(),
2008 )
2009 .expect("Failed to create verifier")
2010 .with_service_chain(service_nodes.clone(), Some("api-gateway".to_string()))
2011 .verify()
2012 .is_err(),
2013 "Service chain token should fail without domain"
2014 );
2015
2016 assert!(
2020 AuthorizationVerifier::from_bytes(
2021 attested_token_bytes,
2022 public_key,
2023 subject,
2024 resource,
2025 operation,
2026 )
2027 .expect("Failed to create verifier")
2028 .with_domain(domain)
2029 .verify()
2030 .is_ok(),
2031 "Service chain token with valid attestation should pass basic verification"
2032 );
2033 }
2034
2035 #[test]
2036 fn test_latent_capability_basic() {
2037 let root_keypair = KeyPair::new();
2038 let root_public_key = root_keypair.public();
2039
2040 let activator_keypair = KeyPair::new();
2041 let activator_public_key = format!(
2042 "ed25519/{}",
2043 hex::encode(activator_keypair.public().to_bytes())
2044 );
2045
2046 let latent_rights = vec![
2048 ("resource1".to_string(), "read".to_string()),
2049 ("resource1".to_string(), "write".to_string()),
2050 ("resource2".to_string(), "read".to_string()),
2051 ];
2052
2053 let latent_token = HessraAuthorization::new_latent(
2054 latent_rights,
2055 activator_public_key,
2056 TokenTimeConfig::default(),
2057 )
2058 .issue(&root_keypair)
2059 .expect("Failed to create latent token");
2060
2061 let subject = "alice".to_string();
2063 let resource = "resource1".to_string();
2064 let operation = "read".to_string();
2065
2066 let activated_token = activate_latent_token_from_string(
2067 latent_token.clone(),
2068 root_public_key,
2069 subject.clone(),
2070 resource.clone(),
2071 operation.clone(),
2072 &activator_keypair,
2073 TokenTimeConfig::default(),
2074 )
2075 .expect("Failed to activate latent token");
2076
2077 let result = crate::verify::verify_token_local(
2079 &activated_token,
2080 root_public_key,
2081 &subject,
2082 &resource,
2083 &operation,
2084 );
2085
2086 assert!(result.is_ok(), "Activated token should verify successfully");
2087 }
2088
2089 #[test]
2090 fn test_latent_capability_multiple_activations() {
2091 let root_keypair = KeyPair::new();
2092 let root_public_key = root_keypair.public();
2093
2094 let activator_keypair = KeyPair::new();
2095 let activator_public_key = format!(
2096 "ed25519/{}",
2097 hex::encode(activator_keypair.public().to_bytes())
2098 );
2099
2100 let latent_rights = vec![
2102 ("resource1".to_string(), "read".to_string()),
2103 ("resource1".to_string(), "write".to_string()),
2104 ("resource2".to_string(), "read".to_string()),
2105 ];
2106
2107 let latent_token = HessraAuthorization::new_latent(
2108 latent_rights,
2109 activator_public_key,
2110 TokenTimeConfig::default(),
2111 )
2112 .issue(&root_keypair)
2113 .expect("Failed to create latent token");
2114
2115 let activations = vec![
2117 (
2118 "alice".to_string(),
2119 "resource1".to_string(),
2120 "read".to_string(),
2121 ),
2122 (
2123 "bob".to_string(),
2124 "resource1".to_string(),
2125 "write".to_string(),
2126 ),
2127 (
2128 "charlie".to_string(),
2129 "resource2".to_string(),
2130 "read".to_string(),
2131 ),
2132 ];
2133
2134 for (subject, resource, operation) in activations {
2135 let activated_token = activate_latent_token_from_string(
2136 latent_token.clone(),
2137 root_public_key,
2138 subject.clone(),
2139 resource.clone(),
2140 operation.clone(),
2141 &activator_keypair,
2142 TokenTimeConfig::default(),
2143 )
2144 .expect("Failed to activate latent token");
2145
2146 let result = crate::verify::verify_token_local(
2148 &activated_token,
2149 root_public_key,
2150 &subject,
2151 &resource,
2152 &operation,
2153 );
2154
2155 assert!(
2156 result.is_ok(),
2157 "Activated token for {} should verify successfully",
2158 subject
2159 );
2160 }
2161 }
2162
2163 #[test]
2164 fn test_latent_capability_invalid_right() {
2165 let root_keypair = KeyPair::new();
2166 let root_public_key = root_keypair.public();
2167
2168 let activator_keypair = KeyPair::new();
2169 let activator_public_key = format!(
2170 "ed25519/{}",
2171 hex::encode(activator_keypair.public().to_bytes())
2172 );
2173
2174 let latent_rights = vec![("resource1".to_string(), "read".to_string())];
2176
2177 let latent_token = HessraAuthorization::new_latent(
2178 latent_rights,
2179 activator_public_key,
2180 TokenTimeConfig::default(),
2181 )
2182 .issue(&root_keypair)
2183 .expect("Failed to create latent token");
2184
2185 let activated_token = activate_latent_token_from_string(
2187 latent_token,
2188 root_public_key,
2189 "alice".to_string(),
2190 "resource1".to_string(),
2191 "write".to_string(), &activator_keypair,
2193 TokenTimeConfig::default(),
2194 )
2195 .expect("Activation should succeed (validation happens at verification)");
2196
2197 let result = crate::verify::verify_token_local(
2199 &activated_token,
2200 root_public_key,
2201 "alice",
2202 "resource1",
2203 "write",
2204 );
2205
2206 assert!(
2207 result.is_err(),
2208 "Should fail to verify token with right not in latent_rights"
2209 );
2210 }
2211
2212 #[test]
2213 fn test_latent_capability_with_domain_restriction() {
2214 let root_keypair = KeyPair::new();
2215 let root_public_key = root_keypair.public();
2216
2217 let activator_keypair = KeyPair::new();
2218 let activator_public_key = format!(
2219 "ed25519/{}",
2220 hex::encode(activator_keypair.public().to_bytes())
2221 );
2222
2223 let domain = "myapp.hessra.dev".to_string();
2224
2225 let latent_rights = vec![("resource1".to_string(), "read".to_string())];
2227
2228 let latent_token = HessraAuthorization::new_latent(
2229 latent_rights,
2230 activator_public_key,
2231 TokenTimeConfig::default(),
2232 )
2233 .domain_restricted(domain.clone())
2234 .issue(&root_keypair)
2235 .expect("Failed to create latent token with domain restriction");
2236
2237 let activated_token = activate_latent_token_from_string(
2239 latent_token,
2240 root_public_key,
2241 "alice".to_string(),
2242 "resource1".to_string(),
2243 "read".to_string(),
2244 &activator_keypair,
2245 TokenTimeConfig::default(),
2246 )
2247 .expect("Failed to activate latent token");
2248
2249 let result = crate::verify::AuthorizationVerifier::new(
2251 activated_token.clone(),
2252 root_public_key,
2253 "alice".to_string(),
2254 "resource1".to_string(),
2255 "read".to_string(),
2256 )
2257 .with_domain(domain.clone())
2258 .verify();
2259
2260 assert!(result.is_ok(), "Should verify with correct domain");
2261
2262 let result = crate::verify::AuthorizationVerifier::new(
2264 activated_token,
2265 root_public_key,
2266 "alice".to_string(),
2267 "resource1".to_string(),
2268 "read".to_string(),
2269 )
2270 .verify();
2271
2272 assert!(result.is_err(), "Should fail to verify without domain");
2273 }
2274
2275 #[test]
2276 fn test_latent_capability_with_multi_party() {
2277 let root_keypair = KeyPair::new();
2278 let root_public_key = root_keypair.public();
2279
2280 let activator_keypair = KeyPair::new();
2281 let activator_public_key = format!(
2282 "ed25519/{}",
2283 hex::encode(activator_keypair.public().to_bytes())
2284 );
2285
2286 let party_keypair = KeyPair::new();
2288 let party_public_key =
2289 format!("ed25519/{}", hex::encode(party_keypair.public().to_bytes()));
2290 let party_node = ServiceNode {
2291 component: "approval_service".to_string(),
2292 public_key: party_public_key,
2293 };
2294
2295 let latent_rights = vec![("resource1".to_string(), "read".to_string())];
2297
2298 let latent_token = HessraAuthorization::new_latent(
2299 latent_rights,
2300 activator_public_key,
2301 TokenTimeConfig::default(),
2302 )
2303 .multi_party(vec![party_node])
2304 .issue(&root_keypair)
2305 .expect("Failed to create latent token with multi-party");
2306
2307 let latent_token_bytes =
2309 crate::decode_token(&latent_token).expect("Failed to decode token");
2310 let attested_latent_bytes = crate::attest::add_multi_party_attestation(
2311 latent_token_bytes,
2312 root_public_key,
2313 "approval_service".to_string(),
2314 party_keypair,
2315 )
2316 .expect("Failed to add multi-party attestation");
2317
2318 let activated_token_bytes = activate_latent_token(
2320 attested_latent_bytes,
2321 root_public_key,
2322 "alice".to_string(),
2323 "resource1".to_string(),
2324 "read".to_string(),
2325 &activator_keypair,
2326 TokenTimeConfig::default(),
2327 )
2328 .expect("Failed to activate attested latent token");
2329
2330 let activated_token = crate::encode_token(&activated_token_bytes);
2331
2332 let result = crate::verify::verify_token_local(
2334 &activated_token,
2335 root_public_key,
2336 "alice",
2337 "resource1",
2338 "read",
2339 );
2340
2341 assert!(
2342 result.is_ok(),
2343 "Activated token with multi-party attestation should verify"
2344 );
2345 }
2346
2347 #[test]
2348 fn test_activated_latent_with_service_chain() {
2349 let root_keypair = KeyPair::new();
2350 let root_public_key = root_keypair.public();
2351
2352 let activator_keypair = KeyPair::new();
2353 let activator_public_key = format!(
2354 "ed25519/{}",
2355 hex::encode(activator_keypair.public().to_bytes())
2356 );
2357
2358 let chain_keypair = KeyPair::new();
2360 let chain_public_key =
2361 format!("ed25519/{}", hex::encode(chain_keypair.public().to_bytes()));
2362 let chain_node = ServiceNode {
2363 component: "edge_function".to_string(),
2364 public_key: chain_public_key,
2365 };
2366
2367 let latent_rights = vec![("resource1".to_string(), "read".to_string())];
2369
2370 let latent_token = HessraAuthorization::new_latent(
2371 latent_rights,
2372 activator_public_key,
2373 TokenTimeConfig::default(),
2374 )
2375 .service_chain(vec![chain_node.clone()])
2376 .issue(&root_keypair)
2377 .expect("Failed to create latent token with service chain");
2378
2379 let activated_token_bytes = activate_latent_token(
2381 crate::decode_token(&latent_token).expect("Failed to decode"),
2382 root_public_key,
2383 "alice".to_string(),
2384 "resource1".to_string(),
2385 "read".to_string(),
2386 &activator_keypair,
2387 TokenTimeConfig::default(),
2388 )
2389 .expect("Failed to activate latent token");
2390
2391 let attested_token_bytes = crate::attest::add_service_node_attestation(
2393 activated_token_bytes,
2394 root_public_key,
2395 "resource1",
2396 &chain_keypair,
2397 )
2398 .expect("Failed to add service chain attestation");
2399
2400 let result = verify_service_chain_biscuit_local(
2402 attested_token_bytes,
2403 root_public_key,
2404 "alice".to_string(),
2405 "resource1".to_string(),
2406 "read".to_string(),
2407 vec![chain_node],
2408 None,
2409 );
2410
2411 assert!(
2412 result.is_ok(),
2413 "Activated latent token with service chain should verify"
2414 );
2415 }
2416
2417 #[test]
2418 fn test_latent_capability_wrong_activator_key() {
2419 let root_keypair = KeyPair::new();
2420 let root_public_key = root_keypair.public();
2421
2422 let activator_keypair = KeyPair::new();
2423 let activator_public_key = format!(
2424 "ed25519/{}",
2425 hex::encode(activator_keypair.public().to_bytes())
2426 );
2427
2428 let latent_rights = vec![("resource1".to_string(), "read".to_string())];
2430
2431 let latent_token = HessraAuthorization::new_latent(
2432 latent_rights,
2433 activator_public_key,
2434 TokenTimeConfig::default(),
2435 )
2436 .issue(&root_keypair)
2437 .expect("Failed to create latent token");
2438
2439 let wrong_activator_keypair = KeyPair::new();
2441
2442 let activated_token = activate_latent_token_from_string(
2443 latent_token,
2444 root_public_key,
2445 "alice".to_string(),
2446 "resource1".to_string(),
2447 "read".to_string(),
2448 &wrong_activator_keypair,
2449 TokenTimeConfig::default(),
2450 )
2451 .expect("Activation succeeds (wrong key detected at verification)");
2452
2453 let result = crate::verify::verify_token_local(
2455 &activated_token,
2456 root_public_key,
2457 "alice",
2458 "resource1",
2459 "read",
2460 );
2461
2462 assert!(
2463 result.is_err(),
2464 "Should fail to verify token activated with wrong key"
2465 );
2466 }
2467
2468 #[test]
2469 fn test_latent_capability_time_attenuation() {
2470 let root_keypair = KeyPair::new();
2471 let root_public_key = root_keypair.public();
2472
2473 let activator_keypair = KeyPair::new();
2474 let activator_public_key = format!(
2475 "ed25519/{}",
2476 hex::encode(activator_keypair.public().to_bytes())
2477 );
2478
2479 let latent_rights = vec![("resource1".to_string(), "read".to_string())];
2481
2482 let latent_token = HessraAuthorization::new_latent(
2483 latent_rights,
2484 activator_public_key,
2485 TokenTimeConfig {
2486 start_time: Some(Utc::now().timestamp()),
2487 duration: 1800, },
2489 )
2490 .issue(&root_keypair)
2491 .expect("Failed to create latent token");
2492
2493 let activated_token_short = activate_latent_token_from_string(
2495 latent_token.clone(),
2496 root_public_key,
2497 "alice".to_string(),
2498 "resource1".to_string(),
2499 "read".to_string(),
2500 &activator_keypair,
2501 TokenTimeConfig {
2502 start_time: Some(Utc::now().timestamp()),
2503 duration: 300, },
2505 )
2506 .expect("Failed to activate latent token");
2507
2508 let result = crate::verify::verify_token_local(
2510 &activated_token_short,
2511 root_public_key,
2512 "alice",
2513 "resource1",
2514 "read",
2515 );
2516 assert!(
2517 result.is_ok(),
2518 "Activated token with 5min expiration should verify"
2519 );
2520
2521 let activated_token_expired = activate_latent_token_from_string(
2523 latent_token.clone(),
2524 root_public_key,
2525 "bob".to_string(),
2526 "resource1".to_string(),
2527 "read".to_string(),
2528 &activator_keypair,
2529 TokenTimeConfig {
2530 start_time: Some(Utc::now().timestamp() - 2), duration: 1, },
2533 )
2534 .expect("Failed to activate latent token");
2535
2536 let result = crate::verify::verify_token_local(
2538 &activated_token_expired,
2539 root_public_key,
2540 "bob",
2541 "resource1",
2542 "read",
2543 );
2544 assert!(
2545 result.is_err(),
2546 "Activated token with expired time should fail verification"
2547 );
2548
2549 let latent_token_long = HessraAuthorization::new_latent(
2554 vec![("resource2".to_string(), "write".to_string())],
2555 format!(
2556 "ed25519/{}",
2557 hex::encode(activator_keypair.public().to_bytes())
2558 ),
2559 TokenTimeConfig {
2560 start_time: Some(Utc::now().timestamp()),
2561 duration: 3600, },
2563 )
2564 .issue(&root_keypair)
2565 .expect("Failed to create long-lived latent token");
2566
2567 let activated_expired_despite_latent = activate_latent_token_from_string(
2568 latent_token_long,
2569 root_public_key,
2570 "charlie".to_string(),
2571 "resource2".to_string(),
2572 "write".to_string(),
2573 &activator_keypair,
2574 TokenTimeConfig {
2575 start_time: Some(Utc::now().timestamp() - 10), duration: 1, },
2578 )
2579 .expect("Failed to activate long-lived latent token");
2580
2581 let result = crate::verify::verify_token_local(
2583 &activated_expired_despite_latent,
2584 root_public_key,
2585 "charlie",
2586 "resource2",
2587 "write",
2588 );
2589 assert!(
2590 result.is_err(),
2591 "Activation expiration should take precedence over latent expiration"
2592 );
2593 }
2594
2595 #[test]
2596 fn test_verify_capability_token_basic() {
2597 let subject = "alice".to_string();
2598 let resource = "resource1".to_string();
2599 let operation = "read".to_string();
2600 let keypair = KeyPair::new();
2601 let public_key = keypair.public();
2602
2603 let token = create_token(
2605 subject.clone(),
2606 resource.clone(),
2607 operation.clone(),
2608 keypair,
2609 )
2610 .unwrap();
2611
2612 let result =
2614 crate::verify::verify_capability_token_local(&token, public_key, &resource, &operation);
2615
2616 assert!(result.is_ok());
2617 }
2618
2619 #[test]
2620 fn test_verify_capability_token_wrong_resource() {
2621 let keypair = KeyPair::new();
2622 let public_key = keypair.public();
2623
2624 let token = create_token(
2625 "alice".to_string(),
2626 "resource1".to_string(),
2627 "read".to_string(),
2628 keypair,
2629 )
2630 .unwrap();
2631
2632 let result = crate::verify::verify_capability_token_local(
2634 &token,
2635 public_key,
2636 "resource2", "read",
2638 );
2639
2640 assert!(result.is_err());
2641 }
2642
2643 #[test]
2644 fn test_verify_capability_token_wrong_operation() {
2645 let keypair = KeyPair::new();
2646 let public_key = keypair.public();
2647
2648 let token = create_token(
2649 "alice".to_string(),
2650 "resource1".to_string(),
2651 "read".to_string(),
2652 keypair,
2653 )
2654 .unwrap();
2655
2656 let result = crate::verify::verify_capability_token_local(
2658 &token,
2659 public_key,
2660 "resource1",
2661 "write", );
2663
2664 assert!(result.is_err());
2665 }
2666
2667 #[test]
2668 fn test_verify_capability_with_domain() {
2669 let domain = "myapp.hessra.dev".to_string();
2670 let keypair = KeyPair::new();
2671 let public_key = keypair.public();
2672
2673 let token = HessraAuthorization::new(
2675 "alice".to_string(),
2676 "resource1".to_string(),
2677 "read".to_string(),
2678 TokenTimeConfig::default(),
2679 )
2680 .domain_restricted(domain.clone())
2681 .issue(&keypair)
2682 .unwrap();
2683
2684 let result = crate::verify::AuthorizationVerifier::new_capability(
2686 token.clone(),
2687 public_key,
2688 "resource1".to_string(),
2689 "read".to_string(),
2690 )
2691 .with_domain(domain.clone())
2692 .verify();
2693
2694 assert!(result.is_ok());
2695
2696 let result = crate::verify::AuthorizationVerifier::new_capability(
2698 token,
2699 public_key,
2700 "resource1".to_string(),
2701 "read".to_string(),
2702 )
2703 .verify();
2704
2705 assert!(result.is_err());
2706 }
2707
2708 #[test]
2709 fn test_verify_capability_with_service_chain() {
2710 let keypair = KeyPair::new();
2711 let public_key = keypair.public();
2712
2713 let chain_keypair = KeyPair::new();
2714 let chain_public_key =
2715 format!("ed25519/{}", hex::encode(chain_keypair.public().to_bytes()));
2716 let chain_node = ServiceNode {
2717 component: "edge_function".to_string(),
2718 public_key: chain_public_key,
2719 };
2720
2721 let token = HessraAuthorization::new(
2723 "alice".to_string(),
2724 "resource1".to_string(),
2725 "read".to_string(),
2726 TokenTimeConfig::default(),
2727 )
2728 .service_chain(vec![chain_node.clone()])
2729 .issue(&keypair)
2730 .unwrap();
2731
2732 let token_bytes = crate::decode_token(&token).unwrap();
2734 let attested = crate::attest::add_service_node_attestation(
2735 token_bytes,
2736 public_key,
2737 "resource1",
2738 &chain_keypair,
2739 )
2740 .unwrap();
2741 let attested_token = crate::encode_token(&attested);
2742
2743 let result = crate::verify::verify_service_chain_capability_token_local(
2745 &attested_token,
2746 public_key,
2747 "resource1",
2748 "read",
2749 vec![chain_node],
2750 None,
2751 );
2752
2753 assert!(result.is_ok());
2754 }
2755
2756 #[test]
2757 fn test_capability_verifier_builder() {
2758 let keypair = KeyPair::new();
2759 let public_key = keypair.public();
2760 let domain = "example.com".to_string();
2761
2762 let token = HessraAuthorization::new(
2763 "alice".to_string(),
2764 "resource1".to_string(),
2765 "read".to_string(),
2766 TokenTimeConfig::default(),
2767 )
2768 .domain_restricted(domain.clone())
2769 .issue(&keypair)
2770 .unwrap();
2771
2772 let result = crate::verify::AuthorizationVerifier::new_capability(
2774 token,
2775 public_key,
2776 "resource1".to_string(),
2777 "read".to_string(),
2778 )
2779 .with_domain(domain)
2780 .verify();
2781
2782 assert!(result.is_ok());
2783 }
2784
2785 #[test]
2786 fn test_capability_vs_identity_verification() {
2787 let keypair = KeyPair::new();
2788 let public_key = keypair.public();
2789
2790 let token = create_token(
2792 "alice".to_string(),
2793 "document_123".to_string(),
2794 "read".to_string(),
2795 keypair,
2796 )
2797 .unwrap();
2798
2799 let result = crate::verify::verify_token_local(
2801 &token,
2802 public_key,
2803 "alice", "document_123",
2805 "read",
2806 );
2807 assert!(result.is_ok());
2808
2809 let result = crate::verify::verify_token_local(
2811 &token,
2812 public_key,
2813 "bob", "document_123",
2815 "read",
2816 );
2817 assert!(result.is_err());
2818
2819 let result = crate::verify::verify_capability_token_local(
2821 &token,
2822 public_key,
2823 "document_123", "read",
2825 );
2826 assert!(result.is_ok());
2827 }
2828}