Implement secure RBAC
The default policy will been replaced with one which aligns with the Secure-RBAC scopes and roles. Since ironic-inspector is a tool used only by system-level admins, only the ``system`` scope is supported, and the only roles in the policy rules are ``admin`` and ``reader``. The is_admin and is_observer rules are deprecated for removal, and every rule which refers to them are deprecated in favor of the system-scoped equivalent (system_scope:all with role:admin or role:reader) No unit tests covered the existing policy, these are now covered by test_acl.TestACLDeprecated. Change-Id: I4d038245c6b97b1504fb47eeec78ad3f9e5a897c
This commit is contained in:
parent
5c79d7552a
commit
c9e312f8b4
@ -16,6 +16,7 @@ import sys
|
||||
|
||||
from oslo_concurrency import lockutils
|
||||
from oslo_config import cfg
|
||||
from oslo_log import versionutils
|
||||
from oslo_policy import opts
|
||||
from oslo_policy import policy
|
||||
|
||||
@ -23,23 +24,52 @@ CONF = cfg.CONF
|
||||
|
||||
_ENFORCER = None
|
||||
|
||||
|
||||
# TODO(gmann): Remove setting the default value of config policy_file
|
||||
# once oslo_policy change the default value to 'policy.yaml'.
|
||||
# https://github.com/openstack/oslo.policy/blob/a626ad12fe5a3abd49d70e3e5b95589d279ab578/oslo_policy/opts.py#L49
|
||||
DEFAULT_POLICY_FILE = 'policy.yaml'
|
||||
opts.set_defaults(cfg.CONF, DEFAULT_POLICY_FILE)
|
||||
|
||||
# Generic policy check string for system administrators. These are the people
|
||||
# who need the highest level of authorization to operate the deployment.
|
||||
# They're allowed to create, read, update, or delete any system-specific
|
||||
# resource. They can also operate on project-specific resources where
|
||||
# applicable (e.g., cleaning up baremetal hosts)
|
||||
SYSTEM_ADMIN = 'role:admin and system_scope:all'
|
||||
|
||||
# Generic policy check string for system users who don't require all the
|
||||
# authorization that system administrators typically have. This persona, or
|
||||
# check string, typically isn't used by default, but it's existence it useful
|
||||
# in the event a deployment wants to offload some administrative action from
|
||||
# system administrator to system members
|
||||
SYSTEM_MEMBER = 'role:member and system_scope:all'
|
||||
|
||||
# Generic policy check string for read-only access to system-level resources.
|
||||
# This persona is useful for someone who needs access for auditing or even
|
||||
# support. These uses are also able to view project-specific resources where
|
||||
# applicable (e.g., listing all volumes in the deployment, regardless of the
|
||||
# project they belong to).
|
||||
SYSTEM_READER = 'role:reader and system_scope:all'
|
||||
|
||||
deprecated_node_reason = """
|
||||
The inspector API is now aware of system scope and default roles.
|
||||
"""
|
||||
|
||||
default_policies = [
|
||||
policy.RuleDefault(
|
||||
'is_admin',
|
||||
'role:admin or role:administrator or role:baremetal_admin',
|
||||
description='Full read/write API access'),
|
||||
description='Full read/write API access',
|
||||
deprecated_for_removal=True,
|
||||
deprecated_reason=deprecated_node_reason,
|
||||
deprecated_since=versionutils.deprecated.WALLABY),
|
||||
policy.RuleDefault(
|
||||
'is_observer',
|
||||
'role:baremetal_observer',
|
||||
description='Read-only API access'),
|
||||
description='Read-only API access',
|
||||
deprecated_for_removal=True,
|
||||
deprecated_reason=deprecated_node_reason,
|
||||
deprecated_since=versionutils.deprecated.WALLABY),
|
||||
policy.RuleDefault(
|
||||
'public_api',
|
||||
'is_public_api:True',
|
||||
@ -66,67 +96,126 @@ api_version_policies = [
|
||||
]
|
||||
|
||||
|
||||
deprecated_introspection_status = policy.DeprecatedRule(
|
||||
name='introspection:status',
|
||||
check_str='rule:is_admin or rule:is_observer'
|
||||
)
|
||||
deprecated_introspection_start = policy.DeprecatedRule(
|
||||
name='introspection:start',
|
||||
check_str='rule:is_admin'
|
||||
)
|
||||
deprecated_introspection_abort = policy.DeprecatedRule(
|
||||
name='introspection:abort',
|
||||
check_str='rule:is_admin'
|
||||
)
|
||||
deprecated_introspection_data = policy.DeprecatedRule(
|
||||
name='introspection:data',
|
||||
check_str='rule:is_admin'
|
||||
)
|
||||
deprecated_introspection_reapply = policy.DeprecatedRule(
|
||||
name='introspection:reapply',
|
||||
check_str='rule:is_admin'
|
||||
)
|
||||
deprecated_introspection_rule_get = policy.DeprecatedRule(
|
||||
name='introspection:rule:get',
|
||||
check_str='rule:is_admin'
|
||||
)
|
||||
deprecated_introspection_rule_delete = policy.DeprecatedRule(
|
||||
name='introspection:rule:delete',
|
||||
check_str='rule:is_admin'
|
||||
)
|
||||
deprecated_introspection_rule_create = policy.DeprecatedRule(
|
||||
name='introspection:rule:create',
|
||||
check_str='rule:is_admin'
|
||||
)
|
||||
|
||||
introspection_policies = [
|
||||
policy.DocumentedRuleDefault(
|
||||
'introspection:continue',
|
||||
'rule:public_api',
|
||||
'Ramdisk callback to continue introspection',
|
||||
[{'path': '/continue', 'method': 'POST'}]
|
||||
name='introspection:continue',
|
||||
check_str='rule:public_api',
|
||||
description='Ramdisk callback to continue introspection',
|
||||
operations=[{'path': '/continue', 'method': 'POST'}],
|
||||
),
|
||||
policy.DocumentedRuleDefault(
|
||||
'introspection:status',
|
||||
'rule:is_admin or rule:is_observer',
|
||||
'Get introspection status',
|
||||
[{'path': '/introspection', 'method': 'GET'},
|
||||
{'path': '/introspection/{node_id}', 'method': 'GET'}]
|
||||
name='introspection:status',
|
||||
check_str=SYSTEM_READER,
|
||||
description='Get introspection status',
|
||||
operations=[{'path': '/introspection', 'method': 'GET'},
|
||||
{'path': '/introspection/{node_id}', 'method': 'GET'}],
|
||||
deprecated_rule=deprecated_introspection_status,
|
||||
deprecated_reason=deprecated_node_reason,
|
||||
deprecated_since=versionutils.deprecated.WALLABY
|
||||
),
|
||||
policy.DocumentedRuleDefault(
|
||||
'introspection:start',
|
||||
'rule:is_admin',
|
||||
'Start introspection',
|
||||
[{'path': '/introspection/{node_id}', 'method': 'POST'}]
|
||||
name='introspection:start',
|
||||
check_str=SYSTEM_ADMIN,
|
||||
description='Start introspection',
|
||||
operations=[{'path': '/introspection/{node_id}', 'method': 'POST'}],
|
||||
deprecated_rule=deprecated_introspection_start,
|
||||
deprecated_reason=deprecated_node_reason,
|
||||
deprecated_since=versionutils.deprecated.WALLABY
|
||||
),
|
||||
policy.DocumentedRuleDefault(
|
||||
'introspection:abort',
|
||||
'rule:is_admin',
|
||||
'Abort introspection',
|
||||
[{'path': '/introspection/{node_id}/abort', 'method': 'POST'}]
|
||||
name='introspection:abort',
|
||||
check_str=SYSTEM_ADMIN,
|
||||
description='Abort introspection',
|
||||
operations=[{'path': '/introspection/{node_id}/abort',
|
||||
'method': 'POST'}],
|
||||
deprecated_rule=deprecated_introspection_abort,
|
||||
deprecated_reason=deprecated_node_reason,
|
||||
deprecated_since=versionutils.deprecated.WALLABY
|
||||
),
|
||||
policy.DocumentedRuleDefault(
|
||||
'introspection:data',
|
||||
'rule:is_admin',
|
||||
'Get introspection data',
|
||||
[{'path': '/introspection/{node_id}/data', 'method': 'GET'}]
|
||||
name='introspection:data',
|
||||
check_str=SYSTEM_ADMIN,
|
||||
description='Get introspection data',
|
||||
operations=[{'path': '/introspection/{node_id}/data',
|
||||
'method': 'GET'}],
|
||||
deprecated_rule=deprecated_introspection_data,
|
||||
deprecated_reason=deprecated_node_reason,
|
||||
deprecated_since=versionutils.deprecated.WALLABY
|
||||
),
|
||||
policy.DocumentedRuleDefault(
|
||||
'introspection:reapply',
|
||||
'rule:is_admin',
|
||||
'Reapply introspection on stored data',
|
||||
[{'path': '/introspection/{node_id}/data/unprocessed',
|
||||
'method': 'POST'}]
|
||||
name='introspection:reapply',
|
||||
check_str=SYSTEM_ADMIN,
|
||||
description='Reapply introspection on stored data',
|
||||
operations=[{'path': '/introspection/{node_id}/data/unprocessed',
|
||||
'method': 'POST'}],
|
||||
deprecated_rule=deprecated_introspection_reapply,
|
||||
deprecated_reason=deprecated_node_reason,
|
||||
deprecated_since=versionutils.deprecated.WALLABY
|
||||
),
|
||||
]
|
||||
|
||||
rule_policies = [
|
||||
policy.DocumentedRuleDefault(
|
||||
'introspection:rule:get',
|
||||
'rule:is_admin',
|
||||
'Get introspection rule(s)',
|
||||
[{'path': '/rules', 'method': 'GET'},
|
||||
{'path': '/rules/{rule_id}', 'method': 'GET'}]
|
||||
name='introspection:rule:get',
|
||||
check_str=SYSTEM_ADMIN,
|
||||
description='Get introspection rule(s)',
|
||||
operations=[{'path': '/rules', 'method': 'GET'},
|
||||
{'path': '/rules/{rule_id}', 'method': 'GET'}],
|
||||
deprecated_rule=deprecated_introspection_rule_get,
|
||||
deprecated_reason=deprecated_node_reason,
|
||||
deprecated_since=versionutils.deprecated.WALLABY
|
||||
),
|
||||
policy.DocumentedRuleDefault(
|
||||
'introspection:rule:delete',
|
||||
'rule:is_admin',
|
||||
'Delete introspection rule(s)',
|
||||
[{'path': '/rules', 'method': 'DELETE'},
|
||||
{'path': '/rules/{rule_id}', 'method': 'DELETE'}]
|
||||
name='introspection:rule:delete',
|
||||
check_str=SYSTEM_ADMIN,
|
||||
description='Delete introspection rule(s)',
|
||||
operations=[{'path': '/rules', 'method': 'DELETE'},
|
||||
{'path': '/rules/{rule_id}', 'method': 'DELETE'}],
|
||||
deprecated_rule=deprecated_introspection_rule_delete,
|
||||
deprecated_reason=deprecated_node_reason,
|
||||
deprecated_since=versionutils.deprecated.WALLABY
|
||||
),
|
||||
policy.DocumentedRuleDefault(
|
||||
'introspection:rule:create',
|
||||
'rule:is_admin',
|
||||
'Create introspection rule',
|
||||
[{'path': '/rules', 'method': 'POST'}]
|
||||
name='introspection:rule:create',
|
||||
check_str=SYSTEM_ADMIN,
|
||||
description='Create introspection rule',
|
||||
operations=[{'path': '/rules', 'method': 'POST'}],
|
||||
deprecated_rule=deprecated_introspection_rule_create,
|
||||
deprecated_reason=deprecated_node_reason,
|
||||
deprecated_since=versionutils.deprecated.WALLABY
|
||||
),
|
||||
]
|
||||
|
||||
|
438
ironic_inspector/test/unit/test_acl.py
Normal file
438
ironic_inspector/test/unit/test_acl.py
Normal file
@ -0,0 +1,438 @@
|
||||
# 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.
|
||||
|
||||
import datetime
|
||||
from unittest import mock
|
||||
import uuid
|
||||
|
||||
import fixtures
|
||||
from keystoneauth1.fixture import v3 as v3_token
|
||||
from keystonemiddleware import auth_token
|
||||
from oslo_config import cfg
|
||||
from oslo_context import context as oslo_context
|
||||
import oslo_messaging as messaging
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from ironic_inspector.common import rpc
|
||||
import ironic_inspector.conf
|
||||
from ironic_inspector import introspection_state as istate
|
||||
from ironic_inspector import main
|
||||
from ironic_inspector import node_cache
|
||||
from ironic_inspector.test import base as test_base
|
||||
|
||||
CONF = ironic_inspector.conf.CONF
|
||||
|
||||
|
||||
# Tokens for RBAC policy tests
|
||||
ADMIN_TOKEN = uuid.uuid4().hex
|
||||
admin_context = oslo_context.RequestContext(
|
||||
user_id=ADMIN_TOKEN,
|
||||
roles=['admin', 'member', 'reader'],
|
||||
)
|
||||
|
||||
MEMBER_TOKEN = uuid.uuid4().hex
|
||||
member_context = oslo_context.RequestContext(
|
||||
user_id=MEMBER_TOKEN,
|
||||
roles=['member', 'reader'],
|
||||
)
|
||||
|
||||
READER_TOKEN = uuid.uuid4().hex
|
||||
reader_context = oslo_context.RequestContext(
|
||||
user_id=READER_TOKEN,
|
||||
roles=['reader'],
|
||||
)
|
||||
|
||||
NO_ROLE_TOKEN = uuid.uuid4().hex
|
||||
no_role_context = oslo_context.RequestContext(
|
||||
user_id=READER_TOKEN,
|
||||
roles=[],
|
||||
)
|
||||
|
||||
# Tokens for deprecated policy tests
|
||||
BM_ADMIN_TOKEN = uuid.uuid4().hex
|
||||
bm_admin_context = oslo_context.RequestContext(
|
||||
user_id=BM_ADMIN_TOKEN,
|
||||
roles=['baremetal_admin'],
|
||||
)
|
||||
BM_OBSERVER_TOKEN = uuid.uuid4().hex
|
||||
bm_observer_context = oslo_context.RequestContext(
|
||||
user_id=BM_OBSERVER_TOKEN,
|
||||
roles=['baremetal_observer'],
|
||||
)
|
||||
|
||||
|
||||
USERS = {
|
||||
ADMIN_TOKEN: admin_context.to_dict(),
|
||||
MEMBER_TOKEN: member_context.to_dict(),
|
||||
READER_TOKEN: reader_context.to_dict(),
|
||||
NO_ROLE_TOKEN: no_role_context.to_dict(),
|
||||
BM_ADMIN_TOKEN: bm_admin_context.to_dict(),
|
||||
BM_OBSERVER_TOKEN: bm_observer_context.to_dict(),
|
||||
}
|
||||
|
||||
|
||||
class BasePolicyTest(test_base.BaseTest):
|
||||
|
||||
def init_app(self):
|
||||
CONF.set_override('auth_strategy', 'keystone')
|
||||
main._app.testing = True
|
||||
self.app = main.get_app().test_client()
|
||||
|
||||
def setUp(self):
|
||||
super(BasePolicyTest, self).setUp()
|
||||
self.init_app()
|
||||
self.uuid = uuidutils.generate_uuid()
|
||||
self.rpc_get_client_mock = self.useFixture(
|
||||
fixtures.MockPatchObject(rpc, 'get_client', autospec=True)).mock
|
||||
self.client_mock = mock.MagicMock(spec=messaging.RPCClient)
|
||||
self.rpc_get_client_mock.return_value = self.client_mock
|
||||
|
||||
self.fake_token = None
|
||||
mock_auth = mock.patch.object(
|
||||
auth_token.AuthProtocol, 'process_request',
|
||||
autospec=True)
|
||||
self.mock_auth = mock_auth.start()
|
||||
self.addCleanup(mock_auth.stop)
|
||||
self.mock_auth.side_effect = self._fake_process_request
|
||||
|
||||
mock_get = mock.patch.object(node_cache, 'get_node', autospec=True)
|
||||
get = mock_get.start()
|
||||
self.addCleanup(mock_get.stop)
|
||||
get.return_value = node_cache.NodeInfo(
|
||||
uuid=self.uuid,
|
||||
started_at=datetime.datetime(1, 1, 1),
|
||||
state=istate.States.processing)
|
||||
|
||||
def _fake_process_request(self, request, meow):
|
||||
if self.fake_token:
|
||||
request.user_token_valid = True
|
||||
request.user_token = True
|
||||
# is this right?!?
|
||||
request.token_info = self.fake_token
|
||||
request.auth_token = v3_token.Token(
|
||||
user_id=self.fake_token['user'])
|
||||
else:
|
||||
# Because of this, the user will always get a 403 in testing, even
|
||||
# if the API would normally return a 401 if a token is valid
|
||||
request.user_token_valid = False
|
||||
|
||||
def set_token(self, token):
|
||||
self.fake_token = USERS[token]
|
||||
headers = {
|
||||
'X-Auth-Token': token,
|
||||
'X-Roles': ','.join(self.fake_token['roles'])
|
||||
}
|
||||
if cfg.CONF.oslo_policy.enforce_scope:
|
||||
headers['OpenStack-System-Scope'] = 'all'
|
||||
return headers
|
||||
|
||||
def assert_status(self, status_code, token, request_func, path, data=None):
|
||||
headers = self.set_token(token)
|
||||
res = request_func(path, headers=headers, data=data)
|
||||
self.assertEqual(status_code, res.status_code)
|
||||
|
||||
|
||||
class TestACLDeprecated(BasePolicyTest):
|
||||
|
||||
def setUp(self):
|
||||
super(TestACLDeprecated, self).setUp()
|
||||
cfg.CONF.set_override('enforce_scope', False, group='oslo_policy')
|
||||
cfg.CONF.set_override('enforce_new_defaults', False,
|
||||
group='oslo_policy')
|
||||
|
||||
def test_root_baremetal_admin(self):
|
||||
self.assert_status(200, BM_ADMIN_TOKEN, self.app.get, '/')
|
||||
self.assert_status(200, BM_ADMIN_TOKEN, self.app.get, '/v1')
|
||||
|
||||
def test_root_baremetal_observer(self):
|
||||
self.assert_status(200, BM_OBSERVER_TOKEN, self.app.get, '/')
|
||||
self.assert_status(200, BM_OBSERVER_TOKEN, self.app.get, '/v1')
|
||||
|
||||
def test_root_system_no_role(self):
|
||||
self.assert_status(200, NO_ROLE_TOKEN, self.app.get, '/')
|
||||
self.assert_status(200, NO_ROLE_TOKEN, self.app.get, '/v1')
|
||||
|
||||
def test_introspect_baremetal_admin(self):
|
||||
self.assert_status(202, BM_ADMIN_TOKEN, self.app.post,
|
||||
'/v1/introspection/%s' % self.uuid)
|
||||
|
||||
def test_introspect_baremetal_observer(self):
|
||||
self.assert_status(403, BM_OBSERVER_TOKEN, self.app.post,
|
||||
'/v1/introspection/%s/abort' % self.uuid)
|
||||
|
||||
def test_abort_baremetal_admin(self):
|
||||
self.assert_status(202, BM_ADMIN_TOKEN, self.app.post,
|
||||
'/v1/introspection/%s/abort' % self.uuid)
|
||||
|
||||
def test_abort_baremetal_observer(self):
|
||||
self.assert_status(403, BM_OBSERVER_TOKEN, self.app.post,
|
||||
'/v1/introspection/%s/abort' % self.uuid)
|
||||
|
||||
def test_status_baremetal_admin(self):
|
||||
self.assert_status(200, BM_ADMIN_TOKEN, self.app.get,
|
||||
'/v1/introspection/%s' % self.uuid)
|
||||
|
||||
def test_status_baremetal_observer(self):
|
||||
self.assert_status(200, BM_OBSERVER_TOKEN, self.app.get,
|
||||
'/v1/introspection/%s' % self.uuid)
|
||||
|
||||
def test_list_baremetal_admin(self):
|
||||
self.assert_status(200, BM_ADMIN_TOKEN, self.app.get,
|
||||
'/v1/introspection')
|
||||
|
||||
def test_list_baremetal_observer(self):
|
||||
self.assert_status(200, BM_OBSERVER_TOKEN, self.app.get,
|
||||
'/v1/introspection')
|
||||
|
||||
def test_data_baremetal_admin(self):
|
||||
self.assert_status(404, BM_ADMIN_TOKEN, self.app.get,
|
||||
'/v1/introspection/%s/data' % self.uuid)
|
||||
|
||||
def test_data_baremetal_observer(self):
|
||||
self.assert_status(403, BM_OBSERVER_TOKEN, self.app.get,
|
||||
'/v1/introspection/%s/data' % self.uuid)
|
||||
|
||||
def test_data_unprocessed_baremetal_admin(self):
|
||||
self.assert_status(400, BM_ADMIN_TOKEN, self.app.post,
|
||||
'/v1/introspection/%s/data/unprocessed' % self.uuid,
|
||||
data={'foo': 'bar'})
|
||||
|
||||
def test_data_unprocessed_baremetal_observer(self):
|
||||
self.assert_status(403, BM_OBSERVER_TOKEN, self.app.post,
|
||||
'/v1/introspection/%s/data/unprocessed' % self.uuid,
|
||||
data={'foo': 'bar'})
|
||||
|
||||
def test_rule_list_baremetal_admin(self):
|
||||
self.assert_status(200, BM_ADMIN_TOKEN, self.app.get,
|
||||
'/v1/rules')
|
||||
|
||||
def test_rule_list_baremetal_observer(self):
|
||||
self.assert_status(403, BM_OBSERVER_TOKEN, self.app.get,
|
||||
'/v1/rules')
|
||||
|
||||
def test_rule_get_baremetal_admin(self):
|
||||
self.assert_status(404, BM_ADMIN_TOKEN, self.app.get,
|
||||
'/v1/rules/foo')
|
||||
|
||||
def test_rule_get_baremetal_observer(self):
|
||||
self.assert_status(403, BM_OBSERVER_TOKEN, self.app.get,
|
||||
'/v1/rules/foo')
|
||||
|
||||
def test_rule_delete_all_baremetal_admin(self):
|
||||
self.assert_status(204, BM_ADMIN_TOKEN, self.app.delete,
|
||||
'/v1/rules')
|
||||
|
||||
def test_rule_delete_all_baremetal_observer(self):
|
||||
self.assert_status(403, BM_OBSERVER_TOKEN, self.app.delete,
|
||||
'/v1/rules')
|
||||
|
||||
def test_rule_delete_baremetal_admin(self):
|
||||
self.assert_status(404, BM_ADMIN_TOKEN, self.app.delete,
|
||||
'/v1/rules/foo')
|
||||
|
||||
def test_rule_delete_baremetal_observer(self):
|
||||
self.assert_status(403, BM_OBSERVER_TOKEN, self.app.delete,
|
||||
'/v1/rules/foo')
|
||||
|
||||
def test_rule_create_baremetal_admin(self):
|
||||
self.assert_status(500, BM_ADMIN_TOKEN, self.app.post,
|
||||
'/v1/rules',
|
||||
data={
|
||||
'uuid': self.uuid,
|
||||
'conditions': 'cond',
|
||||
'actions': 'act'
|
||||
})
|
||||
|
||||
def test_rule_create_baremetal_observer(self):
|
||||
self.assert_status(403, BM_OBSERVER_TOKEN, self.app.post,
|
||||
'/v1/rules',
|
||||
data={
|
||||
'uuid': self.uuid,
|
||||
'conditions': 'cond',
|
||||
'actions': 'act'
|
||||
})
|
||||
|
||||
|
||||
class TestRBACScoped(BasePolicyTest):
|
||||
|
||||
def setUp(self):
|
||||
super(TestRBACScoped, self).setUp()
|
||||
cfg.CONF.set_override('enforce_scope', True, group='oslo_policy')
|
||||
cfg.CONF.set_override('enforce_new_defaults', True,
|
||||
group='oslo_policy')
|
||||
|
||||
def test_root_system_admin(self):
|
||||
self.assert_status(200, ADMIN_TOKEN, self.app.get, '/')
|
||||
self.assert_status(200, ADMIN_TOKEN, self.app.get, '/v1')
|
||||
|
||||
def test_root_system_member(self):
|
||||
self.assert_status(200, MEMBER_TOKEN, self.app.get, '/')
|
||||
self.assert_status(200, MEMBER_TOKEN, self.app.get, '/v1')
|
||||
|
||||
def test_root_system_reader(self):
|
||||
self.assert_status(200, READER_TOKEN, self.app.get, '/')
|
||||
self.assert_status(200, READER_TOKEN, self.app.get, '/v1')
|
||||
|
||||
def test_root_system_no_role(self):
|
||||
self.assert_status(200, NO_ROLE_TOKEN, self.app.get, '/')
|
||||
self.assert_status(200, NO_ROLE_TOKEN, self.app.get, '/v1')
|
||||
|
||||
def test_introspect_system_admin(self):
|
||||
self.assert_status(202, ADMIN_TOKEN, self.app.post,
|
||||
'/v1/introspection/%s' % self.uuid)
|
||||
|
||||
def test_introspect_system_member(self):
|
||||
self.assert_status(403, MEMBER_TOKEN, self.app.post,
|
||||
'/v1/introspection/%s' % self.uuid)
|
||||
|
||||
def test_introspect_system_reader(self):
|
||||
self.assert_status(403, READER_TOKEN, self.app.post,
|
||||
'/v1/introspection/%s/abort' % self.uuid)
|
||||
|
||||
def test_abort_system_admin(self):
|
||||
self.assert_status(202, ADMIN_TOKEN, self.app.post,
|
||||
'/v1/introspection/%s/abort' % self.uuid)
|
||||
|
||||
def test_abort_system_member(self):
|
||||
self.assert_status(403, MEMBER_TOKEN, self.app.post,
|
||||
'/v1/introspection/%s/abort' % self.uuid)
|
||||
|
||||
def test_abort_system_reader(self):
|
||||
self.assert_status(403, READER_TOKEN, self.app.post,
|
||||
'/v1/introspection/%s/abort' % self.uuid)
|
||||
|
||||
def test_status_system_admin(self):
|
||||
self.assert_status(200, ADMIN_TOKEN, self.app.get,
|
||||
'/v1/introspection/%s' % self.uuid)
|
||||
|
||||
def test_status_system_member(self):
|
||||
self.assert_status(200, MEMBER_TOKEN, self.app.get,
|
||||
'/v1/introspection/%s' % self.uuid)
|
||||
|
||||
def test_status_system_reader(self):
|
||||
self.assert_status(200, READER_TOKEN, self.app.get,
|
||||
'/v1/introspection/%s' % self.uuid)
|
||||
|
||||
def test_list_system_admin(self):
|
||||
self.assert_status(200, ADMIN_TOKEN, self.app.get,
|
||||
'/v1/introspection')
|
||||
|
||||
def test_list_system_member(self):
|
||||
self.assert_status(200, MEMBER_TOKEN, self.app.get,
|
||||
'/v1/introspection')
|
||||
|
||||
def test_list_system_reader(self):
|
||||
self.assert_status(200, READER_TOKEN, self.app.get,
|
||||
'/v1/introspection')
|
||||
|
||||
def test_data_system_admin(self):
|
||||
self.assert_status(404, ADMIN_TOKEN, self.app.get,
|
||||
'/v1/introspection/%s/data' % self.uuid)
|
||||
|
||||
def test_data_system_member(self):
|
||||
self.assert_status(403, MEMBER_TOKEN, self.app.get,
|
||||
'/v1/introspection/%s/data' % self.uuid)
|
||||
|
||||
def test_data_system_reader(self):
|
||||
self.assert_status(403, READER_TOKEN, self.app.get,
|
||||
'/v1/introspection/%s/data' % self.uuid)
|
||||
|
||||
def test_data_unprocessed_system_admin(self):
|
||||
self.assert_status(400, ADMIN_TOKEN, self.app.post,
|
||||
'/v1/introspection/%s/data/unprocessed' % self.uuid,
|
||||
data={'foo': 'bar'})
|
||||
|
||||
def test_data_unprocessed_system_member(self):
|
||||
self.assert_status(403, MEMBER_TOKEN, self.app.post,
|
||||
'/v1/introspection/%s/data/unprocessed' % self.uuid,
|
||||
data={'foo': 'bar'})
|
||||
|
||||
def test_data_unprocessed_system_reader(self):
|
||||
self.assert_status(403, READER_TOKEN, self.app.post,
|
||||
'/v1/introspection/%s/data/unprocessed' % self.uuid,
|
||||
data={'foo': 'bar'})
|
||||
|
||||
def test_rule_list_system_admin(self):
|
||||
self.assert_status(200, ADMIN_TOKEN, self.app.get,
|
||||
'/v1/rules')
|
||||
|
||||
def test_rule_list_system_member(self):
|
||||
self.assert_status(403, MEMBER_TOKEN, self.app.get,
|
||||
'/v1/rules')
|
||||
|
||||
def test_rule_list_system_reader(self):
|
||||
self.assert_status(403, READER_TOKEN, self.app.get,
|
||||
'/v1/rules')
|
||||
|
||||
def test_rule_get_system_admin(self):
|
||||
self.assert_status(404, ADMIN_TOKEN, self.app.get,
|
||||
'/v1/rules/foo')
|
||||
|
||||
def test_rule_get_system_member(self):
|
||||
self.assert_status(403, MEMBER_TOKEN, self.app.get,
|
||||
'/v1/rules/foo')
|
||||
|
||||
def test_rule_get_system_reader(self):
|
||||
self.assert_status(403, READER_TOKEN, self.app.get,
|
||||
'/v1/rules/foo')
|
||||
|
||||
def test_rule_delete_all_system_admin(self):
|
||||
self.assert_status(204, ADMIN_TOKEN, self.app.delete,
|
||||
'/v1/rules')
|
||||
|
||||
def test_rule_delete_all_system_member(self):
|
||||
self.assert_status(403, MEMBER_TOKEN, self.app.delete,
|
||||
'/v1/rules')
|
||||
|
||||
def test_rule_delete_all_system_reader(self):
|
||||
self.assert_status(403, READER_TOKEN, self.app.delete,
|
||||
'/v1/rules')
|
||||
|
||||
def test_rule_delete_system_admin(self):
|
||||
self.assert_status(404, ADMIN_TOKEN, self.app.delete,
|
||||
'/v1/rules/foo')
|
||||
|
||||
def test_rule_delete_system_member(self):
|
||||
self.assert_status(403, MEMBER_TOKEN, self.app.delete,
|
||||
'/v1/rules/foo')
|
||||
|
||||
def test_rule_delete_system_reader(self):
|
||||
self.assert_status(403, READER_TOKEN, self.app.delete,
|
||||
'/v1/rules/foo')
|
||||
|
||||
def test_rule_create_system_admin(self):
|
||||
self.assert_status(500, ADMIN_TOKEN, self.app.post,
|
||||
'/v1/rules',
|
||||
data={
|
||||
'uuid': self.uuid,
|
||||
'conditions': 'cond',
|
||||
'actions': 'act'
|
||||
})
|
||||
|
||||
def test_rule_create_system_member(self):
|
||||
self.assert_status(403, MEMBER_TOKEN, self.app.post,
|
||||
'/v1/rules',
|
||||
data={
|
||||
'uuid': self.uuid,
|
||||
'conditions': 'cond',
|
||||
'actions': 'act'
|
||||
})
|
||||
|
||||
def test_rule_create_system_reader(self):
|
||||
self.assert_status(403, READER_TOKEN, self.app.post,
|
||||
'/v1/rules',
|
||||
data={
|
||||
'uuid': self.uuid,
|
||||
'conditions': 'cond',
|
||||
'actions': 'act'
|
||||
})
|
19
releasenotes/notes/secure-rbac-0d4fcbc865d45858.yaml
Normal file
19
releasenotes/notes/secure-rbac-0d4fcbc865d45858.yaml
Normal file
@ -0,0 +1,19 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
The default policy will been replaced with one which aligns with the
|
||||
Secure-RBAC scopes and roles. Since ironic-inspector is a tool used only
|
||||
by system-level admins, only the ``system`` scope is supported, and the
|
||||
only roles in the policy rules are ``admin`` and ``reader``.
|
||||
upgrade:
|
||||
- |
|
||||
The new policy is only enforced when ``[oslo_policy]`` config is changed to
|
||||
``enforce_new_defaults=True`` and ``enforce_scope=True``, otherwise the
|
||||
existing deprecated policy is used. User accounts which rely on having
|
||||
the ``baremetal_admin`` or ``baremetal_observer`` roles will need to
|
||||
have system-scoped ``admin`` or ``reader`` roles to use the API when the
|
||||
new policy is enforced.
|
||||
deprecations:
|
||||
- |
|
||||
The previous policy is still enforced by default, but is now deprecated
|
||||
and will be removed in a future release.
|
Loading…
Reference in New Issue
Block a user