1use super::device_id::DeviceId;
40use super::error::SecurityError;
41use serde::{Deserialize, Serialize};
42use std::collections::{HashMap, HashSet};
43use std::fmt;
44use std::time::SystemTime;
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
50pub enum Role {
51 Leader,
53
54 Member,
56
57 Observer,
59
60 Commander,
62
63 Admin,
65}
66
67impl fmt::Display for Role {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69 match self {
70 Role::Leader => write!(f, "Leader"),
71 Role::Member => write!(f, "Member"),
72 Role::Observer => write!(f, "Observer"),
73 Role::Commander => write!(f, "Commander"),
74 Role::Admin => write!(f, "Admin"),
75 }
76 }
77}
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
83pub enum Permission {
84 JoinCell,
87 LeaveCell,
89 CreateCell,
91 DisbandCell,
93 SetCellLeader,
95 SetCellObjective,
97
98 AdvertiseCapability,
101 RequestCapability,
103
104 ReadCellState,
107 WriteCellState,
109 ReadNodeState,
111 WriteNodeState,
113 ReadTelemetry,
115
116 FormPlatoon,
119 AggregateToCompany,
121
122 ApproveFormation,
125 VetoCommand,
127
128 ConfigureNetwork,
131 ManageKeys,
133 ViewAuditLog,
135}
136
137impl fmt::Display for Permission {
138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139 match self {
140 Permission::JoinCell => write!(f, "JoinCell"),
141 Permission::LeaveCell => write!(f, "LeaveCell"),
142 Permission::CreateCell => write!(f, "CreateCell"),
143 Permission::DisbandCell => write!(f, "DisbandCell"),
144 Permission::SetCellLeader => write!(f, "SetCellLeader"),
145 Permission::SetCellObjective => write!(f, "SetCellObjective"),
146 Permission::AdvertiseCapability => write!(f, "AdvertiseCapability"),
147 Permission::RequestCapability => write!(f, "RequestCapability"),
148 Permission::ReadCellState => write!(f, "ReadCellState"),
149 Permission::WriteCellState => write!(f, "WriteCellState"),
150 Permission::ReadNodeState => write!(f, "ReadNodeState"),
151 Permission::WriteNodeState => write!(f, "WriteNodeState"),
152 Permission::ReadTelemetry => write!(f, "ReadTelemetry"),
153 Permission::FormPlatoon => write!(f, "FormPlatoon"),
154 Permission::AggregateToCompany => write!(f, "AggregateToCompany"),
155 Permission::ApproveFormation => write!(f, "ApproveFormation"),
156 Permission::VetoCommand => write!(f, "VetoCommand"),
157 Permission::ConfigureNetwork => write!(f, "ConfigureNetwork"),
158 Permission::ManageKeys => write!(f, "ManageKeys"),
159 Permission::ViewAuditLog => write!(f, "ViewAuditLog"),
160 }
161 }
162}
163
164#[derive(Debug, Clone)]
166pub enum AuthenticatedEntity {
167 Device(DeviceIdentityInfo),
169
170 User(UserIdentityInfo),
172}
173
174impl AuthenticatedEntity {
175 pub fn id(&self) -> String {
177 match self {
178 AuthenticatedEntity::Device(info) => info.device_id.to_hex(),
179 AuthenticatedEntity::User(info) => info.username.clone(),
180 }
181 }
182
183 pub fn from_device_id(device_id: DeviceId) -> Self {
185 AuthenticatedEntity::Device(DeviceIdentityInfo {
186 device_id,
187 device_type: DeviceType::Unknown,
188 })
189 }
190}
191
192#[derive(Debug, Clone)]
194pub struct DeviceIdentityInfo {
195 pub device_id: DeviceId,
197
198 pub device_type: DeviceType,
200}
201
202#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
204pub enum DeviceType {
205 Uav,
207 Ugv,
209 C2Station,
211 Sensor,
213 Relay,
215 Unknown,
217}
218
219#[derive(Debug, Clone)]
221pub struct UserIdentityInfo {
222 pub username: String,
224
225 pub roles: HashSet<Role>,
227}
228
229#[derive(Debug, Clone)]
233pub struct AuthorizationContext {
234 pub cell_id: Option<String>,
236
237 pub node_id: Option<String>,
239
240 pub hierarchy_level: Option<HierarchyLevel>,
242
243 pub timestamp: SystemTime,
245
246 pub cell_membership: Option<CellMembershipContext>,
248}
249
250impl AuthorizationContext {
251 pub fn for_cell(cell_id: &str) -> Self {
253 Self {
254 cell_id: Some(cell_id.to_string()),
255 node_id: None,
256 hierarchy_level: Some(HierarchyLevel::Squad),
257 timestamp: SystemTime::now(),
258 cell_membership: None,
259 }
260 }
261
262 pub fn for_node(node_id: &str) -> Self {
264 Self {
265 cell_id: None,
266 node_id: Some(node_id.to_string()),
267 hierarchy_level: None,
268 timestamp: SystemTime::now(),
269 cell_membership: None,
270 }
271 }
272
273 pub fn system() -> Self {
275 Self {
276 cell_id: None,
277 node_id: None,
278 hierarchy_level: None,
279 timestamp: SystemTime::now(),
280 cell_membership: None,
281 }
282 }
283
284 pub fn with_membership(mut self, membership: CellMembershipContext) -> Self {
286 self.cell_membership = Some(membership);
287 self
288 }
289}
290
291#[derive(Debug, Clone)]
293pub struct CellMembershipContext {
294 pub leader_id: Option<String>,
296
297 pub member_ids: HashSet<String>,
299}
300
301impl CellMembershipContext {
302 pub fn new(leader_id: Option<String>, member_ids: HashSet<String>) -> Self {
304 Self {
305 leader_id,
306 member_ids,
307 }
308 }
309
310 pub fn is_leader(&self, device_id: &str) -> bool {
312 self.leader_id.as_ref() == Some(&device_id.to_string())
313 }
314
315 pub fn is_member(&self, device_id: &str) -> bool {
317 self.member_ids.contains(device_id)
318 }
319}
320
321#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
323pub enum HierarchyLevel {
324 Node,
326 Squad,
328 Platoon,
330 Company,
332 Battalion,
334}
335
336#[derive(Debug, Clone)]
338pub struct AuthorizationPolicy {
339 role_permissions: HashMap<Role, HashSet<Permission>>,
341}
342
343impl AuthorizationPolicy {
344 pub fn new() -> Self {
346 Self {
347 role_permissions: HashMap::new(),
348 }
349 }
350
351 pub fn default_policy() -> Self {
355 let mut policy = Self::new();
356
357 policy.grant_role(Role::Leader, Permission::SetCellObjective);
359 policy.grant_role(Role::Leader, Permission::SetCellLeader);
360 policy.grant_role(Role::Leader, Permission::RequestCapability);
361 policy.grant_role(Role::Leader, Permission::ReadCellState);
362 policy.grant_role(Role::Leader, Permission::WriteCellState);
363 policy.grant_role(Role::Leader, Permission::ReadNodeState);
364 policy.grant_role(Role::Leader, Permission::WriteNodeState);
365 policy.grant_role(Role::Leader, Permission::ReadTelemetry);
366 policy.grant_role(Role::Leader, Permission::DisbandCell);
367
368 policy.grant_role(Role::Member, Permission::JoinCell);
370 policy.grant_role(Role::Member, Permission::LeaveCell);
371 policy.grant_role(Role::Member, Permission::AdvertiseCapability);
372 policy.grant_role(Role::Member, Permission::ReadCellState);
373 policy.grant_role(Role::Member, Permission::WriteNodeState);
374 policy.grant_role(Role::Member, Permission::ReadNodeState);
375 policy.grant_role(Role::Member, Permission::ReadTelemetry);
376
377 policy.grant_role(Role::Observer, Permission::ReadCellState);
379 policy.grant_role(Role::Observer, Permission::ReadNodeState);
380 policy.grant_role(Role::Observer, Permission::ReadTelemetry);
381
382 policy.grant_role(Role::Commander, Permission::FormPlatoon);
384 policy.grant_role(Role::Commander, Permission::AggregateToCompany);
385 policy.grant_role(Role::Commander, Permission::ApproveFormation);
386 policy.grant_role(Role::Commander, Permission::VetoCommand);
387 policy.grant_role(Role::Commander, Permission::CreateCell);
388 policy.grant_role(Role::Commander, Permission::ReadCellState);
389 policy.grant_role(Role::Commander, Permission::WriteCellState);
390 policy.grant_role(Role::Commander, Permission::ReadNodeState);
391 policy.grant_role(Role::Commander, Permission::ReadTelemetry);
392
393 policy.grant_role(Role::Admin, Permission::ConfigureNetwork);
395 policy.grant_role(Role::Admin, Permission::ManageKeys);
396 policy.grant_role(Role::Admin, Permission::ViewAuditLog);
397 policy.grant_role(Role::Admin, Permission::CreateCell);
398 policy.grant_role(Role::Admin, Permission::DisbandCell);
399
400 policy
401 }
402
403 pub fn grant_role(&mut self, role: Role, permission: Permission) {
405 self.role_permissions
406 .entry(role)
407 .or_default()
408 .insert(permission);
409 }
410
411 pub fn revoke_role(&mut self, role: Role, permission: Permission) {
413 if let Some(permissions) = self.role_permissions.get_mut(&role) {
414 permissions.remove(&permission);
415 }
416 }
417
418 pub fn role_has_permission(&self, role: Role, permission: Permission) -> bool {
420 self.role_permissions
421 .get(&role)
422 .is_some_and(|perms| perms.contains(&permission))
423 }
424
425 pub fn get_permissions(&self, role: Role) -> HashSet<Permission> {
427 self.role_permissions
428 .get(&role)
429 .cloned()
430 .unwrap_or_default()
431 }
432}
433
434impl Default for AuthorizationPolicy {
435 fn default() -> Self {
436 Self::default_policy()
437 }
438}
439
440#[derive(Debug)]
445pub struct AuthorizationController {
446 policy: AuthorizationPolicy,
448}
449
450impl AuthorizationController {
451 pub fn new(policy: AuthorizationPolicy) -> Self {
453 Self { policy }
454 }
455
456 pub fn with_default_policy() -> Self {
458 Self::new(AuthorizationPolicy::default_policy())
459 }
460
461 pub fn check_permission(
465 &self,
466 entity: &AuthenticatedEntity,
467 permission: Permission,
468 context: &AuthorizationContext,
469 ) -> Result<(), SecurityError> {
470 let roles = self.get_roles(entity, context);
472
473 let granted = roles
475 .iter()
476 .any(|role| self.policy.role_has_permission(*role, permission));
477
478 if granted {
479 Ok(())
480 } else {
481 Err(SecurityError::PermissionDenied {
482 permission: permission.to_string(),
483 entity_id: entity.id(),
484 roles: roles.iter().map(|r| r.to_string()).collect(),
485 })
486 }
487 }
488
489 pub fn get_roles(
491 &self,
492 entity: &AuthenticatedEntity,
493 context: &AuthorizationContext,
494 ) -> HashSet<Role> {
495 let mut roles = HashSet::new();
496
497 match entity {
498 AuthenticatedEntity::Device(device_info) => {
499 if let Some(membership) = &context.cell_membership {
501 let device_hex = device_info.device_id.to_hex();
502
503 if membership.is_leader(&device_hex) {
504 roles.insert(Role::Leader);
505 } else if membership.is_member(&device_hex) {
506 roles.insert(Role::Member);
507 } else {
508 roles.insert(Role::Observer);
510 }
511 } else {
512 roles.insert(Role::Observer);
514 }
515 }
516 AuthenticatedEntity::User(user_info) => {
517 roles = user_info.roles.clone();
519 }
520 }
521
522 roles
523 }
524
525 pub fn policy(&self) -> &AuthorizationPolicy {
527 &self.policy
528 }
529}
530
531impl Default for AuthorizationController {
532 fn default() -> Self {
533 Self::with_default_policy()
534 }
535}
536
537#[cfg(test)]
538mod tests {
539 use super::*;
540
541 fn test_device_id() -> DeviceId {
542 let keypair = crate::security::DeviceKeypair::generate();
543 keypair.device_id()
544 }
545
546 #[test]
547 fn test_role_display() {
548 assert_eq!(Role::Leader.to_string(), "Leader");
549 assert_eq!(Role::Member.to_string(), "Member");
550 assert_eq!(Role::Observer.to_string(), "Observer");
551 assert_eq!(Role::Commander.to_string(), "Commander");
552 assert_eq!(Role::Admin.to_string(), "Admin");
553 }
554
555 #[test]
556 fn test_permission_display() {
557 assert_eq!(Permission::JoinCell.to_string(), "JoinCell");
558 assert_eq!(Permission::SetCellObjective.to_string(), "SetCellObjective");
559 }
560
561 #[test]
562 fn test_default_policy_leader_permissions() {
563 let policy = AuthorizationPolicy::default_policy();
564
565 assert!(policy.role_has_permission(Role::Leader, Permission::SetCellObjective));
567 assert!(policy.role_has_permission(Role::Leader, Permission::SetCellLeader));
568 assert!(policy.role_has_permission(Role::Leader, Permission::WriteCellState));
569
570 assert!(!policy.role_has_permission(Role::Leader, Permission::ConfigureNetwork));
572 assert!(!policy.role_has_permission(Role::Leader, Permission::ManageKeys));
573 }
574
575 #[test]
576 fn test_default_policy_member_permissions() {
577 let policy = AuthorizationPolicy::default_policy();
578
579 assert!(policy.role_has_permission(Role::Member, Permission::JoinCell));
581 assert!(policy.role_has_permission(Role::Member, Permission::LeaveCell));
582 assert!(policy.role_has_permission(Role::Member, Permission::ReadCellState));
583
584 assert!(!policy.role_has_permission(Role::Member, Permission::SetCellObjective));
586 assert!(!policy.role_has_permission(Role::Member, Permission::SetCellLeader));
587 }
588
589 #[test]
590 fn test_default_policy_observer_permissions() {
591 let policy = AuthorizationPolicy::default_policy();
592
593 assert!(policy.role_has_permission(Role::Observer, Permission::ReadCellState));
595 assert!(policy.role_has_permission(Role::Observer, Permission::ReadNodeState));
596 assert!(policy.role_has_permission(Role::Observer, Permission::ReadTelemetry));
597
598 assert!(!policy.role_has_permission(Role::Observer, Permission::WriteCellState));
600 assert!(!policy.role_has_permission(Role::Observer, Permission::WriteNodeState));
601 }
602
603 #[test]
604 fn test_custom_policy() {
605 let mut policy = AuthorizationPolicy::new();
606
607 assert!(!policy.role_has_permission(Role::Member, Permission::CreateCell));
609
610 policy.grant_role(Role::Member, Permission::CreateCell);
612 assert!(policy.role_has_permission(Role::Member, Permission::CreateCell));
613
614 policy.revoke_role(Role::Member, Permission::CreateCell);
616 assert!(!policy.role_has_permission(Role::Member, Permission::CreateCell));
617 }
618
619 #[test]
620 fn test_authorization_controller_leader() {
621 let controller = AuthorizationController::with_default_policy();
622 let device_id = test_device_id();
623 let device_hex = device_id.to_hex();
624
625 let entity = AuthenticatedEntity::from_device_id(device_id);
626
627 let membership = CellMembershipContext::new(Some(device_hex), HashSet::new());
629 let context = AuthorizationContext::for_cell("test-cell").with_membership(membership);
630
631 assert!(controller
633 .check_permission(&entity, Permission::SetCellObjective, &context)
634 .is_ok());
635
636 assert!(controller
638 .check_permission(&entity, Permission::WriteCellState, &context)
639 .is_ok());
640
641 assert!(controller
643 .check_permission(&entity, Permission::ConfigureNetwork, &context)
644 .is_err());
645 }
646
647 #[test]
648 fn test_authorization_controller_member() {
649 let controller = AuthorizationController::with_default_policy();
650 let device_id = test_device_id();
651 let device_hex = device_id.to_hex();
652
653 let entity = AuthenticatedEntity::from_device_id(device_id);
654
655 let mut members = HashSet::new();
657 members.insert(device_hex);
658 let membership = CellMembershipContext::new(Some("other-leader".to_string()), members);
659 let context = AuthorizationContext::for_cell("test-cell").with_membership(membership);
660
661 assert!(controller
663 .check_permission(&entity, Permission::ReadCellState, &context)
664 .is_ok());
665
666 assert!(controller
668 .check_permission(&entity, Permission::WriteNodeState, &context)
669 .is_ok());
670
671 assert!(controller
673 .check_permission(&entity, Permission::SetCellObjective, &context)
674 .is_err());
675 }
676
677 #[test]
678 fn test_authorization_controller_observer() {
679 let controller = AuthorizationController::with_default_policy();
680 let device_id = test_device_id();
681
682 let entity = AuthenticatedEntity::from_device_id(device_id);
683
684 let membership =
686 CellMembershipContext::new(Some("some-leader".to_string()), HashSet::new());
687 let context = AuthorizationContext::for_cell("test-cell").with_membership(membership);
688
689 assert!(controller
691 .check_permission(&entity, Permission::ReadCellState, &context)
692 .is_ok());
693
694 assert!(controller
696 .check_permission(&entity, Permission::WriteCellState, &context)
697 .is_err());
698
699 assert!(controller
701 .check_permission(&entity, Permission::JoinCell, &context)
702 .is_err());
703 }
704
705 #[test]
706 fn test_authorization_controller_user_roles() {
707 let controller = AuthorizationController::with_default_policy();
708
709 let mut roles = HashSet::new();
710 roles.insert(Role::Commander);
711
712 let entity = AuthenticatedEntity::User(UserIdentityInfo {
713 username: "commander_alpha".to_string(),
714 roles,
715 });
716
717 let context = AuthorizationContext::for_cell("test-cell");
718
719 assert!(controller
721 .check_permission(&entity, Permission::ApproveFormation, &context)
722 .is_ok());
723
724 assert!(controller
726 .check_permission(&entity, Permission::FormPlatoon, &context)
727 .is_ok());
728
729 assert!(controller
731 .check_permission(&entity, Permission::ManageKeys, &context)
732 .is_err());
733 }
734
735 #[test]
736 fn test_get_roles_returns_correct_roles() {
737 let controller = AuthorizationController::with_default_policy();
738 let device_id = test_device_id();
739 let device_hex = device_id.to_hex();
740
741 let entity = AuthenticatedEntity::from_device_id(device_id);
742
743 let membership = CellMembershipContext::new(Some(device_hex.clone()), HashSet::new());
745 let context = AuthorizationContext::for_cell("test-cell").with_membership(membership);
746 let roles = controller.get_roles(&entity, &context);
747 assert!(roles.contains(&Role::Leader));
748 assert!(!roles.contains(&Role::Member));
749
750 let mut members = HashSet::new();
752 members.insert(device_hex);
753 let membership = CellMembershipContext::new(Some("other".to_string()), members);
754 let context = AuthorizationContext::for_cell("test-cell").with_membership(membership);
755 let roles = controller.get_roles(&entity, &context);
756 assert!(roles.contains(&Role::Member));
757 assert!(!roles.contains(&Role::Leader));
758 }
759
760 #[test]
761 fn test_permission_denied_error_contains_details() {
762 let controller = AuthorizationController::with_default_policy();
763 let device_id = test_device_id();
764
765 let entity = AuthenticatedEntity::from_device_id(device_id);
766 let context = AuthorizationContext::system();
767
768 let result = controller.check_permission(&entity, Permission::ConfigureNetwork, &context);
769 assert!(result.is_err());
770
771 if let Err(SecurityError::PermissionDenied {
772 permission,
773 entity_id,
774 ..
775 }) = result
776 {
777 assert_eq!(permission, "ConfigureNetwork");
778 assert!(!entity_id.is_empty());
779 } else {
780 panic!("Expected PermissionDenied error");
781 }
782 }
783}