Merge "trivial: Fix irrelevant-files regexes for unit tests"
diff --git a/HACKING.rst b/HACKING.rst
index 9992017..9868e39 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -121,3 +121,34 @@
policies also applies to Patrole.
.. _Tempest logic: https://docs.openstack.org/tempest/latest/HACKING.html#new-tests-for-existing-features
+
+
+Black Box vs. White Box Testing
+-------------------------------
+
+Tempest is a `black box testing framework`_, meaning that it is concerned with
+testing public API endpoints and doesn't concern itself with testing internal
+implementation details. Patrole, as a Tempest plugin, also falls underneath
+the category of black box testing. However, even with policy in code
+documentation, some degree of white box testing is required in order to
+correctly write RBAC tests.
+
+This is because :ref:`policy-in-code` documentation, while useful in many
+respects, is usually quite brief and its main purpose is to help operators
+understand how to customize policy configuration rather than to help
+developers understand complex policy authorization work flows. For example,
+policy in code documentation doesn't make deriving
+:ref:`multiple policies <multiple-policies>` easy. Such documentation also
+doesn't usually mention that a specific parameter needs to be set, or that a
+particular microversion must be enabled, or that a particular set of
+prerequisite API or policy actions must be executed, in order for the policy
+under test to be enforced by the server. This means that test writers must
+account for the internal RBAC implementation in API code in order to correctly
+understand the complete RBAC work flow within an API.
+
+Besides, as mentioned :ref:`elsewhere <design-principles>` in this
+documentation, not all services currently implement policy in code, making
+some degree of white box testing a "necessary evil" for writing robust RBAC
+tests.
+
+.. _black box testing framework: https://docs.openstack.org/tempest/latest/HACKING.html#negative-tests
diff --git a/README.rst b/README.rst
index 31cd3b7..5331445 100644
--- a/README.rst
+++ b/README.rst
@@ -202,8 +202,10 @@
**admin** and **member** roles. However, other services may use entirely
different roles or role combinations.
-For more information about the member role and its nomenclature,
-please see: `<https://ask.openstack.org/en/question/4759/member-vs-_member_/>`__.
+For more information about RBAC, reference the `rbac-overview`_
+documentation page.
+
+.. _rbac-overview: https://docs.openstack.org/patrole/latest/rbac-overview.html
Unit Tests
----------
diff --git a/doc/source/rbac-overview.rst b/doc/source/rbac-overview.rst
index acfd66f..cc47f75 100644
--- a/doc/source/rbac-overview.rst
+++ b/doc/source/rbac-overview.rst
@@ -1,3 +1,5 @@
+.. _rbac-overview:
+
==================================
Role-Based Access Control Overview
==================================
diff --git a/patrole_tempest_plugin/config.py b/patrole_tempest_plugin/config.py
index 90d5fba..62337f7 100644
--- a/patrole_tempest_plugin/config.py
+++ b/patrole_tempest_plugin/config.py
@@ -117,7 +117,7 @@
cfg.StrOpt('report_log_path',
default='.',
help="Path (relative or absolute) where the output from "
- "'enable_reporting' is logged. This is combined with"
+ "'enable_reporting' is logged. This is combined with "
"report_log_name to generate the full path."),
]
diff --git a/patrole_tempest_plugin/requirements_authority.py b/patrole_tempest_plugin/requirements_authority.py
index 4697c3b..4d6f25b 100644
--- a/patrole_tempest_plugin/requirements_authority.py
+++ b/patrole_tempest_plugin/requirements_authority.py
@@ -18,9 +18,10 @@
from oslo_log import log as logging
from tempest import config
-from tempest.lib import exceptions
+from tempest.lib import exceptions as lib_exc
from patrole_tempest_plugin.rbac_authority import RbacAuthority
+from patrole_tempest_plugin import rbac_exceptions
CONF = config.CONF
LOG = logging.getLogger(__name__)
@@ -81,7 +82,7 @@
except yaml.parser.ParserError:
LOG.error("Error while parsing the requirements YAML file. Did "
"you pass a valid component name from the test case?")
- return None
+ return {}
class RequirementsAuthority(RbacAuthority):
@@ -98,10 +99,10 @@
Defaults to ``[patrole].custom_requirements_file``.
:param str component: Name of the OpenStack service to be validated.
"""
- filepath = filepath or CONF.patrole.custom_requirements_file
-
+ self.filepath = filepath or CONF.patrole.custom_requirements_file
if component is not None:
- self.roles_dict = RequirementsParser(filepath).parse(component)
+ self.roles_dict = RequirementsParser(self.filepath).parse(
+ component)
else:
self.roles_dict = None
@@ -116,33 +117,34 @@
:returns: True if ``role`` is allowed to perform ``rule_name``, else
False.
:rtype: bool
- :raises KeyError: If ``rule_name`` does not exist among the keyed
- policy names in the custom requirements file.
+ :raises RbacParsingException: If ``rule_name`` does not exist among the
+ keyed policy names in the custom requirements file.
"""
- if self.roles_dict is None:
- raise exceptions.InvalidConfiguration(
+ if not self.roles_dict:
+ raise lib_exc.InvalidConfiguration(
"Roles dictionary parsed from requirements YAML file is "
"empty. Ensure the requirements YAML file is correctly "
"formatted.")
try:
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)
+ raise rbac_exceptions.RbacParsingException(
+ "'%s' rule name is not defined in the requirements YAML file: "
+ "%s" % (rule_name, self.filepath))
+
+ 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
diff --git a/patrole_tempest_plugin/tests/api/network/rbac_base.py b/patrole_tempest_plugin/tests/api/network/rbac_base.py
index 347651d..dc0ce7f 100644
--- a/patrole_tempest_plugin/tests/api/network/rbac_base.py
+++ b/patrole_tempest_plugin/tests/api/network/rbac_base.py
@@ -13,7 +13,10 @@
# License for the specific language governing permissions and limitations
# under the License.
+from oslo_serialization import jsonutils as json
+
from tempest.api.network import base as network_base
+from tempest.lib.common.utils import test_utils
from patrole_tempest_plugin import rbac_utils
@@ -72,3 +75,13 @@
cls.ntp_client = neutron_tempest_manager.network_client
return manager
+
+ @classmethod
+ def create_service_profile(cls):
+ service_profile = cls.ntp_client.create_service_profile(
+ metainfo=json.dumps({'foo': 'bar'}))
+ service_profile_id = service_profile["service_profile"]["id"]
+ cls.addClassResourceCleanup(
+ test_utils.call_and_ignore_notfound_exc,
+ cls.ntp_client.delete_service_profile, service_profile_id)
+ return service_profile_id
diff --git a/patrole_tempest_plugin/tests/api/network/test_flavor_service_profile_rbac.py b/patrole_tempest_plugin/tests/api/network/test_flavor_service_profile_rbac.py
new file mode 100644
index 0000000..db0b8f1
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/network/test_flavor_service_profile_rbac.py
@@ -0,0 +1,77 @@
+# Copyright 2018 AT&T Corporation.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.network import rbac_base as base
+
+
+class FlavorsServiceProfileExtRbacTest(base.BaseNetworkExtRbacTest):
+ @classmethod
+ def resource_setup(cls):
+ super(FlavorsServiceProfileExtRbacTest, cls).resource_setup()
+ providers = cls.ntp_client.list_service_providers()
+ if not providers["service_providers"]:
+ raise cls.skipException("No service_providers available.")
+ cls.service_type = providers["service_providers"][0]["service_type"]
+
+ cls.flavor_id = cls.create_flavor()
+ cls.service_profile_id = cls.create_service_profile()
+
+ @classmethod
+ def create_flavor(cls):
+ flavor = cls.ntp_client.create_flavor(service_type=cls.service_type)
+ flavor_id = flavor["flavor"]["id"]
+ cls.addClassResourceCleanup(
+ test_utils.call_and_ignore_notfound_exc,
+ cls.ntp_client.delete_flavor, flavor_id)
+ return flavor_id
+
+ def create_flavor_service_profile(self, flavor_id, service_profile_id):
+ self.ntp_client.create_flavor_service_profile(
+ flavor_id, service_profile_id)
+ self.addCleanup(
+ test_utils.call_and_ignore_notfound_exc,
+ self.ntp_client.delete_flavor_service_profile,
+ flavor_id, service_profile_id)
+
+ @decorators.idempotent_id('aa84b4c5-0dd6-4c34-aa81-3a76507f9b81')
+ @rbac_rule_validation.action(service="neutron",
+ rules=["create_flavor_service_profile"])
+ def test_create_flavor_service_profile(self):
+ """Create flavor_service_profile.
+
+ RBAC test for the neutron "create_flavor_service_profile" policy
+ """
+ with self.rbac_utils.override_role(self):
+ self.create_flavor_service_profile(self.flavor_id,
+ self.service_profile_id)
+
+ @decorators.idempotent_id('3b680d9e-946a-4670-ab7f-0e4576675833')
+ @rbac_rule_validation.action(service="neutron",
+ rules=["delete_flavor_service_profile"])
+ def test_delete_flavor_service_profile(self):
+ """Delete flavor_service_profile.
+
+ RBAC test for the neutron "delete_flavor_service_profile" policy
+ """
+ self.create_flavor_service_profile(self.flavor_id,
+ self.service_profile_id)
+
+ with self.rbac_utils.override_role(self):
+ self.ntp_client.delete_flavor_service_profile(
+ self.flavor_id, self.service_profile_id)
diff --git a/patrole_tempest_plugin/tests/api/network/test_flavors_rbac.py b/patrole_tempest_plugin/tests/api/network/test_flavors_rbac.py
index dea95ba..76c0db3 100644
--- a/patrole_tempest_plugin/tests/api/network/test_flavors_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_flavors_rbac.py
@@ -13,8 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-from oslo_serialization import jsonutils as json
-
from tempest.lib.common.utils import data_utils
from tempest.lib.common.utils import test_utils
from tempest.lib import decorators
@@ -118,72 +116,3 @@
with self.rbac_utils.override_role(self):
self.ntp_client.list_flavors()
-
-
-class FlavorsServiceProfileExtRbacTest(base.BaseNetworkExtRbacTest):
- @classmethod
- def resource_setup(cls):
- super(FlavorsServiceProfileExtRbacTest, cls).resource_setup()
- providers = cls.ntp_client.list_service_providers()
- if not providers["service_providers"]:
- raise cls.skipException("No service_providers available.")
- cls.service_type = providers["service_providers"][0]["service_type"]
-
- cls.flavor_id = cls.create_flavor()
- cls.service_profile_id = cls.create_service_profile()
-
- @classmethod
- def create_flavor(cls):
- flavor = cls.ntp_client.create_flavor(service_type=cls.service_type)
- flavor_id = flavor["flavor"]["id"]
- cls.addClassResourceCleanup(
- test_utils.call_and_ignore_notfound_exc,
- cls.ntp_client.delete_flavor, flavor_id)
- return flavor_id
-
- @classmethod
- def create_service_profile(cls):
- service_profile = cls.ntp_client.create_service_profile(
- metainfo=json.dumps({'foo': 'bar'}))
- service_profile_id = service_profile["service_profile"]["id"]
- cls.addClassResourceCleanup(
- test_utils.call_and_ignore_notfound_exc,
- cls.ntp_client.delete_service_profile, service_profile_id)
- return service_profile_id
-
- def create_flavor_service_profile(self, flavor_id, service_profile_id):
- self.ntp_client.create_flavor_service_profile(
- flavor_id, service_profile_id)
- self.addCleanup(
- test_utils.call_and_ignore_notfound_exc,
- self.ntp_client.delete_flavor_service_profile,
- flavor_id, service_profile_id)
-
- @decorators.idempotent_id('aa84b4c5-0dd6-4c34-aa81-3a76507f9b81')
- @rbac_rule_validation.action(service="neutron",
- rules=["create_flavor_service_profile"])
- def test_create_flavor_service_profile(self):
- """Create flavor_service_profile.
-
- RBAC test for the neutron "create_flavor_service_profile" policy
- """
- with self.rbac_utils.override_role(self):
- self.create_flavor_service_profile(self.flavor_id,
- self.service_profile_id)
-
- @decorators.idempotent_id('3b680d9e-946a-4670-ab7f-0e4576675833')
- @rbac_rule_validation.action(service="neutron",
- rules=["get_flavor_service_profile",
- "delete_flavor_service_profile"],
- expected_error_codes=[404, 403])
- def test_delete_flavor_service_profile(self):
- """Delete flavor_service_profile.
-
- RBAC test for the neutron "delete_flavor_service_profile" policy
- """
- self.create_flavor_service_profile(self.flavor_id,
- self.service_profile_id)
-
- with self.rbac_utils.override_role(self):
- self.ntp_client.delete_flavor_service_profile(
- self.flavor_id, self.service_profile_id)
diff --git a/patrole_tempest_plugin/tests/api/network/test_service_profile_rbac.py b/patrole_tempest_plugin/tests/api/network/test_service_profile_rbac.py
new file mode 100644
index 0000000..9e82835
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/network/test_service_profile_rbac.py
@@ -0,0 +1,73 @@
+# Copyright 2018 AT&T Corporation.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.lib import decorators
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.network import rbac_base as base
+
+
+class ServiceProfileExtRbacTest(base.BaseNetworkExtRbacTest):
+ @decorators.idempotent_id('6ce76efa-7400-44c1-80ec-58f79b1d89ca')
+ @rbac_rule_validation.action(service="neutron",
+ rules=["create_service_profile"])
+ def test_create_service_profile(self):
+ """Create service profile
+
+ RBAC test for the neutron "create_service_profile" policy
+ """
+ with self.rbac_utils.override_role(self):
+ self.create_service_profile()
+
+ @decorators.idempotent_id('e4c473b7-3ae9-4a2e-8cac-848f7b01187d')
+ @rbac_rule_validation.action(service="neutron",
+ rules=["get_service_profile"],
+ expected_error_codes=[404])
+ def test_show_service_profile(self):
+ """Show service profile
+
+ RBAC test for the neutron "get_service_profile" policy
+ """
+ profile_id = self.create_service_profile()
+ with self.rbac_utils.override_role(self):
+ self.ntp_client.show_service_profile(profile_id)
+
+ @decorators.idempotent_id('a3dd719d-4cd3-40cc-b4f1-5642e2717adf')
+ @rbac_rule_validation.action(service="neutron",
+ rules=["get_service_profile",
+ "update_service_profile"],
+ expected_error_codes=[404, 403])
+ def test_update_service_profile(self):
+ """Update service profile
+
+ RBAC test for the neutron "update_service_profile" policy
+ """
+ profile_id = self.create_service_profile()
+ with self.rbac_utils.override_role(self):
+ self.ntp_client.update_service_profile(profile_id, enabled=False)
+
+ @decorators.idempotent_id('926b60c2-04fe-4339-aa44-bf27121392e8')
+ @rbac_rule_validation.action(service="neutron",
+ rules=["get_service_profile",
+ "delete_service_profile"],
+ expected_error_codes=[404, 403])
+ def test_delete_service_profile(self):
+ """Delete service profile
+
+ RBAC test for the neutron "delete_service_profile" policy
+ """
+ profile_id = self.create_service_profile()
+ with self.rbac_utils.override_role(self):
+ self.ntp_client.delete_service_profile(profile_id)
diff --git a/patrole_tempest_plugin/tests/unit/test_requirements_authority.py b/patrole_tempest_plugin/tests/unit/test_requirements_authority.py
index 0f7310e..94af81f 100644
--- a/patrole_tempest_plugin/tests/unit/test_requirements_authority.py
+++ b/patrole_tempest_plugin/tests/unit/test_requirements_authority.py
@@ -17,6 +17,7 @@
from tempest.lib import exceptions
from tempest.tests import base
+from patrole_tempest_plugin import rbac_exceptions
from patrole_tempest_plugin import requirements_authority as req_auth
@@ -50,17 +51,17 @@
self.rbac_auth.allowed, "", [""])
def test_auth_allowed_role_in_api(self):
- self.rbac_auth.roles_dict = {'api': [['_member_']]}
- self.assertTrue(self.rbac_auth.allowed("api", ["_member_"]))
+ self.rbac_auth.roles_dict = {'rule': [['_member_']]}
+ self.assertTrue(self.rbac_auth.allowed("rule", ["_member_"]))
def test_auth_allowed_role_not_in_api(self):
- self.rbac_auth.roles_dict = {'api': [['_member_']]}
- self.assertFalse(self.rbac_auth.allowed("api", "support_member"))
+ self.rbac_auth.roles_dict = {'rule': [['_member_']]}
+ self.assertFalse(self.rbac_auth.allowed("rule", "support_member"))
- def test_parser_get_allowed_except_keyerror(self):
- self.rbac_auth.roles_dict = {}
- self.assertRaises(KeyError, self.rbac_auth.allowed,
- "api", "support_member")
+ def test_parser_get_allowed_invalid_rule_raises_parsing_exception(self):
+ self.rbac_auth.roles_dict = {"foo": "bar"}
+ self.assertRaises(rbac_exceptions.RbacParsingException,
+ self.rbac_auth.allowed, "baz", "support_member")
def test_parser_init(self):
req_auth.RequirementsParser(self.yaml_test_file)
@@ -90,7 +91,7 @@
self.rbac_auth.roles_dict = \
req_auth.RequirementsParser.parse("Failure")
- self.assertIsNone(self.rbac_auth.roles_dict)
+ self.assertFalse(self.rbac_auth.roles_dict)
self.assertRaises(exceptions.InvalidConfiguration,
self.rbac_auth.allowed, "", [""])
@@ -99,10 +100,10 @@
considered as part of role itself.
"""
- self.rbac_auth.roles_dict = {'api': [['!admin']]}
- self.assertTrue(self.rbac_auth.allowed("api", ["member"]))
- self.assertTrue(self.rbac_auth.allowed("api", ["!admin"]))
- self.assertFalse(self.rbac_auth.allowed("api", ["admin"]))
+ self.rbac_auth.roles_dict = {'rule': [['!admin']]}
+ self.assertTrue(self.rbac_auth.allowed("rule", ["member"]))
+ self.assertTrue(self.rbac_auth.allowed("rule", ["!admin"]))
+ self.assertFalse(self.rbac_auth.allowed("rule", ["admin"]))
class RequirementsAuthorityMultiRoleTest(BaseRequirementsAuthorityTest):
@@ -112,39 +113,39 @@
considered as part of role itself.
"""
- self.rbac_auth.roles_dict = {'api': [['member', '!admin']]}
- self.assertFalse(self.rbac_auth.allowed("api", ["member", "admin"]))
- self.assertTrue(self.rbac_auth.allowed("api", ["member", "!admin"]))
+ self.rbac_auth.roles_dict = {'rule': [['member', '!admin']]}
+ self.assertFalse(self.rbac_auth.allowed("rule", ["member", "admin"]))
+ self.assertTrue(self.rbac_auth.allowed("rule", ["member", "!admin"]))
def test_auth_allowed_single_rule_scenario(self):
# member and support and not admin and not manager
- self.rbac_auth.roles_dict = {'api': [['member', 'support',
- '!admin', '!manager']]}
+ self.rbac_auth.roles_dict = {'rule': [['member', 'support',
+ '!admin', '!manager']]}
# User is member and support and not manager or admin
- self.assertTrue(self.rbac_auth.allowed("api", ["member",
- "support"]))
+ self.assertTrue(self.rbac_auth.allowed("rule", ["member",
+ "support"]))
# User is member and not manager or admin, but not support
- self.assertFalse(self.rbac_auth.allowed("api", ["member"]))
+ self.assertFalse(self.rbac_auth.allowed("rule", ["member"]))
# User is support and not manager or admin, but not member
- self.assertFalse(self.rbac_auth.allowed("api", ["support"]))
+ self.assertFalse(self.rbac_auth.allowed("rule", ["support"]))
# User is member and support and not manager, but have admin role
- self.assertFalse(self.rbac_auth.allowed("api", ["member",
- "support",
- "admin"]))
+ self.assertFalse(self.rbac_auth.allowed("rule", ["member",
+ "support",
+ "admin"]))
# User is member and not manager, but have admin role and not support
- self.assertFalse(self.rbac_auth.allowed("api", ["member",
- "admin"]))
+ self.assertFalse(self.rbac_auth.allowed("rule", ["member",
+ "admin"]))
# User is member and support, but have manager and admin roles
- self.assertFalse(self.rbac_auth.allowed("api", ["member",
- "support",
- "admin",
- "manager"]))
+ self.assertFalse(self.rbac_auth.allowed("rule", ["member",
+ "support",
+ "admin",
+ "manager"]))
def test_auth_allowed_multi_rule_scenario(self):
rules = [
@@ -152,36 +153,36 @@
['member', 'admin'],
["manager"]
]
- self.rbac_auth.roles_dict = {'api': rules}
+ self.rbac_auth.roles_dict = {'rule': rules}
# Not a single role allows viewer
- self.assertFalse(self.rbac_auth.allowed("api", ["viewer"]))
+ self.assertFalse(self.rbac_auth.allowed("rule", ["viewer"]))
# We have no rule that allows support and admin
- self.assertFalse(self.rbac_auth.allowed("api", ["support",
- "admin"]))
+ self.assertFalse(self.rbac_auth.allowed("rule", ["support",
+ "admin"]))
# There is no rule that requires member without additional requirements
- self.assertFalse(self.rbac_auth.allowed("api", ["member"]))
+ self.assertFalse(self.rbac_auth.allowed("rule", ["member"]))
# Pass with rules[2]
- self.assertTrue(self.rbac_auth.allowed("api", ["manager"]))
+ self.assertTrue(self.rbac_auth.allowed("rule", ["manager"]))
# Pass with rules[0]
- self.assertTrue(self.rbac_auth.allowed("api", ["member",
- "support"]))
+ self.assertTrue(self.rbac_auth.allowed("rule", ["member",
+ "support"]))
# Pass with rules[1]
- self.assertTrue(self.rbac_auth.allowed("api", ["member",
- "admin"]))
+ self.assertTrue(self.rbac_auth.allowed("rule", ["member",
+ "admin"]))
# Pass with rules[2]
- self.assertTrue(self.rbac_auth.allowed("api", ["manager",
- "admin"]))
+ self.assertTrue(self.rbac_auth.allowed("rule", ["manager",
+ "admin"]))
# Pass with rules[1]
- self.assertTrue(self.rbac_auth.allowed("api", ["member",
- "support",
- "admin"]))
+ self.assertTrue(self.rbac_auth.allowed("rule", ["member",
+ "support",
+ "admin"]))
# Pass with rules[1]
- self.assertTrue(self.rbac_auth.allowed("api", ["member",
- "support",
- "admin",
- "manager"]))
+ self.assertTrue(self.rbac_auth.allowed("rule", ["member",
+ "support",
+ "admin",
+ "manager"]))
# Pass with rules[2]
- self.assertTrue(self.rbac_auth.allowed("api", ["admin",
- "manager"]))
+ self.assertTrue(self.rbac_auth.allowed("rule", ["admin",
+ "manager"]))