use crate::auth::types::{Permission, PermissionBounds};
pub fn clamp_permission(delegated_permission: Permission, bounds: &PermissionBounds) -> Permission {
if !validate_permission_bounds(bounds) {
tracing::warn!(
"Invalid permission bounds detected (min > max). Applying only max bound as fallback."
);
if delegated_permission > bounds.max {
return bounds.max.clone();
}
return delegated_permission;
}
if delegated_permission > bounds.max {
return bounds.max.clone();
}
if let Some(min) = &bounds.min
&& delegated_permission < *min
{
return min.clone();
}
delegated_permission
}
pub fn validate_permission_bounds(bounds: &PermissionBounds) -> bool {
if let Some(min) = &bounds.min {
min <= &bounds.max
} else {
true }
}
pub fn can_delegate_with_bounds(
delegating_permission: &Permission,
bounds: &PermissionBounds,
) -> bool {
if bounds.max > *delegating_permission {
return false;
}
validate_permission_bounds(bounds)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_clamp_permission_max_bound() {
let bounds = PermissionBounds {
max: Permission::Write(10),
min: None,
};
let result = clamp_permission(Permission::Admin(5), &bounds);
assert_eq!(result, Permission::Write(10));
let result = clamp_permission(Permission::Write(20), &bounds);
assert_eq!(result, Permission::Write(20));
let result = clamp_permission(Permission::Write(5), &bounds);
assert_eq!(result, Permission::Write(10));
let result = clamp_permission(Permission::Read, &bounds);
assert_eq!(result, Permission::Read);
}
#[test]
fn test_clamp_permission_min_bound() {
let bounds = PermissionBounds {
max: Permission::Admin(5),
min: Some(Permission::Write(10)),
};
let result = clamp_permission(Permission::Admin(5), &bounds);
assert_eq!(result, Permission::Admin(5));
let result = clamp_permission(Permission::Write(15), &bounds);
assert_eq!(result, Permission::Write(10));
let result = clamp_permission(Permission::Write(5), &bounds);
assert_eq!(result, Permission::Write(5));
let result = clamp_permission(Permission::Read, &bounds);
assert_eq!(result, Permission::Write(10));
}
#[test]
fn test_clamp_permission_both_bounds() {
let bounds = PermissionBounds {
max: Permission::Write(5), min: Some(Permission::Write(15)), };
let result = clamp_permission(Permission::Admin(1), &bounds);
assert_eq!(result, Permission::Write(5));
let result = clamp_permission(Permission::Write(20), &bounds);
assert_eq!(result, Permission::Write(15));
let result = clamp_permission(Permission::Write(12), &bounds);
assert_eq!(result, Permission::Write(12));
let result = clamp_permission(Permission::Write(3), &bounds);
assert_eq!(result, Permission::Write(5));
let result = clamp_permission(Permission::Read, &bounds);
assert_eq!(result, Permission::Write(15));
}
#[test]
fn test_validate_permission_bounds_valid() {
let bounds = PermissionBounds {
max: Permission::Write(10),
min: None,
};
assert!(validate_permission_bounds(&bounds));
let bounds = PermissionBounds {
max: Permission::Write(10),
min: Some(Permission::Write(10)),
};
assert!(validate_permission_bounds(&bounds));
let bounds = PermissionBounds {
max: Permission::Admin(5),
min: Some(Permission::Write(10)),
};
assert!(validate_permission_bounds(&bounds));
}
#[test]
fn test_validate_permission_bounds_invalid() {
let bounds = PermissionBounds {
max: Permission::Write(10),
min: Some(Permission::Admin(5)),
};
assert!(!validate_permission_bounds(&bounds));
let bounds = PermissionBounds {
max: Permission::Read,
min: Some(Permission::Write(10)),
};
assert!(!validate_permission_bounds(&bounds));
}
#[test]
fn test_can_delegate_with_bounds_valid() {
let delegating_permission = Permission::Admin(5);
let bounds = PermissionBounds {
max: Permission::Write(10),
min: Some(Permission::Read),
};
assert!(can_delegate_with_bounds(&delegating_permission, &bounds));
let bounds = PermissionBounds {
max: Permission::Admin(5),
min: None,
};
assert!(can_delegate_with_bounds(&delegating_permission, &bounds));
}
#[test]
fn test_can_delegate_with_bounds_invalid() {
let delegating_permission = Permission::Write(10);
let bounds = PermissionBounds {
max: Permission::Admin(5),
min: None,
};
assert!(!can_delegate_with_bounds(&delegating_permission, &bounds));
let bounds = PermissionBounds {
max: Permission::Write(20),
min: Some(Permission::Admin(1)),
};
assert!(!can_delegate_with_bounds(&delegating_permission, &bounds));
let bounds = PermissionBounds {
max: Permission::Write(5), min: Some(Permission::Read),
};
assert!(!can_delegate_with_bounds(&delegating_permission, &bounds));
}
#[test]
fn test_permission_clamping_edge_cases() {
let bounds = PermissionBounds {
max: Permission::Write(10),
min: Some(Permission::Write(10)),
};
let result = clamp_permission(Permission::Write(10), &bounds);
assert_eq!(result, Permission::Write(10));
let result = clamp_permission(Permission::Admin(5), &bounds);
assert_eq!(result, Permission::Write(10));
let result = clamp_permission(Permission::Read, &bounds);
assert_eq!(result, Permission::Write(10));
}
#[test]
fn test_permission_priority_clamping() {
let bounds = PermissionBounds {
max: Permission::Write(5),
min: Some(Permission::Write(15)),
};
let result = clamp_permission(Permission::Write(12), &bounds);
assert_eq!(result, Permission::Write(12));
let result = clamp_permission(Permission::Write(20), &bounds);
assert_eq!(result, Permission::Write(15));
let result = clamp_permission(Permission::Write(3), &bounds);
assert_eq!(result, Permission::Write(5));
}
}