Merge "Add user and project domains to ironic context"
This commit is contained in:
commit
f0108e05ed
@ -2,12 +2,12 @@
|
||||
"admin_api": "role:admin or role:administrator"
|
||||
# Internal flag for public API routes
|
||||
"public_api": "is_public_api:True"
|
||||
# Show or mask secrets within driver_info in API responses
|
||||
# Show or mask secrets within node driver information in API responses
|
||||
"show_password": "!"
|
||||
# Show or mask secrets within instance_info in API responses
|
||||
# Show or mask secrets within instance information in API responses
|
||||
"show_instance_secrets": "!"
|
||||
# May be used to restrict access to specific tenants
|
||||
"is_member": "tenant:demo or tenant:baremetal"
|
||||
# May be used to restrict access to specific projects
|
||||
"is_member": "(project_domain_id:default or project_domain_id:None) and (project_name:demo or project_name:baremetal)"
|
||||
# Read-only API access
|
||||
"is_observer": "rule:is_member and (role:observer or role:baremetal_observer)"
|
||||
# Full read/write API access
|
||||
|
@ -14,15 +14,55 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import re
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log
|
||||
from pecan import hooks
|
||||
import six
|
||||
from six.moves import http_client
|
||||
|
||||
from ironic.common import context
|
||||
from ironic.common.i18n import _LW
|
||||
from ironic.common import policy
|
||||
from ironic.conductor import rpcapi
|
||||
from ironic.db import api as dbapi
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
CHECKED_DEPRECATED_POLICY_ARGS = False
|
||||
|
||||
|
||||
def policy_deprecation_check():
|
||||
global CHECKED_DEPRECATED_POLICY_ARGS
|
||||
if not CHECKED_DEPRECATED_POLICY_ARGS:
|
||||
enforcer = policy.get_enforcer()
|
||||
substitution_dict = {
|
||||
'user': 'user_id',
|
||||
'domain_id': 'user_domain_id',
|
||||
'domain_name': 'user_domain_id',
|
||||
'tenant': 'project_name',
|
||||
}
|
||||
policy_rules = enforcer.file_rules.values()
|
||||
for rule in policy_rules:
|
||||
str_rule = six.text_type(rule)
|
||||
for deprecated, replacement in substitution_dict.items():
|
||||
if re.search(r'\b%s\b' % deprecated, str_rule):
|
||||
LOG.warning(_LW(
|
||||
"Deprecated argument %(deprecated)s is used in policy "
|
||||
"file rule (%(rule)s), please use %(replacement)s "
|
||||
"argument instead. The possibility to use deprecated "
|
||||
"arguments will be removed in the Pike release."),
|
||||
{'deprecated': deprecated, 'replacement': replacement,
|
||||
'rule': str_rule})
|
||||
if deprecated == 'domain_name':
|
||||
LOG.warning(_LW(
|
||||
"Please note that user_domain_id is an ID of the "
|
||||
"user domain, while the deprecated domain_name is "
|
||||
"its name. The policy rule has to be updated "
|
||||
"accordingly."))
|
||||
CHECKED_DEPRECATED_POLICY_ARGS = True
|
||||
|
||||
|
||||
class ConfigHook(hooks.PecanHook):
|
||||
"""Attach the config object to the request so controllers can get to it."""
|
||||
@ -39,52 +79,25 @@ class DBHook(hooks.PecanHook):
|
||||
|
||||
|
||||
class ContextHook(hooks.PecanHook):
|
||||
"""Configures a request context and attaches it to the request.
|
||||
|
||||
The following HTTP request headers are used:
|
||||
|
||||
X-User-Id or X-User:
|
||||
Used for context.user_id.
|
||||
|
||||
X-Tenant-Id or X-Tenant:
|
||||
Used for context.tenant.
|
||||
|
||||
X-Auth-Token:
|
||||
Used for context.auth_token.
|
||||
|
||||
X-Roles:
|
||||
Used for setting context.is_admin flag to either True or False.
|
||||
The flag is set to True, if X-Roles contains either an administrator
|
||||
or admin substring. Otherwise it is set to False.
|
||||
|
||||
"""
|
||||
"""Configures a request context and attaches it to the request."""
|
||||
def __init__(self, public_api_routes):
|
||||
self.public_api_routes = public_api_routes
|
||||
super(ContextHook, self).__init__()
|
||||
|
||||
def before(self, state):
|
||||
headers = state.request.headers
|
||||
|
||||
# Do not pass any token with context for noauth mode
|
||||
auth_token = (None if cfg.CONF.auth_strategy == 'noauth' else
|
||||
headers.get('X-Auth-Token'))
|
||||
is_public_api = state.request.environ.get('is_public_api', False)
|
||||
ctx = context.RequestContext.from_environ(state.request.environ,
|
||||
is_public_api=is_public_api)
|
||||
# Do not pass any token with context for noauth mode
|
||||
if cfg.CONF.auth_strategy == 'noauth':
|
||||
ctx.auth_token = None
|
||||
|
||||
creds = {
|
||||
'user': headers.get('X-User') or headers.get('X-User-Id'),
|
||||
'tenant': headers.get('X-Tenant') or headers.get('X-Tenant-Id'),
|
||||
'domain_id': headers.get('X-User-Domain-Id'),
|
||||
'domain_name': headers.get('X-User-Domain-Name'),
|
||||
'auth_token': auth_token,
|
||||
'roles': headers.get('X-Roles', '').split(','),
|
||||
'is_public_api': is_public_api,
|
||||
}
|
||||
|
||||
creds = ctx.to_policy_values()
|
||||
is_admin = policy.check('is_admin', creds, creds)
|
||||
ctx.is_admin = is_admin
|
||||
policy_deprecation_check()
|
||||
|
||||
state.request.context = context.RequestContext(
|
||||
is_admin=is_admin,
|
||||
**creds)
|
||||
state.request.context = ctx
|
||||
|
||||
def after(self, state):
|
||||
if state.request.context == {}:
|
||||
|
@ -13,49 +13,40 @@
|
||||
# under the License.
|
||||
|
||||
from oslo_context import context
|
||||
from oslo_log import log
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class RequestContext(context.RequestContext):
|
||||
"""Extends security contexts from the oslo.context library."""
|
||||
|
||||
def __init__(self, auth_token=None, domain_id=None, domain_name=None,
|
||||
user=None, tenant=None, is_admin=False, is_public_api=False,
|
||||
read_only=False, show_deleted=False, request_id=None,
|
||||
roles=None, overwrite=True):
|
||||
def __init__(self, is_public_api=False, **kwargs):
|
||||
"""Initialize the RequestContext
|
||||
|
||||
:param auth_token: The authentication token of the current request.
|
||||
:param domain_id: The ID of the domain.
|
||||
:param domain_name: The name of the domain.
|
||||
:param user: The name of the user.
|
||||
:param tenant: The name of the tenant.
|
||||
:param is_admin: Indicates if the request context is an administrator
|
||||
context.
|
||||
:param is_public_api: Specifies whether the request should be processed
|
||||
without authentication.
|
||||
:param read_only: unused flag for Ironic.
|
||||
:param show_deleted: unused flag for Ironic.
|
||||
:param request_id: The UUID of the request.
|
||||
:param roles: List of user's roles if any.
|
||||
:param overwrite: Set to False to ensure that the greenthread local
|
||||
copy of the index is not overwritten.
|
||||
without authentication.
|
||||
:param kwargs: additional arguments passed to oslo.context.
|
||||
"""
|
||||
super(RequestContext, self).__init__(auth_token=auth_token,
|
||||
user=user, tenant=tenant,
|
||||
is_admin=is_admin,
|
||||
read_only=read_only,
|
||||
show_deleted=show_deleted,
|
||||
request_id=request_id,
|
||||
overwrite=overwrite)
|
||||
super(RequestContext, self).__init__(**kwargs)
|
||||
self.is_public_api = is_public_api
|
||||
self.domain_id = domain_id
|
||||
self.domain_name = domain_name
|
||||
# NOTE(dims): roles was added in context.RequestContext recently.
|
||||
# we should pass roles in __init__ above instead of setting the
|
||||
# value here once the minimum version of oslo.context is updated.
|
||||
self.roles = roles or []
|
||||
|
||||
def to_policy_values(self):
|
||||
policy_values = super(RequestContext, self).to_policy_values()
|
||||
# TODO(vdrok): remove all of these apart from is_public_api and
|
||||
# project_name after deprecation period
|
||||
policy_values.update({
|
||||
'user': self.user,
|
||||
'domain_id': self.user_domain,
|
||||
'domain_name': self.user_domain_name,
|
||||
'tenant': self.tenant,
|
||||
'project_name': self.project_name,
|
||||
'is_public_api': self.is_public_api,
|
||||
})
|
||||
return policy_values
|
||||
|
||||
def to_dict(self):
|
||||
# TODO(vdrok): reuse the base class to_dict in Pike
|
||||
return {'auth_token': self.auth_token,
|
||||
'user': self.user,
|
||||
'tenant': self.tenant,
|
||||
@ -63,16 +54,18 @@ class RequestContext(context.RequestContext):
|
||||
'read_only': self.read_only,
|
||||
'show_deleted': self.show_deleted,
|
||||
'request_id': self.request_id,
|
||||
'domain_id': self.domain_id,
|
||||
'domain_id': self.user_domain,
|
||||
'roles': self.roles,
|
||||
'domain_name': self.domain_name,
|
||||
'domain_name': self.user_domain_name,
|
||||
'is_public_api': self.is_public_api}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, values):
|
||||
values.pop('user', None)
|
||||
values.pop('tenant', None)
|
||||
return cls(**values)
|
||||
def from_dict(cls, values, **kwargs):
|
||||
kwargs.setdefault('is_public_api', values.get('is_public_api', False))
|
||||
if 'domain_id' in values:
|
||||
kwargs.setdefault('user_domain', values['domain_id'])
|
||||
return super(RequestContext, RequestContext).from_dict(values,
|
||||
**kwargs)
|
||||
|
||||
def ensure_thread_contain_context(self):
|
||||
"""Ensure threading contains context
|
||||
@ -90,7 +83,7 @@ class RequestContext(context.RequestContext):
|
||||
def get_admin_context():
|
||||
"""Create an administrator context."""
|
||||
|
||||
context = RequestContext(None,
|
||||
context = RequestContext(auth_token=None,
|
||||
tenant=None,
|
||||
is_admin=True,
|
||||
overwrite=False)
|
||||
|
@ -55,8 +55,8 @@ default_policies = [
|
||||
description='Show or mask secrets within instance information in API responses'), # noqa
|
||||
# Roles likely to be overridden by operator
|
||||
policy.RuleDefault('is_member',
|
||||
'tenant:demo or tenant:baremetal',
|
||||
description='May be used to restrict access to specific tenants'), # noqa
|
||||
'(project_domain_id:default or project_domain_id:None) and (project_name:demo or project_name:baremetal)', # noqa
|
||||
description='May be used to restrict access to specific projects'), # noqa
|
||||
policy.RuleDefault('is_observer',
|
||||
'rule:is_member and (role:observer or role:baremetal_observer)', # noqa
|
||||
description='Read-only API access'),
|
||||
|
@ -25,6 +25,8 @@ from six.moves import http_client
|
||||
from ironic.api.controllers import root
|
||||
from ironic.api import hooks
|
||||
from ironic.common import context
|
||||
from ironic.common import policy
|
||||
from ironic.tests import base as tests_base
|
||||
from ironic.tests.unit.api import base
|
||||
|
||||
|
||||
@ -42,24 +44,6 @@ class FakeRequestState(object):
|
||||
self.request = FakeRequest(headers, context, environ)
|
||||
self.response = FakeRequest(headers, context, environ)
|
||||
|
||||
def set_context(self):
|
||||
headers = self.request.headers
|
||||
creds = {
|
||||
'user': headers.get('X-User') or headers.get('X-User-Id'),
|
||||
'tenant': headers.get('X-Tenant') or headers.get('X-Tenant-Id'),
|
||||
'domain_id': headers.get('X-User-Domain-Id'),
|
||||
'domain_name': headers.get('X-User-Domain-Name'),
|
||||
'auth_token': headers.get('X-Auth-Token'),
|
||||
'roles': headers.get('X-Roles', '').split(','),
|
||||
}
|
||||
is_admin = ('admin' in creds['roles'] or
|
||||
'administrator' in creds['roles'])
|
||||
is_public_api = self.request.environ.get('is_public_api', False)
|
||||
|
||||
self.request.context = context.RequestContext(
|
||||
is_admin=is_admin, is_public_api=is_public_api,
|
||||
**creds)
|
||||
|
||||
|
||||
def fake_headers(admin=False):
|
||||
headers = {
|
||||
@ -99,6 +83,14 @@ def fake_headers(admin=False):
|
||||
return headers
|
||||
|
||||
|
||||
def headers_to_environ(headers, **kwargs):
|
||||
environ = {}
|
||||
for k, v in headers.items():
|
||||
environ['HTTP_%s' % k.replace('-', '_').upper()] = v
|
||||
environ.update(kwargs)
|
||||
return environ
|
||||
|
||||
|
||||
class TestNoExceptionTracebackHook(base.BaseApiTest):
|
||||
|
||||
TRACE = [u'Traceback (most recent call last):',
|
||||
@ -212,88 +204,52 @@ class TestNoExceptionTracebackHook(base.BaseApiTest):
|
||||
|
||||
|
||||
class TestContextHook(base.BaseApiTest):
|
||||
@mock.patch.object(context, 'RequestContext')
|
||||
def test_context_hook_not_admin(self, mock_ctx):
|
||||
cfg.CONF.set_override('auth_strategy', 'keystone')
|
||||
headers = fake_headers(admin=False)
|
||||
reqstate = FakeRequestState(headers=headers)
|
||||
context_hook = hooks.ContextHook(None)
|
||||
context_hook.before(reqstate)
|
||||
mock_ctx.assert_called_with(
|
||||
auth_token=headers['X-Auth-Token'],
|
||||
user=headers['X-User'],
|
||||
tenant=headers['X-Tenant'],
|
||||
domain_id=headers['X-User-Domain-Id'],
|
||||
domain_name=headers['X-User-Domain-Name'],
|
||||
is_public_api=False,
|
||||
is_admin=False,
|
||||
roles=headers['X-Roles'].split(','))
|
||||
|
||||
@mock.patch.object(context, 'RequestContext')
|
||||
def test_context_hook_admin(self, mock_ctx):
|
||||
cfg.CONF.set_override('auth_strategy', 'keystone')
|
||||
headers = fake_headers(admin=True)
|
||||
reqstate = FakeRequestState(headers=headers)
|
||||
@mock.patch.object(policy, 'check')
|
||||
def _test_context_hook(self, mock_policy, mock_ctx, is_admin=False,
|
||||
is_public_api=False, auth_strategy='keystone',
|
||||
request_id=None):
|
||||
cfg.CONF.set_override('auth_strategy', auth_strategy)
|
||||
headers = fake_headers(admin=is_admin)
|
||||
environ = headers_to_environ(headers, is_public_api=is_public_api)
|
||||
reqstate = FakeRequestState(headers=headers, environ=environ)
|
||||
context_hook = hooks.ContextHook(None)
|
||||
ctx = mock.Mock()
|
||||
if request_id:
|
||||
ctx.request_id = request_id
|
||||
mock_ctx.from_environ.return_value = ctx
|
||||
policy_dict = {'user_id': 'foo'} # Lots of other values here
|
||||
ctx.to_policy_values.return_value = policy_dict
|
||||
mock_policy.return_value = is_admin
|
||||
context_hook.before(reqstate)
|
||||
mock_ctx.assert_called_with(
|
||||
auth_token=headers['X-Auth-Token'],
|
||||
user=headers['X-User'],
|
||||
tenant=headers['X-Tenant'],
|
||||
domain_id=headers['X-User-Domain-Id'],
|
||||
domain_name=headers['X-User-Domain-Name'],
|
||||
is_public_api=False,
|
||||
is_admin=True,
|
||||
roles=headers['X-Roles'].split(','))
|
||||
creds_dict = {'is_public_api': is_public_api}
|
||||
mock_ctx.from_environ.assert_called_once_with(environ, **creds_dict)
|
||||
mock_policy.assert_called_once_with('is_admin', policy_dict,
|
||||
policy_dict)
|
||||
self.assertIs(is_admin, ctx.is_admin)
|
||||
if auth_strategy == 'noauth':
|
||||
self.assertIsNone(ctx.auth_token)
|
||||
return context_hook, reqstate
|
||||
|
||||
@mock.patch.object(context, 'RequestContext')
|
||||
def test_context_hook_public_api(self, mock_ctx):
|
||||
cfg.CONF.set_override('auth_strategy', 'keystone')
|
||||
headers = fake_headers(admin=True)
|
||||
env = {'is_public_api': True}
|
||||
reqstate = FakeRequestState(headers=headers, environ=env)
|
||||
context_hook = hooks.ContextHook(None)
|
||||
context_hook.before(reqstate)
|
||||
mock_ctx.assert_called_with(
|
||||
auth_token=headers['X-Auth-Token'],
|
||||
user=headers['X-User'],
|
||||
tenant=headers['X-Tenant'],
|
||||
domain_id=headers['X-User-Domain-Id'],
|
||||
domain_name=headers['X-User-Domain-Name'],
|
||||
is_public_api=True,
|
||||
is_admin=True,
|
||||
roles=headers['X-Roles'].split(','))
|
||||
def test_context_hook_not_admin(self):
|
||||
self._test_context_hook()
|
||||
|
||||
@mock.patch.object(context, 'RequestContext')
|
||||
def test_context_hook_noauth_token_removed(self, mock_ctx):
|
||||
cfg.CONF.set_override('auth_strategy', 'noauth')
|
||||
headers = fake_headers(admin=False)
|
||||
reqstate = FakeRequestState(headers=headers)
|
||||
context_hook = hooks.ContextHook(None)
|
||||
context_hook.before(reqstate)
|
||||
mock_ctx.assert_called_with(
|
||||
auth_token=None,
|
||||
user=headers['X-User'],
|
||||
tenant=headers['X-Tenant'],
|
||||
domain_id=headers['X-User-Domain-Id'],
|
||||
domain_name=headers['X-User-Domain-Name'],
|
||||
is_public_api=False,
|
||||
is_admin=False,
|
||||
roles=headers['X-Roles'].split(','))
|
||||
def test_context_hook_admin(self):
|
||||
self._test_context_hook(is_admin=True)
|
||||
|
||||
@mock.patch.object(context, 'RequestContext')
|
||||
def test_context_hook_after_add_request_id(self, mock_ctx):
|
||||
headers = fake_headers(admin=True)
|
||||
reqstate = FakeRequestState(headers=headers)
|
||||
reqstate.set_context()
|
||||
reqstate.request.context.request_id = 'fake-id'
|
||||
context_hook = hooks.ContextHook(None)
|
||||
def test_context_hook_public_api(self):
|
||||
self._test_context_hook(is_admin=True, is_public_api=True)
|
||||
|
||||
def test_context_hook_noauth_token_removed(self):
|
||||
self._test_context_hook(auth_strategy='noauth')
|
||||
|
||||
def test_context_hook_after_add_request_id(self):
|
||||
context_hook, reqstate = self._test_context_hook(is_admin=True,
|
||||
request_id='fake-id')
|
||||
context_hook.after(reqstate)
|
||||
self.assertIn('Openstack-Request-Id',
|
||||
reqstate.response.headers)
|
||||
self.assertEqual(
|
||||
'fake-id',
|
||||
reqstate.response.headers['Openstack-Request-Id'])
|
||||
self.assertEqual('fake-id',
|
||||
reqstate.response.headers['Openstack-Request-Id'])
|
||||
|
||||
def test_context_hook_after_miss_context(self):
|
||||
response = self.get_json('/bad/path',
|
||||
@ -302,6 +258,19 @@ class TestContextHook(base.BaseApiTest):
|
||||
response.headers)
|
||||
|
||||
|
||||
class TestPolicyDeprecation(tests_base.TestCase):
|
||||
|
||||
@mock.patch.object(hooks, 'CHECKED_DEPRECATED_POLICY_ARGS', False)
|
||||
@mock.patch.object(hooks.LOG, 'warning')
|
||||
@mock.patch.object(policy, 'get_enforcer')
|
||||
def test_policy_deprecation_check(self, enforcer_mock, warning_mock):
|
||||
rules = {'is_member': 'project_name:demo or tenant:baremetal',
|
||||
'is_default_project_domain': 'project_domain_id:default'}
|
||||
enforcer_mock.return_value = mock.Mock(file_rules=rules, autospec=True)
|
||||
hooks.policy_deprecation_check()
|
||||
self.assertEqual(1, warning_mock.call_count)
|
||||
|
||||
|
||||
class TestPublicUrlHook(base.BaseApiTest):
|
||||
|
||||
def test_before_host_url(self):
|
||||
|
@ -20,66 +20,33 @@ from ironic.tests import base as tests_base
|
||||
class RequestContextTestCase(tests_base.TestCase):
|
||||
def setUp(self):
|
||||
super(RequestContextTestCase, self).setUp()
|
||||
|
||||
@mock.patch.object(oslo_context.RequestContext, "__init__")
|
||||
def test_create_context(self, context_mock):
|
||||
test_context = context.RequestContext()
|
||||
context_mock.assert_called_once_with(
|
||||
auth_token=None, user=None, tenant=None, is_admin=False,
|
||||
read_only=False, show_deleted=False, request_id=None,
|
||||
overwrite=True)
|
||||
self.assertFalse(test_context.is_public_api)
|
||||
self.assertIsNone(test_context.domain_id)
|
||||
self.assertIsNone(test_context.domain_name)
|
||||
self.assertEqual([], test_context.roles)
|
||||
|
||||
def test_from_dict(self):
|
||||
dict = {
|
||||
"user": "user1",
|
||||
"tenant": "tenant1",
|
||||
"is_public_api": True,
|
||||
"domain_id": "domain_id1",
|
||||
"domain_name": "domain_name1",
|
||||
"roles": None
|
||||
}
|
||||
ctx = context.RequestContext.from_dict(dict)
|
||||
self.assertIsNone(ctx.user)
|
||||
self.assertIsNone(ctx.tenant)
|
||||
self.assertTrue(ctx.is_public_api)
|
||||
self.assertEqual("domain_id1", ctx.domain_id)
|
||||
self.assertEqual("domain_name1", ctx.domain_name)
|
||||
self.assertEqual([], ctx.roles)
|
||||
|
||||
def test_to_dict(self):
|
||||
values = {
|
||||
self.context_dict = {
|
||||
'auth_token': 'auth_token1',
|
||||
"user": "user1",
|
||||
"tenant": "tenant1",
|
||||
"project_name": "somename",
|
||||
'is_admin': True,
|
||||
'read_only': True,
|
||||
'show_deleted': True,
|
||||
'request_id': 'id1',
|
||||
"is_public_api": True,
|
||||
"domain_id": "domain_id1",
|
||||
"domain_name": "domain_name1",
|
||||
"domain": "domain_id2",
|
||||
"user_domain": "domain_id3",
|
||||
"user_domain_name": "TreeDomain",
|
||||
"project_domain": "domain_id4",
|
||||
"roles": None,
|
||||
"overwrite": True
|
||||
}
|
||||
ctx = context.RequestContext(**values)
|
||||
ctx_dict = ctx.to_dict()
|
||||
self.assertIn('auth_token', ctx_dict)
|
||||
self.assertIn('user', ctx_dict)
|
||||
self.assertIn('tenant', ctx_dict)
|
||||
self.assertIn('is_admin', ctx_dict)
|
||||
self.assertIn('read_only', ctx_dict)
|
||||
self.assertIn('show_deleted', ctx_dict)
|
||||
self.assertIn('request_id', ctx_dict)
|
||||
self.assertIn('domain_id', ctx_dict)
|
||||
self.assertIn('roles', ctx_dict)
|
||||
self.assertIn('domain_name', ctx_dict)
|
||||
self.assertIn('is_public_api', ctx_dict)
|
||||
self.assertNotIn('overwrite', ctx_dict)
|
||||
|
||||
@mock.patch.object(oslo_context.RequestContext, "__init__")
|
||||
def test_create_context(self, context_mock):
|
||||
test_context = context.RequestContext()
|
||||
context_mock.assert_called_once_with()
|
||||
self.assertFalse(test_context.is_public_api)
|
||||
|
||||
def test_to_dict(self):
|
||||
ctx = context.RequestContext(**self.context_dict)
|
||||
ctx_dict = ctx.to_dict()
|
||||
self.assertEqual('auth_token1', ctx_dict['auth_token'])
|
||||
self.assertEqual('user1', ctx_dict['user'])
|
||||
self.assertEqual('tenant1', ctx_dict['tenant'])
|
||||
@ -88,8 +55,33 @@ class RequestContextTestCase(tests_base.TestCase):
|
||||
self.assertTrue(ctx_dict['show_deleted'])
|
||||
self.assertEqual('id1', ctx_dict['request_id'])
|
||||
self.assertTrue(ctx_dict['is_public_api'])
|
||||
self.assertEqual('domain_id1', ctx_dict['domain_id'])
|
||||
self.assertEqual('domain_name1', ctx_dict['domain_name'])
|
||||
self.assertEqual('domain_id3', ctx_dict['domain_id'])
|
||||
self.assertEqual('TreeDomain', ctx_dict['domain_name'])
|
||||
self.assertEqual([], ctx_dict['roles'])
|
||||
self.assertNotIn('overwrite', ctx_dict)
|
||||
|
||||
def test_from_dict(self):
|
||||
test_context = context.RequestContext.from_dict(
|
||||
{'project_name': 'demo', 'is_public_api': True,
|
||||
'domain_id': 'meow'})
|
||||
self.assertEqual('demo', test_context.project_name)
|
||||
self.assertEqual('meow', test_context.user_domain)
|
||||
self.assertTrue(test_context.is_public_api)
|
||||
|
||||
def test_to_policy_values(self):
|
||||
ctx = context.RequestContext(**self.context_dict)
|
||||
ctx_dict = ctx.to_policy_values()
|
||||
self.assertEqual('user1', ctx_dict['user'])
|
||||
self.assertEqual('user1', ctx_dict['user_id'])
|
||||
self.assertEqual('tenant1', ctx_dict['tenant'])
|
||||
self.assertEqual('tenant1', ctx_dict['project_id'])
|
||||
self.assertEqual('somename', ctx_dict['project_name'])
|
||||
self.assertTrue(ctx_dict['is_public_api'])
|
||||
self.assertTrue(ctx_dict['is_admin_project'])
|
||||
self.assertEqual('domain_id3', ctx_dict['domain_id'])
|
||||
self.assertEqual('TreeDomain', ctx_dict['domain_name'])
|
||||
self.assertEqual('domain_id3', ctx_dict['user_domain_id'])
|
||||
self.assertEqual('domain_id4', ctx_dict['project_domain_id'])
|
||||
self.assertEqual([], ctx_dict['roles'])
|
||||
|
||||
def test_get_admin_context(self):
|
||||
|
@ -42,15 +42,28 @@ class PolicyInCodeTestCase(base.TestCase):
|
||||
self.assertTrue(policy.check('public_api', creds, creds))
|
||||
|
||||
def test_show_password(self):
|
||||
creds = {'roles': [u'admin'], 'tenant': 'admin'}
|
||||
self.assertTrue(policy.check('show_password', creds, creds))
|
||||
creds = {'roles': [u'admin'], 'project_name': 'admin',
|
||||
'project_domain_id': 'default'}
|
||||
self.assertFalse(policy.check('show_password', creds, creds))
|
||||
|
||||
def test_is_member(self):
|
||||
creds = [{'project_name': 'demo', 'project_domain_id': 'default'},
|
||||
{'project_name': 'baremetal', 'project_domain_id': 'default'},
|
||||
{'project_name': 'demo', 'project_domain_id': None},
|
||||
{'project_name': 'baremetal', 'project_domain_id': None}]
|
||||
for c in creds:
|
||||
self.assertTrue(policy.check('is_member', c, c))
|
||||
c = {'project_name': 'demo1', 'project_domain_id': 'default2'}
|
||||
self.assertFalse(policy.check('is_member', c, c))
|
||||
|
||||
def test_node_get(self):
|
||||
creds = {'roles': ['baremetal_observer'], 'tenant': 'demo'}
|
||||
creds = {'roles': ['baremetal_observer'], 'project_name': 'demo',
|
||||
'project_domain_id': 'default'}
|
||||
self.assertTrue(policy.check('baremetal:node:get', creds, creds))
|
||||
|
||||
def test_node_create(self):
|
||||
creds = {'roles': ['baremetal_admin'], 'tenant': 'demo'}
|
||||
creds = {'roles': ['baremetal_admin'], 'project_name': 'demo',
|
||||
'project_domain_id': 'default'}
|
||||
self.assertTrue(policy.check('baremetal:node:create', creds, creds))
|
||||
|
||||
|
||||
|
@ -179,11 +179,7 @@ class TestRequestContextSerializer(base.TestCase):
|
||||
self.assertEqual(self.context.to_dict(), serialize_values)
|
||||
|
||||
def test_deserialize_context(self):
|
||||
self.context.user = 'fake-user'
|
||||
self.context.tenant = 'fake-tenant'
|
||||
serialize_values = self.context.to_dict()
|
||||
new_context = self.serializer.deserialize_context(serialize_values)
|
||||
# Ironic RequestContext from_dict will pop 'user' and 'tenant' and
|
||||
# initialize to None.
|
||||
self.assertIsNone(new_context.user)
|
||||
self.assertIsNone(new_context.tenant)
|
||||
self.assertEqual(serialize_values, new_context.to_dict())
|
||||
self.assertIsInstance(new_context, ironic_context.RequestContext)
|
||||
|
@ -209,8 +209,8 @@ class _TestObject(object):
|
||||
base.IronicObject.obj_class_from_name, 'foo', '1.0')
|
||||
|
||||
def test_with_alternate_context(self):
|
||||
ctxt1 = context.RequestContext('foo', 'foo')
|
||||
ctxt2 = context.RequestContext('bar', tenant='alternate')
|
||||
ctxt1 = context.RequestContext(auth_token='foo', tenant='foo')
|
||||
ctxt2 = context.RequestContext(auth_token='bar', tenant='alternate')
|
||||
obj = MyObj.query(ctxt1)
|
||||
obj.update_test(ctxt2)
|
||||
self.assertEqual('alternate-context', obj.bar)
|
||||
|
@ -0,0 +1,10 @@
|
||||
---
|
||||
deprecations:
|
||||
- |
|
||||
Usage of the following values was deprecated in the policy files:
|
||||
|
||||
- domain_id and domain_name - user_domain_id should be used
|
||||
instead of those (note - user_domain is an ID of the domain,
|
||||
not its name);
|
||||
- tenant - project_name should be used instead;
|
||||
- user - user_id should be used instead.
|
Loading…
x
Reference in New Issue
Block a user