Catch up to changes in RequestContext

RequestContext has a helpful "from_environ"
method that can handle all possible combinations
of auth information users can send our way
when manila is deployed with its Keystone auth
middleware. We could switch to that, so that
we don't have to maintain support for the
full list of current and deprecated auth
configuration options in our auth
middleware.

While we're there, we can also update the
"to_dict" and "from_dict" methods in manila's
context class to match the information we need.

Change-Id: I5d554caf82a1fc4f1dcfede3ea61159ddaeb342e
Closes-Bug: #1602081
Signed-off-by: Goutham Pacha Ravi <gouthampravi@gmail.com>
This commit is contained in:
Goutham Pacha Ravi 2021-02-15 17:01:13 -08:00
parent 0d8f415e86
commit c97f89f6e5
3 changed files with 67 additions and 75 deletions

View File

@ -73,24 +73,6 @@ class ManilaKeystoneContext(base_wsgi.Middleware):
@webob.dec.wsgify(RequestClass=base_wsgi.Request)
def __call__(self, req):
user_id = req.headers.get('X_USER')
user_id = req.headers.get('X_USER_ID', user_id)
if user_id is None:
LOG.debug("Neither X_USER_ID nor X_USER found in request")
return webob.exc.HTTPUnauthorized()
# get the roles
roles = [r.strip() for r in req.headers.get('X_ROLE', '').split(',')]
if 'X_TENANT_ID' in req.headers:
# This is the new header since Keystone went to ID/Name
project_id = req.headers['X_TENANT_ID']
else:
# This is for legacy compatibility
project_id = req.headers['X_TENANT']
# Get the auth token
auth_token = req.headers.get('X_AUTH_TOKEN',
req.headers.get('X_STORAGE_TOKEN'))
# Build a context, including the auth_token...
remote_address = req.remote_addr
if CONF.use_forwarded_for:
@ -105,12 +87,26 @@ class ManilaKeystoneContext(base_wsgi.Middleware):
raise webob.exc.HTTPInternalServerError(
_('Invalid service catalog json.'))
ctx = context.RequestContext(user_id,
project_id,
roles=roles,
auth_token=auth_token,
remote_address=remote_address,
service_catalog=service_catalog)
ctx = context.RequestContext.from_environ(
req.environ,
remote_address=remote_address,
service_catalog=service_catalog)
if ctx.user_id is None:
LOG.debug("Neither X_USER_ID nor X_USER found in request")
return webob.exc.HTTPUnauthorized()
if req.environ.get('X_PROJECT_DOMAIN_ID'):
ctx.project_domain_id = req.environ['X_PROJECT_DOMAIN_ID']
if req.environ.get('X_PROJECT_DOMAIN_NAME'):
ctx.project_domain_name = req.environ['X_PROJECT_DOMAIN_NAME']
if req.environ.get('X_USER_DOMAIN_ID'):
ctx.user_domain_id = req.environ['X_USER_DOMAIN_ID']
if req.environ.get('X_USER_DOMAIN_NAME'):
ctx.user_domain_name = req.environ['X_USER_DOMAIN_NAME']
req.environ['manila.context'] = ctx
return self.application

View File

@ -21,7 +21,6 @@ import copy
from oslo_context import context
from oslo_utils import timeutils
import six
from manila.i18n import _
from manila import policy
@ -34,43 +33,26 @@ class RequestContext(context.RequestContext):
"""
def __init__(self, user_id, project_id, is_admin=None, read_deleted="no",
roles=None, remote_address=None, timestamp=None,
request_id=None, auth_token=None, overwrite=True,
quota_class=None, service_catalog=None, **kwargs):
def __init__(self, user_id=None, project_id=None, is_admin=None,
read_deleted="no", project_name=None, remote_address=None,
timestamp=None, quota_class=None, service_catalog=None,
system_scope=None,
**kwargs):
"""Initialize RequestContext.
:param read_deleted: 'no' indicates deleted records are hidden, 'yes'
indicates deleted records are visible, 'only' indicates that
*only* deleted records are visible.
: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.
:param kwargs: Extra arguments passed transparently to
oslo_context.RequestContext.
"""
kwargs.setdefault('user_id', user_id)
kwargs.setdefault('project_id', project_id)
user = kwargs.pop('user', None)
tenant = kwargs.pop('tenant', None)
super(RequestContext, self).__init__(
auth_token=auth_token,
user=user_id or user,
tenant=project_id or tenant,
domain=kwargs.pop('domain', None),
user_domain=kwargs.pop('user_domain', None),
project_domain=kwargs.pop('project_domain', None),
is_admin=is_admin,
read_only=kwargs.pop('read_only', False),
show_deleted=kwargs.pop('show_deleted', False),
request_id=request_id,
resource_uuid=kwargs.pop('resource_uuid', None),
overwrite=overwrite,
roles=roles)
self.user_id = self.user
self.project_id = self.tenant
super(RequestContext, self).__init__(is_admin=is_admin, **kwargs)
self.project_name = project_name
if self.is_admin is None:
self.is_admin = policy.check_is_admin(self)
elif self.is_admin and 'admin' not in self.roles:
@ -79,17 +61,16 @@ class RequestContext(context.RequestContext):
self.remote_address = remote_address
if not timestamp:
timestamp = timeutils.utcnow()
if isinstance(timestamp, six.string_types):
timestamp = timeutils.parse_strtime(timestamp)
elif isinstance(timestamp, str):
timestamp = timeutils.parse_isotime(timestamp)
self.timestamp = timestamp
self.quota_class = quota_class
if service_catalog:
self.service_catalog = [s for s in service_catalog
if s.get('type') in ('compute', 'volume')]
else:
self.service_catalog = []
self.quota_class = quota_class
def _get_read_deleted(self):
return self._read_deleted
@ -107,20 +88,37 @@ class RequestContext(context.RequestContext):
def to_dict(self):
values = super(RequestContext, self).to_dict()
values.update({
'user_id': getattr(self, 'user_id', None),
'project_id': getattr(self, 'project_id', None),
'read_deleted': getattr(self, 'read_deleted', None),
'remote_address': getattr(self, 'remote_address', None),
'timestamp': self.timestamp.isoformat() if hasattr(
self, 'timestamp') else None,
'quota_class': getattr(self, 'quota_class', None),
'service_catalog': getattr(self, 'service_catalog', None)})
values['user_id'] = self.user_id
values['project_id'] = self.project_id
values['project_name'] = self.project_name
values['domain_id'] = self.domain_id
values['read_deleted'] = self.read_deleted
values['remote_address'] = self.remote_address
values['timestamp'] = self.timestamp.isoformat()
values['quota_class'] = self.quota_class
values['service_catalog'] = self.service_catalog
values['request_id'] = self.request_id
return values
@classmethod
def from_dict(cls, values):
return cls(**values)
return cls(
user_id=values.get('user_id'),
project_id=values.get('project_id'),
project_name=values.get('project_name'),
domain_id=values.get('domain_id'),
read_deleted=values.get('read_deleted'),
remote_address=values.get('remote_address'),
timestamp=values.get('timestamp'),
quota_class=values.get('quota_class'),
service_catalog=values.get('service_catalog'),
request_id=values.get('request_id'),
is_admin=values.get('is_admin'),
roles=values.get('roles'),
auth_token=values.get('auth_token'),
user_domain_id=values.get('user_domain_id'),
project_domain_id=values.get('project_domain_id')
)
def elevated(self, read_deleted=None, overwrite=False):
"""Return a version of this context with admin flag set."""

View File

@ -87,15 +87,13 @@ def enforce(context, action, target, do_raise=True):
"""
init()
if not isinstance(context, dict):
context = context.to_dict()
# Add the exception arguments if asked to do a raise
extra = {}
if do_raise:
extra.update(exc=exception.PolicyNotAuthorized, action=action,
do_raise=do_raise)
return _ENFORCER.enforce(action, target, context, **extra)
return _ENFORCER.enforce(action,
target,
context.to_policy_values(),
do_raise=do_raise,
exc=exception.PolicyNotAuthorized,
action=action)
def set_rules(rules, overwrite=True, use_conf=False):