Sync context with oslo.context

Heat makes a lot of variations to the basic oslo.context which are going
to make it very hard to reuse with features added to the base
oslo.context.

There are a number of changes here that will make the heat context
options more like those from oslo.context.

*) context.user and context.tenant are IDs, not names. This will be
   important for policy credentials.

*) kwargs should be passed through to base context so it can be extended
   in the base class.

Change-Id: Ib0d60c6af196ba5c00459110b7a6190cff916d6f
This commit is contained in:
Jamie Lennox 2016-01-16 14:04:54 +11:00
parent 98dec2c9de
commit 87a37f5db2
15 changed files with 103 additions and 70 deletions

View File

@ -92,12 +92,12 @@ class KeystoneClientV2(object):
auth_kwargs['trust_id'] = self.context.trust_id
auth_kwargs['tenant_id'] = self.context.tenant_id
elif self.context.auth_token is not None:
kwargs['tenant_name'] = self.context.tenant
kwargs['tenant_name'] = self.context.project_name
kwargs['token'] = self.context.auth_token
elif self.context.password is not None:
kwargs['username'] = self.context.username
kwargs['password'] = self.context.password
kwargs['tenant_name'] = self.context.tenant
kwargs['tenant_name'] = self.context.project_name
kwargs['tenant_id'] = self.context.tenant_id
else:
LOG.error(_LE("Keystone v2 API connection failed, no password "

View File

@ -47,8 +47,10 @@ class KeystonePasswordAuthProtocol(object):
if not tenant:
return self._reject_request(env, start_response, auth_url)
try:
ctx = context.RequestContext(username=username, password=password,
tenant_id=tenant, auth_url=auth_url,
ctx = context.RequestContext(username=username,
password=password,
tenant=tenant,
auth_url=auth_url,
user_domain_id=user_domain_id,
is_admin=False)
auth_ref = ctx.auth_plugin.get_access(self.session)

View File

@ -57,6 +57,17 @@ def list_opts():
yield TRUSTEE_CONF_GROUP, trustee_opts
def _moved_attr(new_name):
def getter(self):
return getattr(self, new_name)
def setter(self, value):
setattr(self, new_name, value)
return property(getter, setter)
class RequestContext(context.RequestContext):
"""Stores information about the security context.
@ -64,39 +75,33 @@ class RequestContext(context.RequestContext):
additional request information.
"""
def __init__(self, auth_token=None, username=None, password=None,
aws_creds=None, tenant=None, user_id=None,
tenant_id=None, auth_url=None, roles=None, is_admin=None,
read_only=False, show_deleted=False,
overwrite=True, trust_id=None, trustor_user_id=None,
request_id=None, auth_token_info=None, region_name=None,
auth_plugin=None, trusts_auth_plugin=None,
user_domain_id=None, project_domain_id=None, **kwargs):
def __init__(self, username=None, password=None, aws_creds=None,
auth_url=None, roles=None, is_admin=None, read_only=False,
show_deleted=False, overwrite=True, trust_id=None,
trustor_user_id=None, request_id=None, auth_token_info=None,
region_name=None, auth_plugin=None, trusts_auth_plugin=None,
user_domain_id=None, project_domain_id=None,
project_name=None, **kwargs):
"""Initialisation of the request context.
:param overwrite: Set to False to ensure that the greenthread local
copy of the index is not overwritten.
:param kwargs: Extra arguments that might be present, but we ignore
because they possibly came in from older rpc messages.
"""
super(RequestContext, self).__init__(auth_token=auth_token,
user=username, tenant=tenant,
is_admin=is_admin,
super(RequestContext, self).__init__(is_admin=is_admin,
read_only=read_only,
show_deleted=show_deleted,
request_id=request_id,
user_domain=user_domain_id,
project_domain=project_domain_id,
roles=roles,
overwrite=overwrite)
overwrite=overwrite,
**kwargs)
self.username = username
self.user_id = user_id
self.password = password
self.region_name = region_name
self.aws_creds = aws_creds
self.tenant_id = tenant_id
self.project_name = project_name
self.auth_token_info = auth_token_info
self.auth_url = auth_url
self._session = None
@ -123,6 +128,9 @@ class RequestContext(context.RequestContext):
self._object_cache[cache_cls] = cache
return cache
user_id = _moved_attr('user')
tenant_id = _moved_attr('tenant')
@property
def session(self):
if self._session is None:
@ -144,7 +152,7 @@ class RequestContext(context.RequestContext):
'user_id': self.user_id,
'password': self.password,
'aws_creds': self.aws_creds,
'tenant': self.tenant,
'tenant': self.project_name,
'tenant_id': self.tenant_id,
'trust_id': self.trust_id,
'trustor_user_id': self.trustor_user_id,
@ -152,7 +160,7 @@ class RequestContext(context.RequestContext):
'auth_url': self.auth_url,
'roles': self.roles,
'is_admin': self.is_admin,
'user': self.user,
'user': self.username,
'request_id': self.request_id,
'show_deleted': self.show_deleted,
'region_name': self.region_name,
@ -162,7 +170,26 @@ class RequestContext(context.RequestContext):
@classmethod
def from_dict(cls, values):
return cls(**values)
return cls(
auth_token=values.get('auth_token'),
username=values.get('username'),
user=values.get('user_id'),
password=values.get('password'),
aws_creds=values.get('aws_creds'),
project_name=values.get('tenant'),
tenant=values.get('tenant_id'),
trust_id=values.get('trust_id'),
trustor_user_id=values.get('trustor_user_id'),
auth_token_info=values.get('auth_token_info'),
auth_url=values.get('auth_url'),
roles=values.get('roles'),
is_admin=values.get('is_admin'),
request_id=values.get('request_id'),
show_deleted=values.get('show_deleted', False),
region_name=values.get('region_name'),
user_domain_id=values.get('user_domain'),
project_domain_id=values.get('project_domain')
)
@property
def keystone_v3_endpoint(self):
@ -330,7 +357,7 @@ class ContextMiddleware(wsgi.Middleware):
user_id = headers.get('X-User-Id')
user_domain_id = headers.get('X_User_Domain_Id')
token = headers.get('X-Auth-Token')
tenant = headers.get('X-Project-Name')
project_name = headers.get('X-Project-Name')
tenant_id = headers.get('X-Project-Id')
project_domain_id = headers.get('X_Project_Domain_Id')
region_name = headers.get('X-Region-Name')
@ -348,10 +375,11 @@ class ContextMiddleware(wsgi.Middleware):
req.context = self.make_context(
auth_token=token,
tenant=tenant, tenant_id=tenant_id,
tenant=tenant_id,
project_name=project_name,
aws_creds=aws_creds,
username=username,
user_id=user_id,
user=user_id,
password=password,
auth_url=auth_url,
roles=roles,

View File

@ -408,11 +408,11 @@ def format_notification_body(stack):
state = 'Unknown'
result = {
rpc_api.NOTIFY_TENANT_ID: stack.context.tenant_id,
rpc_api.NOTIFY_USER_ID: stack.context.user,
rpc_api.NOTIFY_USER_ID: stack.context.username,
# deprecated: please use rpc_api.NOTIFY_USERID for user id or
# rpc_api.NOTIFY_USERNAME for user name.
rpc_api.NOTIFY_USERID: stack.context.user_id,
rpc_api.NOTIFY_USERNAME: stack.context.user,
rpc_api.NOTIFY_USERNAME: stack.context.username,
rpc_api.NOTIFY_STACK_ID: stack.id,
rpc_api.NOTIFY_STACK_NAME: stack.name,
rpc_api.NOTIFY_STATE: state,

View File

@ -37,7 +37,7 @@ class CeilometerClientPlugin(client_plugin.ClientPlugin):
args = {
'auth_url': con.auth_url,
'service_type': self.METERING,
'project_name': con.tenant,
'project_name': con.project_name,
'token': lambda: self.auth_token,
'user_domain_id': con.user_domain,
'project_domain_id': con.project_domain,

View File

@ -44,7 +44,7 @@ class SwiftClientPlugin(client_plugin.ClientPlugin):
endpoint_type = self._get_client_option(CLIENT_NAME, 'endpoint_type')
args = {
'auth_version': '2.0',
'tenant_name': con.tenant,
'tenant_name': con.project_name,
'user': con.username,
'key': None,
'authurl': None,

View File

@ -132,11 +132,11 @@ class S3Bucket(resource.Resource):
con = self.context
ac = self.properties[self.ACCESS_CONTROL]
tenant_username = '%s:%s' % (con.tenant, con.username)
tenant_username = '%s:%s' % (con.project_name, con.username)
if ac in ('PublicRead', 'PublicReadWrite'):
headers['X-Container-Read'] = '.r:*'
elif ac == 'AuthenticatedRead':
headers['X-Container-Read'] = con.tenant
headers['X-Container-Read'] = con.project_name
else:
headers['X-Container-Read'] = tenant_username

View File

@ -87,7 +87,7 @@ class TestPolicyEnforce(common.HeatTestCase):
def setUp(self):
super(TestPolicyEnforce, self).setUp()
self.req = wsgi.Request({})
self.req.context = context.RequestContext(tenant_id='foo',
self.req.context = context.RequestContext(tenant='foo',
is_admin=False)
class DummyController(object):
@ -112,7 +112,7 @@ class TestPolicyEnforce(common.HeatTestCase):
@mock.patch.object(policy.Enforcer, 'enforce')
def test_policy_enforce_tenant_mismatch_is_admin(self, mock_enforce):
self.req.context = context.RequestContext(tenant_id='foo',
self.req.context = context.RequestContext(tenant='foo',
is_admin=True)
mock_enforce.return_value = True

View File

@ -27,7 +27,7 @@ class SwiftClientPluginTestCase(common.HeatTestCase):
super(SwiftClientPluginTestCase, self).setUp()
self.swift_client = mock.Mock()
self.context = utils.dummy_context()
self.context.tenant_id = "demo"
self.context.tenant = "demo"
c = self.context.clients
self.swift_plugin = c.client_plugin('swift')
self.swift_plugin.client = lambda: self.swift_client

View File

@ -359,11 +359,11 @@ class SqlAlchemyTest(common.HeatTestCase):
st = db_api.stack_get_by_name(self.ctx, 'stack')
self.assertEqual(UUID1, st.id)
self.ctx.tenant_id = UUID3
self.ctx.tenant = UUID3
st = db_api.stack_get_by_name(self.ctx, 'stack')
self.assertIsNone(st)
self.ctx.tenant_id = UUID2
self.ctx.tenant = UUID2
st = db_api.stack_get_by_name(self.ctx, 'stack')
self.assertEqual(UUID1, st.id)
@ -401,12 +401,12 @@ class SqlAlchemyTest(common.HeatTestCase):
self.assertEqual(UUID2, result.id)
self.ctx.tenant_id = str(uuid.uuid4())
self.ctx.tenant = str(uuid.uuid4())
result = db_api.stack_get_by_name_and_owner_id(self.ctx, 'stack2',
None)
self.assertIsNone(result)
self.ctx.tenant_id = UUID3
self.ctx.tenant = UUID3
result = db_api.stack_get_by_name_and_owner_id(self.ctx, 'stack2',
stack1.id)
@ -1011,8 +1011,8 @@ class SqlAlchemyTest(common.HeatTestCase):
self.ctx.password = None
self.ctx.trust_id = 'atrust123'
self.ctx.trustor_user_id = 'atrustor123'
self.ctx.tenant_id = 'atenant123'
self.ctx.tenant = 'atenant'
self.ctx.tenant = 'atenant123'
self.ctx.project_name = 'atenant'
self.ctx.auth_url = 'anauthurl'
self.ctx.region_name = 'aregion'
db_creds = db_api.user_creds_create(self.ctx)
@ -1079,7 +1079,7 @@ class SqlAlchemyTest(common.HeatTestCase):
self.assertEqual(tenant_id, config.tenant)
self.assertEqual('Heat::Shell', config.group)
self.assertEqual(conf, config.config['config'])
self.ctx.tenant_id = None
self.ctx.tenant = None
self.assertRaises(
exception.NotFound,
db_api.software_config_get,
@ -1178,7 +1178,7 @@ class SqlAlchemyTest(common.HeatTestCase):
values['stack_user_project_id'], deployment.stack_user_project_id)
# assert not found with invalid context tenant
self.ctx.tenant_id = str(uuid.uuid4())
self.ctx.tenant = str(uuid.uuid4())
self.assertRaises(
exception.NotFound,
db_api.software_deployment_get,
@ -1186,7 +1186,7 @@ class SqlAlchemyTest(common.HeatTestCase):
deployment_id)
# assert found with stack_user_project_id context tenant
self.ctx.tenant_id = deployment.stack_user_project_id
self.ctx.tenant = deployment.stack_user_project_id
deployment = db_api.software_deployment_get(self.ctx, deployment_id)
self.assertIsNotNone(deployment)
self.assertEqual(values['tenant'], deployment.tenant)
@ -1307,7 +1307,7 @@ class SqlAlchemyTest(common.HeatTestCase):
values = {'tenant': self.ctx.tenant_id, 'status': 'IN_PROGRESS',
'stack_id': stack.id}
snapshot = db_api.snapshot_create(self.ctx, values)
self.ctx.tenant_id = str(uuid.uuid4())
self.ctx.tenant = str(uuid.uuid4())
self.assertRaises(
exception.NotFound,
db_api.snapshot_get,
@ -1584,7 +1584,7 @@ class DBAPIUserCredsTest(common.HeatTestCase):
self.assertEqual('trustor_id', user_creds['trustor_user_id'])
self.assertIsNone(user_creds['username'])
self.assertIsNone(user_creds['password'])
self.assertEqual(self.ctx.tenant, user_creds['tenant'])
self.assertEqual(self.ctx.project_name, user_creds['tenant'])
self.assertEqual(self.ctx.tenant_id, user_creds['tenant_id'])
def test_user_creds_create_password(self):
@ -1831,14 +1831,14 @@ class DBAPIStackTest(common.HeatTestCase):
def test_stack_get_returns_none_if_tenant_id_does_not_match(self):
stack = create_stack(self.ctx, self.template, self.user_creds)
self.ctx.tenant_id = 'abc'
self.ctx.tenant = 'abc'
stack = db_api.stack_get(self.ctx, UUID1, show_deleted=False)
self.assertIsNone(stack)
def test_stack_get_tenant_is_stack_user_project_id(self):
stack = create_stack(self.ctx, self.template, self.user_creds,
stack_user_project_id='astackuserproject')
self.ctx.tenant_id = 'astackuserproject'
self.ctx.tenant = 'astackuserproject'
ret_stack = db_api.stack_get(self.ctx, stack.id, show_deleted=False)
self.assertIsNotNone(ret_stack)
self.assertEqual(stack.id, ret_stack.id)
@ -1847,7 +1847,6 @@ class DBAPIStackTest(common.HeatTestCase):
def test_stack_get_can_return_a_stack_from_different_tenant(self):
stack = create_stack(self.ctx, self.template, self.user_creds)
self.ctx.tenant_id = 'abc'
# with tenant_safe = False
ret_stack = db_api.stack_get(self.ctx, stack.id,
show_deleted=False, tenant_safe=False)
self.assertEqual(stack.id, ret_stack.id)
@ -1869,7 +1868,7 @@ class DBAPIStackTest(common.HeatTestCase):
self.assertIsNone(db_api.stack_get_by_name(self.ctx, 'abc'))
self.ctx.tenant_id = 'abc'
self.ctx.tenant = 'abc'
self.assertIsNone(db_api.stack_get_by_name(self.ctx, 'abc'))
def test_stack_get_all(self):
@ -1917,15 +1916,15 @@ class DBAPIStackTest(common.HeatTestCase):
[create_stack(self.ctx, self.template, self.user_creds,
**val) for val in values]
self.ctx.tenant_id = UUID1
self.ctx.tenant = UUID1
stacks = db_api.stack_get_all(self.ctx)
self.assertEqual(2, len(stacks))
self.ctx.tenant_id = UUID2
self.ctx.tenant = UUID2
stacks = db_api.stack_get_all(self.ctx)
self.assertEqual(3, len(stacks))
self.ctx.tenant_id = UUID3
self.ctx.tenant = UUID3
self.assertEqual([], db_api.stack_get_all(self.ctx))
def test_stack_get_all_with_tenant_safe_false(self):
@ -1968,10 +1967,10 @@ class DBAPIStackTest(common.HeatTestCase):
[create_stack(self.ctx, self.template, self.user_creds,
**val) for val in values]
self.ctx.tenant_id = UUID1
self.ctx.tenant = UUID1
self.assertEqual(2, db_api.stack_count_all(self.ctx))
self.ctx.tenant_id = UUID2
self.ctx.tenant = UUID2
self.assertEqual(3, db_api.stack_count_all(self.ctx))
def test_stack_count_all_with_tenant_safe_false(self):
@ -2530,7 +2529,7 @@ class DBAPIEventTest(common.HeatTestCase):
]
[create_event(self.ctx, **val) for val in values]
self.ctx.tenant_id = 'tenant1'
self.ctx.tenant = 'tenant1'
events = db_api.event_get_all_by_tenant(self.ctx)
self.assertEqual(2, len(events))
marker = events[0].uuid
@ -2554,7 +2553,7 @@ class DBAPIEventTest(common.HeatTestCase):
sort_keys=sort_keys)
self.assertEqual(2, len(events))
self.ctx.tenant_id = 'tenant2'
self.ctx.tenant = 'tenant2'
events = db_api.event_get_all_by_tenant(self.ctx)
self.assertEqual(1, len(events))
@ -2568,11 +2567,11 @@ class DBAPIEventTest(common.HeatTestCase):
]
[create_event(self.ctx, **val) for val in values]
self.ctx.tenant_id = 'tenant1'
self.ctx.tenant = 'tenant1'
events = db_api.event_get_all_by_stack(self.ctx, self.stack1.id)
self.assertEqual(2, len(events))
self.ctx.tenant_id = 'tenant2'
self.ctx.tenant = 'tenant2'
events = db_api.event_get_all_by_stack(self.ctx, self.stack2.id)
self.assertEqual(1, len(events))

View File

@ -157,7 +157,7 @@ class CeilometerAlarmTest(common.HeatTestCase):
temp = template_format.parse(template)
template = tmpl.Template(temp)
ctx = utils.dummy_context()
ctx.tenant_id = 'test_tenant'
ctx.tenant = 'test_tenant'
stack = parser.Stack(ctx, utils.random_name(), template,
disable_rollback=True)
stack.store()

View File

@ -59,9 +59,9 @@ class TestRequestContext(common.HeatTestCase):
username=self.ctx.get('username'),
password=self.ctx.get('password'),
aws_creds=self.ctx.get('aws_creds'),
tenant=self.ctx.get('tenant'),
tenant_id=self.ctx.get('tenant_id'),
user_id=self.ctx.get('user_id'),
project_name=self.ctx.get('tenant'),
tenant=self.ctx.get('tenant_id'),
user=self.ctx.get('user_id'),
auth_url=self.ctx.get('auth_url'),
roles=self.ctx.get('roles'),
show_deleted=self.ctx.get('show_deleted'),
@ -69,7 +69,6 @@ class TestRequestContext(common.HeatTestCase):
auth_token_info=self.ctx.get('auth_token_info'),
trustor_user_id=self.ctx.get('trustor_user_id'),
trust_id=self.ctx.get('trust_id'),
user=self.ctx.get('user'),
region_name=self.ctx.get('region_name'),
user_domain_id=self.ctx.get('user_domain'),
project_domain_id=self.ctx.get('project_domain'))
@ -91,6 +90,11 @@ class TestRequestContext(common.HeatTestCase):
k == 'user_domain_id' or
k == 'project_domain_id'):
continue
# these values are different between attribute and context
if k == 'tenant' or k == 'user':
continue
self.assertEqual(self.ctx.get(k), ctx.to_dict().get(k))
override = '%s_override' % k
setattr(ctx, k, override)

View File

@ -396,7 +396,7 @@ class StackServiceAuthorizeTest(common.HeatTestCase):
self.ctx, self.stack, 'NoSuchResource'))
# not matching credential_id
self.ctx.user_id = str(uuid.uuid4())
self.ctx.user = str(uuid.uuid4())
self.assertFalse(self.eng._authorize_stack_user(
self.ctx, self.stack, 'WebServer'))

View File

@ -95,7 +95,7 @@ class SignalTest(common.HeatTestCase):
tpl = template.Template(template_format.parse(template_string))
ctx = utils.dummy_context()
ctx.tenant_id = 'test_tenant'
ctx.tenant = 'test_tenant'
stack = stk.Stack(ctx, stack_name, tpl, disable_rollback=True)
with utils.UUIDStub(stack_id):
stack.store()

View File

@ -68,7 +68,7 @@ class StackTest(common.HeatTestCase):
self.assertEqual('bar', self.stack.tenant_id)
def test_stack_reads_tenant_from_context_if_empty(self):
self.ctx.tenant_id = 'foo'
self.ctx.tenant = 'foo'
self.stack = stack.Stack(self.ctx, 'test_stack', self.tmpl,
tenant_id=None)
self.assertEqual('foo', self.stack.tenant_id)
@ -493,11 +493,11 @@ class StackTest(common.HeatTestCase):
self.assertEqual(identifier.arn(), newstack.parameters['AWS::StackId'])
def test_load_reads_tenant_id(self):
self.ctx.tenant_id = 'foobar'
self.ctx.tenant = 'foobar'
self.stack = stack.Stack(self.ctx, 'stack_name', self.tmpl)
self.stack.store()
stack_id = self.stack.id
self.ctx.tenant_id = None
self.ctx.tenant = None
self.stack = stack.Stack.load(self.ctx, stack_id=stack_id)
self.assertEqual('foobar', self.stack.tenant_id)