Skip to main content

rocketmq_auth/authorization/model/
policy.rs

1// Copyright 2023 The RocketMQ Rust Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use rocketmq_security_api::Action;
16
17use super::environment::Environment;
18use super::policy_entry::PolicyEntry;
19use super::resource::Resource;
20use crate::authorization::enums::decision::Decision;
21use crate::authorization::enums::policy_type::PolicyType;
22
23#[derive(Clone, Debug, PartialEq, Eq)]
24pub struct Policy {
25    policy_type: PolicyType,
26    entries: Vec<PolicyEntry>,
27}
28
29impl Policy {
30    pub fn of(
31        resources: Vec<Resource>,
32        actions: Vec<Action>,
33        environment: Option<Environment>,
34        decision: Decision,
35    ) -> Self {
36        Self::of_type(PolicyType::Custom, resources, actions, environment, decision)
37    }
38
39    pub fn of_type(
40        policy_type: PolicyType,
41        resources: Vec<Resource>,
42        actions: Vec<Action>,
43        environment: Option<Environment>,
44        decision: Decision,
45    ) -> Self {
46        let entries = resources
47            .into_iter()
48            .map(|r| PolicyEntry::of(r, actions.clone(), environment.clone(), decision))
49            .collect();
50        Policy { policy_type, entries }
51    }
52
53    pub fn of_entries(policy_type: PolicyType, entries: Vec<PolicyEntry>) -> Self {
54        Policy { policy_type, entries }
55    }
56
57    pub fn update_entry(&mut self, new_entries: Vec<PolicyEntry>) {
58        if self.entries.is_empty() {
59            self.entries = Vec::new();
60        }
61        for new_entry in new_entries {
62            match self.get_entry_mut(new_entry.resource()) {
63                None => self.entries.push(new_entry),
64                Some(entry) => entry.update_entry(
65                    new_entry.actions().clone(),
66                    new_entry.environment().cloned(),
67                    new_entry.decision(),
68                ),
69            }
70        }
71    }
72
73    pub fn delete_entry(&mut self, resource: &Resource) {
74        if let Some(pos) = self.entries.iter().position(|e| e.resource() == resource) {
75            self.entries.remove(pos);
76        }
77    }
78
79    fn get_entry_mut(&mut self, resource: &Resource) -> Option<&mut PolicyEntry> {
80        self.entries.iter_mut().find(|e| e.resource() == resource)
81    }
82
83    // getters/setters
84    pub fn policy_type(&self) -> PolicyType {
85        self.policy_type
86    }
87
88    pub fn set_policy_type(&mut self, t: PolicyType) {
89        self.policy_type = t;
90    }
91
92    pub fn entries(&self) -> &Vec<PolicyEntry> {
93        &self.entries
94    }
95
96    pub fn set_entries(&mut self, e: Vec<PolicyEntry>) {
97        self.entries = e;
98    }
99}
100
101#[cfg(test)]
102mod tests {
103    use rocketmq_security_api::Action;
104    use rocketmq_security_api::ResourcePattern;
105    use rocketmq_security_api::ResourceType;
106
107    use super::*;
108    use crate::authorization::enums::policy_type::PolicyType;
109
110    #[test]
111    fn test_of_and_update_delete() {
112        let r1 = Resource::of(ResourceType::Topic, Some("t1".to_string()), ResourcePattern::Literal);
113        let r2 = Resource::of(ResourceType::Topic, Some("t2".to_string()), ResourcePattern::Literal);
114        let mut p = Policy::of(vec![r1.clone()], vec![Action::Pub], None, Decision::Allow);
115        assert_eq!(p.entries().len(), 1);
116
117        // update: add r2
118        p.update_entry(vec![PolicyEntry::of(
119            r2.clone(),
120            vec![Action::Pub],
121            None,
122            Decision::Allow,
123        )]);
124        assert_eq!(p.entries().len(), 2);
125
126        // delete r1
127        p.delete_entry(&r1);
128        assert_eq!(p.entries().len(), 1);
129        assert!(p.entries().iter().all(|e| e.resource() != &r1));
130
131        // set entries directly
132        p.set_entries(vec![PolicyEntry::of(
133            r1.clone(),
134            vec![Action::Sub],
135            None,
136            Decision::Deny,
137        )]);
138        assert_eq!(p.entries().len(), 1);
139        assert_eq!(p.policy_type(), PolicyType::Custom);
140    }
141}