Merge "Add user and project domains to ironic context"

This commit is contained in:
Jenkins 2016-11-23 14:24:54 +00:00 committed by Gerrit Code Review
commit f0108e05ed
10 changed files with 221 additions and 235 deletions

View File

@ -2,12 +2,12 @@
"admin_api": "role:admin or role:administrator" "admin_api": "role:admin or role:administrator"
# Internal flag for public API routes # Internal flag for public API routes
"public_api": "is_public_api:True" "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_password": "!"
# Show or mask secrets within instance_info in API responses # Show or mask secrets within instance information in API responses
"show_instance_secrets": "!" "show_instance_secrets": "!"
# May be used to restrict access to specific tenants # May be used to restrict access to specific projects
"is_member": "tenant:demo or tenant:baremetal" "is_member": "(project_domain_id:default or project_domain_id:None) and (project_name:demo or project_name:baremetal)"
# Read-only API access # Read-only API access
"is_observer": "rule:is_member and (role:observer or role:baremetal_observer)" "is_observer": "rule:is_member and (role:observer or role:baremetal_observer)"
# Full read/write API access # Full read/write API access

View File

@ -14,15 +14,55 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import re
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log
from pecan import hooks from pecan import hooks
import six
from six.moves import http_client from six.moves import http_client
from ironic.common import context from ironic.common import context
from ironic.common.i18n import _LW
from ironic.common import policy from ironic.common import policy
from ironic.conductor import rpcapi from ironic.conductor import rpcapi
from ironic.db import api as dbapi 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): class ConfigHook(hooks.PecanHook):
"""Attach the config object to the request so controllers can get to it.""" """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): class ContextHook(hooks.PecanHook):
"""Configures a request context and attaches it to the request. """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.
"""
def __init__(self, public_api_routes): def __init__(self, public_api_routes):
self.public_api_routes = public_api_routes self.public_api_routes = public_api_routes
super(ContextHook, self).__init__() super(ContextHook, self).__init__()
def before(self, state): 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) 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 = { creds = ctx.to_policy_values()
'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,
}
is_admin = policy.check('is_admin', creds, creds) is_admin = policy.check('is_admin', creds, creds)
ctx.is_admin = is_admin
policy_deprecation_check()
state.request.context = context.RequestContext( state.request.context = ctx
is_admin=is_admin,
**creds)
def after(self, state): def after(self, state):
if state.request.context == {}: if state.request.context == {}:

View File

@ -13,49 +13,40 @@
# under the License. # under the License.
from oslo_context import context from oslo_context import context
from oslo_log import log
LOG = log.getLogger(__name__)
class RequestContext(context.RequestContext): class RequestContext(context.RequestContext):
"""Extends security contexts from the oslo.context library.""" """Extends security contexts from the oslo.context library."""
def __init__(self, auth_token=None, domain_id=None, domain_name=None, def __init__(self, is_public_api=False, **kwargs):
user=None, tenant=None, is_admin=False, is_public_api=False,
read_only=False, show_deleted=False, request_id=None,
roles=None, overwrite=True):
"""Initialize the RequestContext """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 :param is_public_api: Specifies whether the request should be processed
without authentication. without authentication.
:param read_only: unused flag for Ironic. :param kwargs: additional arguments passed to oslo.context.
: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.
""" """
super(RequestContext, self).__init__(auth_token=auth_token, super(RequestContext, self).__init__(**kwargs)
user=user, tenant=tenant,
is_admin=is_admin,
read_only=read_only,
show_deleted=show_deleted,
request_id=request_id,
overwrite=overwrite)
self.is_public_api = is_public_api self.is_public_api = is_public_api
self.domain_id = domain_id
self.domain_name = domain_name def to_policy_values(self):
# NOTE(dims): roles was added in context.RequestContext recently. policy_values = super(RequestContext, self).to_policy_values()
# we should pass roles in __init__ above instead of setting the # TODO(vdrok): remove all of these apart from is_public_api and
# value here once the minimum version of oslo.context is updated. # project_name after deprecation period
self.roles = roles or [] 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): def to_dict(self):
# TODO(vdrok): reuse the base class to_dict in Pike
return {'auth_token': self.auth_token, return {'auth_token': self.auth_token,
'user': self.user, 'user': self.user,
'tenant': self.tenant, 'tenant': self.tenant,
@ -63,16 +54,18 @@ class RequestContext(context.RequestContext):
'read_only': self.read_only, 'read_only': self.read_only,
'show_deleted': self.show_deleted, 'show_deleted': self.show_deleted,
'request_id': self.request_id, 'request_id': self.request_id,
'domain_id': self.domain_id, 'domain_id': self.user_domain,
'roles': self.roles, 'roles': self.roles,
'domain_name': self.domain_name, 'domain_name': self.user_domain_name,
'is_public_api': self.is_public_api} 'is_public_api': self.is_public_api}
@classmethod @classmethod
def from_dict(cls, values): def from_dict(cls, values, **kwargs):
values.pop('user', None) kwargs.setdefault('is_public_api', values.get('is_public_api', False))
values.pop('tenant', None) if 'domain_id' in values:
return cls(**values) kwargs.setdefault('user_domain', values['domain_id'])
return super(RequestContext, RequestContext).from_dict(values,
**kwargs)
def ensure_thread_contain_context(self): def ensure_thread_contain_context(self):
"""Ensure threading contains context """Ensure threading contains context
@ -90,7 +83,7 @@ class RequestContext(context.RequestContext):
def get_admin_context(): def get_admin_context():
"""Create an administrator context.""" """Create an administrator context."""
context = RequestContext(None, context = RequestContext(auth_token=None,
tenant=None, tenant=None,
is_admin=True, is_admin=True,
overwrite=False) overwrite=False)

View File

@ -55,8 +55,8 @@ default_policies = [
description='Show or mask secrets within instance information in API responses'), # noqa description='Show or mask secrets within instance information in API responses'), # noqa
# Roles likely to be overridden by operator # Roles likely to be overridden by operator
policy.RuleDefault('is_member', policy.RuleDefault('is_member',
'tenant:demo or tenant:baremetal', '(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 tenants'), # noqa description='May be used to restrict access to specific projects'), # noqa
policy.RuleDefault('is_observer', policy.RuleDefault('is_observer',
'rule:is_member and (role:observer or role:baremetal_observer)', # noqa 'rule:is_member and (role:observer or role:baremetal_observer)', # noqa
description='Read-only API access'), description='Read-only API access'),

View File

@ -25,6 +25,8 @@ from six.moves import http_client
from ironic.api.controllers import root from ironic.api.controllers import root
from ironic.api import hooks from ironic.api import hooks
from ironic.common import context 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 from ironic.tests.unit.api import base
@ -42,24 +44,6 @@ class FakeRequestState(object):
self.request = FakeRequest(headers, context, environ) self.request = FakeRequest(headers, context, environ)
self.response = 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): def fake_headers(admin=False):
headers = { headers = {
@ -99,6 +83,14 @@ def fake_headers(admin=False):
return headers 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): class TestNoExceptionTracebackHook(base.BaseApiTest):
TRACE = [u'Traceback (most recent call last):', TRACE = [u'Traceback (most recent call last):',
@ -212,88 +204,52 @@ class TestNoExceptionTracebackHook(base.BaseApiTest):
class TestContextHook(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') @mock.patch.object(context, 'RequestContext')
def test_context_hook_admin(self, mock_ctx): @mock.patch.object(policy, 'check')
cfg.CONF.set_override('auth_strategy', 'keystone') def _test_context_hook(self, mock_policy, mock_ctx, is_admin=False,
headers = fake_headers(admin=True) is_public_api=False, auth_strategy='keystone',
reqstate = FakeRequestState(headers=headers) 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) 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) context_hook.before(reqstate)
mock_ctx.assert_called_with( creds_dict = {'is_public_api': is_public_api}
auth_token=headers['X-Auth-Token'], mock_ctx.from_environ.assert_called_once_with(environ, **creds_dict)
user=headers['X-User'], mock_policy.assert_called_once_with('is_admin', policy_dict,
tenant=headers['X-Tenant'], policy_dict)
domain_id=headers['X-User-Domain-Id'], self.assertIs(is_admin, ctx.is_admin)
domain_name=headers['X-User-Domain-Name'], if auth_strategy == 'noauth':
is_public_api=False, self.assertIsNone(ctx.auth_token)
is_admin=True, return context_hook, reqstate
roles=headers['X-Roles'].split(','))
@mock.patch.object(context, 'RequestContext') def test_context_hook_not_admin(self):
def test_context_hook_public_api(self, mock_ctx): self._test_context_hook()
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(','))
@mock.patch.object(context, 'RequestContext') def test_context_hook_admin(self):
def test_context_hook_noauth_token_removed(self, mock_ctx): self._test_context_hook(is_admin=True)
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(','))
@mock.patch.object(context, 'RequestContext') def test_context_hook_public_api(self):
def test_context_hook_after_add_request_id(self, mock_ctx): self._test_context_hook(is_admin=True, is_public_api=True)
headers = fake_headers(admin=True)
reqstate = FakeRequestState(headers=headers) def test_context_hook_noauth_token_removed(self):
reqstate.set_context() self._test_context_hook(auth_strategy='noauth')
reqstate.request.context.request_id = 'fake-id'
context_hook = hooks.ContextHook(None) 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) context_hook.after(reqstate)
self.assertIn('Openstack-Request-Id', self.assertEqual('fake-id',
reqstate.response.headers) reqstate.response.headers['Openstack-Request-Id'])
self.assertEqual(
'fake-id',
reqstate.response.headers['Openstack-Request-Id'])
def test_context_hook_after_miss_context(self): def test_context_hook_after_miss_context(self):
response = self.get_json('/bad/path', response = self.get_json('/bad/path',
@ -302,6 +258,19 @@ class TestContextHook(base.BaseApiTest):
response.headers) 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): class TestPublicUrlHook(base.BaseApiTest):
def test_before_host_url(self): def test_before_host_url(self):

View File

@ -20,66 +20,33 @@ from ironic.tests import base as tests_base
class RequestContextTestCase(tests_base.TestCase): class RequestContextTestCase(tests_base.TestCase):
def setUp(self): def setUp(self):
super(RequestContextTestCase, self).setUp() super(RequestContextTestCase, self).setUp()
self.context_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(
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 = {
'auth_token': 'auth_token1', 'auth_token': 'auth_token1',
"user": "user1", "user": "user1",
"tenant": "tenant1", "tenant": "tenant1",
"project_name": "somename",
'is_admin': True, 'is_admin': True,
'read_only': True, 'read_only': True,
'show_deleted': True, 'show_deleted': True,
'request_id': 'id1', 'request_id': 'id1',
"is_public_api": True, "is_public_api": True,
"domain_id": "domain_id1", "domain": "domain_id2",
"domain_name": "domain_name1", "user_domain": "domain_id3",
"user_domain_name": "TreeDomain",
"project_domain": "domain_id4",
"roles": None, "roles": None,
"overwrite": True "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('auth_token1', ctx_dict['auth_token'])
self.assertEqual('user1', ctx_dict['user']) self.assertEqual('user1', ctx_dict['user'])
self.assertEqual('tenant1', ctx_dict['tenant']) self.assertEqual('tenant1', ctx_dict['tenant'])
@ -88,8 +55,33 @@ class RequestContextTestCase(tests_base.TestCase):
self.assertTrue(ctx_dict['show_deleted']) self.assertTrue(ctx_dict['show_deleted'])
self.assertEqual('id1', ctx_dict['request_id']) self.assertEqual('id1', ctx_dict['request_id'])
self.assertTrue(ctx_dict['is_public_api']) self.assertTrue(ctx_dict['is_public_api'])
self.assertEqual('domain_id1', ctx_dict['domain_id']) self.assertEqual('domain_id3', ctx_dict['domain_id'])
self.assertEqual('domain_name1', ctx_dict['domain_name']) 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']) self.assertEqual([], ctx_dict['roles'])
def test_get_admin_context(self): def test_get_admin_context(self):

View File

@ -42,15 +42,28 @@ class PolicyInCodeTestCase(base.TestCase):
self.assertTrue(policy.check('public_api', creds, creds)) self.assertTrue(policy.check('public_api', creds, creds))
def test_show_password(self): def test_show_password(self):
creds = {'roles': [u'admin'], 'tenant': 'admin'} creds = {'roles': [u'admin'], 'project_name': 'admin',
self.assertTrue(policy.check('show_password', creds, creds)) '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): 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)) self.assertTrue(policy.check('baremetal:node:get', creds, creds))
def test_node_create(self): 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)) self.assertTrue(policy.check('baremetal:node:create', creds, creds))

View File

@ -179,11 +179,7 @@ class TestRequestContextSerializer(base.TestCase):
self.assertEqual(self.context.to_dict(), serialize_values) self.assertEqual(self.context.to_dict(), serialize_values)
def test_deserialize_context(self): def test_deserialize_context(self):
self.context.user = 'fake-user'
self.context.tenant = 'fake-tenant'
serialize_values = self.context.to_dict() serialize_values = self.context.to_dict()
new_context = self.serializer.deserialize_context(serialize_values) new_context = self.serializer.deserialize_context(serialize_values)
# Ironic RequestContext from_dict will pop 'user' and 'tenant' and self.assertEqual(serialize_values, new_context.to_dict())
# initialize to None. self.assertIsInstance(new_context, ironic_context.RequestContext)
self.assertIsNone(new_context.user)
self.assertIsNone(new_context.tenant)

View File

@ -209,8 +209,8 @@ class _TestObject(object):
base.IronicObject.obj_class_from_name, 'foo', '1.0') base.IronicObject.obj_class_from_name, 'foo', '1.0')
def test_with_alternate_context(self): def test_with_alternate_context(self):
ctxt1 = context.RequestContext('foo', 'foo') ctxt1 = context.RequestContext(auth_token='foo', tenant='foo')
ctxt2 = context.RequestContext('bar', tenant='alternate') ctxt2 = context.RequestContext(auth_token='bar', tenant='alternate')
obj = MyObj.query(ctxt1) obj = MyObj.query(ctxt1)
obj.update_test(ctxt2) obj.update_test(ctxt2)
self.assertEqual('alternate-context', obj.bar) self.assertEqual('alternate-context', obj.bar)

View File

@ -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.