RequirementsAuthority multi role support enhancement
This patchset eliminates different behaviour between
policy_authority and requirements_authority.
Problem description:
`rbac_test_roles = [member,]`
Policy authority:
`update_port: role:member and role:viewer`
Results in 403/False (we are member but not viewer).
Requirements authority:
```
req_auth:
update_port:
- member
- viewer
```
Results in 200/True (member in update_port list).
Proposed solution:
Change requirements_authority file sytax to support
comma separated roles to be considered as logical and.
Depends-On: https://review.openstack.org/#/c/606110/
Change-Id: I2e2a4a2020f5e85af15f1836d69386bc91a2d2ec
Co-Authored-By: Felipe Monteiro <felipe.monteiro@att.com>
diff --git a/patrole_tempest_plugin/requirements_authority.py b/patrole_tempest_plugin/requirements_authority.py
index 57caf79..4697c3b 100644
--- a/patrole_tempest_plugin/requirements_authority.py
+++ b/patrole_tempest_plugin/requirements_authority.py
@@ -12,6 +12,7 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
+import copy
import yaml
from oslo_log import log as logging
@@ -50,7 +51,7 @@
<service_foo>:
<api_action_a>:
- <allowed_role_1>
- - <allowed_role_2>
+ - <allowed_role_2>,<allowed_role_3>
- <allowed_role_3>
<api_action_b>:
- <allowed_role_2>
@@ -67,7 +68,16 @@
try:
for section in RequirementsParser.Inner._rbac_map:
if component in section:
- return section[component]
+ rules = copy.copy(section[component])
+
+ for rule in rules:
+ rules[rule] = [
+ roles.split(',') for roles in rules[rule]]
+
+ for i, role_pack in enumerate(rules[rule]):
+ rules[rule][i] = [r.strip() for r in role_pack]
+
+ return rules
except yaml.parser.ParserError:
LOG.error("Error while parsing the requirements YAML file. Did "
"you pass a valid component name from the test case?")
@@ -115,8 +125,24 @@
"empty. Ensure the requirements YAML file is correctly "
"formatted.")
try:
- _api = self.roles_dict[rule_name]
- return all(role in _api for role in roles)
+ requirement_roles = self.roles_dict[rule_name]
+
+ for role_reqs in requirement_roles:
+ required_roles = [
+ role for role in role_reqs if not role.startswith("!")]
+ forbidden_roles = [
+ role[1:] for role in role_reqs if role.startswith("!")]
+
+ # User must have all required roles
+ required_passed = all([r in roles for r in required_roles])
+ # User must not have any forbidden roles
+ forbidden_passed = all([r not in forbidden_roles
+ for r in roles])
+
+ if required_passed and forbidden_passed:
+ return True
+
+ return False
except KeyError:
raise KeyError("'%s' API is not defined in the requirements YAML "
"file" % rule_name)