use rocketmq_security_api::Action;
use super::environment::Environment;
use super::resource::Resource;
use crate::authorization::enums::decision::Decision;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PolicyEntry {
resource: Resource,
actions: Vec<Action>,
environment: Option<Environment>,
decision: Decision,
}
impl PolicyEntry {
pub fn of(resource: Resource, actions: Vec<Action>, environment: Option<Environment>, decision: Decision) -> Self {
Self {
resource,
actions,
environment,
decision,
}
}
pub fn update_entry(&mut self, actions: Vec<Action>, environment: Option<Environment>, decision: Decision) {
self.actions = actions;
self.environment = environment;
self.decision = decision;
}
pub fn is_match_resource(&self, resource: &Resource) -> bool {
self.resource.is_match(resource)
}
pub fn is_match_action(&self, actions: &[Action]) -> bool {
if self.actions.is_empty() {
return false;
}
if actions.contains(&Action::Any) {
return true;
}
let contains_all = self.actions.contains(&Action::All);
actions
.iter()
.any(|a| self.actions.iter().any(|sa| sa == a) || contains_all)
}
pub fn is_match_environment(&self, environment: &Environment) -> bool {
match &self.environment {
None => true,
Some(env) => env.is_match(environment),
}
}
pub fn to_resource_str(&self) -> Option<String> {
self.resource.resource_key()
}
pub fn to_actions_str(&self) -> Option<Vec<String>> {
if self.actions.is_empty() {
return None;
}
Some(
self.actions
.iter()
.map(|a| a.name().to_string())
.collect::<Vec<String>>(),
)
}
pub fn resource(&self) -> &Resource {
&self.resource
}
pub fn set_resource(&mut self, r: Resource) {
self.resource = r;
}
pub fn actions(&self) -> &Vec<Action> {
&self.actions
}
pub fn set_actions(&mut self, a: Vec<Action>) {
self.actions = a;
}
pub fn environment(&self) -> Option<&Environment> {
self.environment.as_ref()
}
pub fn set_environment(&mut self, e: Option<Environment>) {
self.environment = e;
}
pub fn decision(&self) -> Decision {
self.decision
}
pub fn set_decision(&mut self, d: Decision) {
self.decision = d;
}
}
#[cfg(test)]
mod tests {
use rocketmq_security_api::Action;
use rocketmq_security_api::ResourceType;
use super::*;
use crate::authorization::enums::decision::Decision;
use crate::authorization::model::resource::Resource;
#[test]
fn test_of_and_to_strings() {
let r = Resource::of(
ResourceType::Topic,
Some("foo".to_string()),
rocketmq_security_api::ResourcePattern::Literal,
);
let p = PolicyEntry::of(r.clone(), vec![Action::Pub, Action::Sub], None, Decision::Allow);
assert_eq!(p.to_resource_str(), Some("Topic:foo".to_string()));
assert_eq!(p.to_actions_str().unwrap(), vec!["Pub".to_string(), "Sub".to_string()]);
assert_eq!(p.decision(), Decision::Allow);
}
#[test]
fn test_is_match_action_any_and_all() {
let r = Resource::of(
ResourceType::Topic,
Some("x".to_string()),
rocketmq_security_api::ResourcePattern::Literal,
);
let p = PolicyEntry::of(r, vec![Action::Pub, Action::Sub], None, Decision::Allow);
assert!(p.is_match_action(&[Action::Pub]));
assert!(!p.is_match_action(&[Action::Create]));
assert!(p.is_match_action(&[Action::Any]));
let r2 = Resource::of(
ResourceType::Topic,
Some("x".to_string()),
rocketmq_security_api::ResourcePattern::Literal,
);
let p2 = PolicyEntry::of(r2, vec![Action::All], None, Decision::Allow);
assert!(p2.is_match_action(&[Action::Create]));
}
#[test]
fn test_is_match_resource_and_environment() {
let rule = PolicyEntry::of(
Resource::of(
ResourceType::Topic,
Some("pre".to_string()),
rocketmq_security_api::ResourcePattern::Prefixed,
),
vec![Action::Pub],
Some(crate::authorization::model::environment::Environment::of("1.2.3.4").unwrap()),
Decision::Allow,
);
let res = Resource::of(
ResourceType::Topic,
Some("prefix_val".to_string()),
rocketmq_security_api::ResourcePattern::Literal,
);
assert!(rule.is_match_resource(&res));
assert!(
rule.is_match_environment(&crate::authorization::model::environment::Environment::of("1.2.3.4").unwrap())
);
assert!(
!rule.is_match_environment(&crate::authorization::model::environment::Environment::of("8.8.8.8").unwrap())
);
}
}