Refactor Authorization:
Merged the decorator logic into a single function that calls check_policy. Moved authorization logic in authorize.py Prep for oslo-context fixes Change-Id: Id1452db131740c68b3756a819792f9a60cff239c
This commit is contained in:
parent
e18923daa1
commit
7d8f2fcfb9
@ -22,9 +22,9 @@ from oslo_log import log
|
|||||||
from six.moves import urllib
|
from six.moves import urllib
|
||||||
|
|
||||||
from keystone.assignment import schema
|
from keystone.assignment import schema
|
||||||
|
from keystone.common import authorization
|
||||||
from keystone.common import controller
|
from keystone.common import controller
|
||||||
from keystone.common import dependency
|
from keystone.common import dependency
|
||||||
from keystone.common import utils
|
|
||||||
from keystone.common import validation
|
from keystone.common import validation
|
||||||
from keystone.common import wsgi
|
from keystone.common import wsgi
|
||||||
import keystone.conf
|
import keystone.conf
|
||||||
@ -50,7 +50,7 @@ class TenantAssignment(controller.V2Controller):
|
|||||||
Doesn't care about token scopedness.
|
Doesn't care about token scopedness.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
token_ref = utils.get_token_ref(request.context_dict)
|
token_ref = authorization.get_token_ref(request.context_dict)
|
||||||
|
|
||||||
tenant_refs = (
|
tenant_refs = (
|
||||||
self.assignment_api.list_projects_for_user(token_ref.user_id))
|
self.assignment_api.list_projects_for_user(token_ref.user_id))
|
||||||
@ -964,7 +964,7 @@ class RoleAssignmentV3(controller.V3Controller):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
ref = {}
|
ref = {}
|
||||||
for filter, value in protection_info['filter_attr'].items():
|
for filter, value in protection_info.get('filter_attr', {}).items():
|
||||||
if filter == 'scope.project.id' and value:
|
if filter == 'scope.project.id' and value:
|
||||||
ref['project'] = self.resource_api.get_project(value)
|
ref['project'] = self.resource_api.get_project(value)
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ import six
|
|||||||
|
|
||||||
from keystone.auth import core
|
from keystone.auth import core
|
||||||
from keystone.auth import schema
|
from keystone.auth import schema
|
||||||
|
from keystone.common import authorization
|
||||||
from keystone.common import controller
|
from keystone.common import controller
|
||||||
from keystone.common import dependency
|
from keystone.common import dependency
|
||||||
from keystone.common import utils
|
from keystone.common import utils
|
||||||
@ -298,7 +299,7 @@ class Auth(controller.V3Controller):
|
|||||||
@controller.protected()
|
@controller.protected()
|
||||||
def check_token(self, request):
|
def check_token(self, request):
|
||||||
token_id = request.context_dict.get('subject_token_id')
|
token_id = request.context_dict.get('subject_token_id')
|
||||||
window_seconds = self._token_validation_window(request)
|
window_seconds = authorization.token_validation_window(request)
|
||||||
token_data = self.token_provider_api.validate_token(
|
token_data = self.token_provider_api.validate_token(
|
||||||
token_id, window_seconds=window_seconds)
|
token_id, window_seconds=window_seconds)
|
||||||
# NOTE(morganfainberg): The code in
|
# NOTE(morganfainberg): The code in
|
||||||
@ -314,7 +315,7 @@ class Auth(controller.V3Controller):
|
|||||||
@controller.protected()
|
@controller.protected()
|
||||||
def validate_token(self, request):
|
def validate_token(self, request):
|
||||||
token_id = request.context_dict.get('subject_token_id')
|
token_id = request.context_dict.get('subject_token_id')
|
||||||
window_seconds = self._token_validation_window(request)
|
window_seconds = authorization.token_validation_window(request)
|
||||||
include_catalog = 'nocatalog' not in request.params
|
include_catalog = 'nocatalog' not in request.params
|
||||||
token_data = self.token_provider_api.validate_token(
|
token_data = self.token_provider_api.validate_token(
|
||||||
token_id, window_seconds=window_seconds)
|
token_id, window_seconds=window_seconds)
|
||||||
|
@ -15,14 +15,19 @@
|
|||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# 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 copy
|
||||||
|
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
|
from oslo_utils import strutils
|
||||||
|
|
||||||
|
from keystone.common import utils
|
||||||
|
from keystone import conf
|
||||||
from keystone import exception
|
from keystone import exception
|
||||||
from keystone.i18n import _
|
from keystone.i18n import _
|
||||||
from keystone.models import token_model
|
from keystone.models import token_model
|
||||||
|
|
||||||
|
|
||||||
|
CONF = conf.CONF
|
||||||
AUTH_CONTEXT_ENV = 'KEYSTONE_AUTH_CONTEXT'
|
AUTH_CONTEXT_ENV = 'KEYSTONE_AUTH_CONTEXT'
|
||||||
"""Environment variable used to convey the Keystone auth context.
|
"""Environment variable used to convey the Keystone auth context.
|
||||||
|
|
||||||
@ -111,3 +116,151 @@ def token_to_auth_context(token):
|
|||||||
|
|
||||||
auth_context['is_admin_project'] = token.is_admin_project
|
auth_context['is_admin_project'] = token.is_admin_project
|
||||||
return auth_context
|
return auth_context
|
||||||
|
|
||||||
|
|
||||||
|
def assert_admin(app, request):
|
||||||
|
"""Ensure the user is an admin.
|
||||||
|
|
||||||
|
:raises keystone.exception.Unauthorized: if a token could not be
|
||||||
|
found/authorized, a user is invalid, or a tenant is
|
||||||
|
invalid/not scoped.
|
||||||
|
:raises keystone.exception.Forbidden: if the user is not an admin and
|
||||||
|
does not have the admin role
|
||||||
|
|
||||||
|
"""
|
||||||
|
request.assert_authenticated()
|
||||||
|
|
||||||
|
if not request.context.is_admin:
|
||||||
|
user_token_ref = get_token_ref(request.context_dict)
|
||||||
|
|
||||||
|
creds = copy.deepcopy(user_token_ref.metadata)
|
||||||
|
|
||||||
|
try:
|
||||||
|
creds['user_id'] = user_token_ref.user_id
|
||||||
|
except exception.UnexpectedError:
|
||||||
|
LOG.debug('Invalid user')
|
||||||
|
raise exception.Unauthorized(_('Invalid user'))
|
||||||
|
|
||||||
|
if user_token_ref.project_scoped:
|
||||||
|
creds['tenant_id'] = user_token_ref.project_id
|
||||||
|
else:
|
||||||
|
LOG.debug('Invalid tenant')
|
||||||
|
raise exception.Unauthorized(_('Invalid tenant'))
|
||||||
|
|
||||||
|
creds['roles'] = user_token_ref.role_names
|
||||||
|
# Accept either is_admin or the admin role
|
||||||
|
app.policy_api.enforce(creds, 'admin_required', {})
|
||||||
|
|
||||||
|
|
||||||
|
def _build_policy_check_credentials(action, context, kwargs):
|
||||||
|
kwargs_str = ', '.join(['%s=%s' % (k, kwargs[k]) for k in kwargs])
|
||||||
|
kwargs_str = strutils.mask_password(kwargs_str)
|
||||||
|
msg = 'RBAC: Authorizing %(action)s(%(kwargs)s)'
|
||||||
|
LOG.debug(msg, {'action': action, 'kwargs': kwargs_str})
|
||||||
|
|
||||||
|
return context['environment'].get(AUTH_CONTEXT_ENV, {})
|
||||||
|
|
||||||
|
|
||||||
|
def _handle_member_from_driver(self, policy_dict, **kwargs):
|
||||||
|
# Check to see if we need to include the target entity in our
|
||||||
|
# policy checks. We deduce this by seeing if the class has
|
||||||
|
# specified a get_member() method and that kwargs contains the
|
||||||
|
# appropriate entity id.
|
||||||
|
if (hasattr(self, 'get_member_from_driver') and
|
||||||
|
self.get_member_from_driver is not None):
|
||||||
|
key = '%s_id' % self.member_name
|
||||||
|
if key in kwargs:
|
||||||
|
ref = self.get_member_from_driver(kwargs[key])
|
||||||
|
policy_dict['target'] = {self.member_name: ref}
|
||||||
|
|
||||||
|
|
||||||
|
def token_validation_window(request):
|
||||||
|
# NOTE(jamielennox): it's dumb that i have to put this here. We should
|
||||||
|
# only validate subject token in one place.
|
||||||
|
|
||||||
|
allow_expired = request.params.get('allow_expired')
|
||||||
|
allow_expired = strutils.bool_from_string(allow_expired, default=False)
|
||||||
|
return CONF.token.allow_expired_window if allow_expired else 0
|
||||||
|
|
||||||
|
|
||||||
|
def _handle_subject_token_id(self, request, policy_dict):
|
||||||
|
if request.context_dict.get('subject_token_id') is not None:
|
||||||
|
window_seconds = token_validation_window(request)
|
||||||
|
|
||||||
|
token_ref = token_model.KeystoneToken(
|
||||||
|
token_id=request.context_dict['subject_token_id'],
|
||||||
|
token_data=self.token_provider_api.validate_token(
|
||||||
|
request.context_dict['subject_token_id'],
|
||||||
|
window_seconds=window_seconds))
|
||||||
|
policy_dict.setdefault('target', {})
|
||||||
|
policy_dict['target'].setdefault(self.member_name, {})
|
||||||
|
policy_dict['target'][self.member_name]['user_id'] = (
|
||||||
|
token_ref.user_id)
|
||||||
|
try:
|
||||||
|
user_domain_id = token_ref.user_domain_id
|
||||||
|
except exception.UnexpectedError:
|
||||||
|
user_domain_id = None
|
||||||
|
if user_domain_id:
|
||||||
|
policy_dict['target'][self.member_name].setdefault(
|
||||||
|
'user', {})
|
||||||
|
policy_dict['target'][self.member_name][
|
||||||
|
'user'].setdefault('domain', {})
|
||||||
|
policy_dict['target'][self.member_name]['user'][
|
||||||
|
'domain']['id'] = (
|
||||||
|
user_domain_id)
|
||||||
|
|
||||||
|
|
||||||
|
def check_protection(controller, request, prep_info, target_attr=None,
|
||||||
|
*args, **kwargs):
|
||||||
|
"""Provide call protection for complex target attributes.
|
||||||
|
|
||||||
|
As well as including the standard parameters from the original API
|
||||||
|
call (which is passed in prep_info), this call will add in any
|
||||||
|
additional entities or attributes (passed in target_attr), so that
|
||||||
|
they can be referenced by policy rules.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if request.context.is_admin:
|
||||||
|
LOG.warning('RBAC: Bypassing authorization')
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
action = 'identity:%s' % prep_info['f_name']
|
||||||
|
# TODO(henry-nash) need to log the target attributes as well
|
||||||
|
creds = _build_policy_check_credentials(
|
||||||
|
action, request.context_dict, prep_info['input_attr'])
|
||||||
|
# Build the dict the policy engine will check against from both the
|
||||||
|
# parameters passed into the call we are protecting (which was
|
||||||
|
# stored in the prep_info by protected()), plus the target
|
||||||
|
# attributes provided.
|
||||||
|
policy_dict = {}
|
||||||
|
_handle_member_from_driver(controller, policy_dict, **kwargs)
|
||||||
|
_handle_subject_token_id(controller, request, policy_dict)
|
||||||
|
|
||||||
|
if target_attr:
|
||||||
|
policy_dict = {'target': target_attr}
|
||||||
|
policy_dict.update(prep_info['input_attr'])
|
||||||
|
if 'filter_attr' in prep_info:
|
||||||
|
policy_dict.update(prep_info['filter_attr'])
|
||||||
|
|
||||||
|
for key in kwargs:
|
||||||
|
policy_dict[key] = kwargs[key]
|
||||||
|
controller.policy_api.enforce(creds,
|
||||||
|
action,
|
||||||
|
utils.flatten_dict(policy_dict))
|
||||||
|
LOG.debug('RBAC: Authorization granted')
|
||||||
|
|
||||||
|
|
||||||
|
def get_token_ref(context):
|
||||||
|
"""Retrieve KeystoneToken object from the auth context and returns it.
|
||||||
|
|
||||||
|
:param dict context: The request context.
|
||||||
|
:raises keystone.exception.Unauthorized: If auth context cannot be found.
|
||||||
|
:returns: The KeystoneToken object.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Retrieve the auth context that was prepared by AuthContextMiddleware.
|
||||||
|
auth_context = (context['environment'][AUTH_CONTEXT_ENV])
|
||||||
|
return auth_context['token']
|
||||||
|
except KeyError:
|
||||||
|
LOG.warning("Couldn't find the auth context.")
|
||||||
|
raise exception.Unauthorized()
|
||||||
|
@ -17,19 +17,16 @@ import uuid
|
|||||||
|
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
from oslo_log import versionutils
|
from oslo_log import versionutils
|
||||||
from oslo_utils import strutils
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from keystone.common import authorization
|
from keystone.common import authorization
|
||||||
from keystone.common import dependency
|
from keystone.common import dependency
|
||||||
from keystone.common import driver_hints
|
from keystone.common import driver_hints
|
||||||
from keystone.common import policy
|
|
||||||
from keystone.common import utils
|
from keystone.common import utils
|
||||||
from keystone.common import wsgi
|
from keystone.common import wsgi
|
||||||
import keystone.conf
|
import keystone.conf
|
||||||
from keystone import exception
|
from keystone import exception
|
||||||
from keystone.i18n import _
|
from keystone.i18n import _
|
||||||
from keystone.models import token_model
|
|
||||||
|
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
@ -72,15 +69,6 @@ def v2_auth_deprecated(f):
|
|||||||
return wrapper()
|
return wrapper()
|
||||||
|
|
||||||
|
|
||||||
def _build_policy_check_credentials(self, action, context, kwargs):
|
|
||||||
kwargs_str = ', '.join(['%s=%s' % (k, kwargs[k]) for k in kwargs])
|
|
||||||
kwargs_str = strutils.mask_password(kwargs_str)
|
|
||||||
msg = 'RBAC: Authorizing %(action)s(%(kwargs)s)'
|
|
||||||
LOG.debug(msg, {'action': action, 'kwargs': kwargs_str})
|
|
||||||
|
|
||||||
return context['environment'].get(authorization.AUTH_CONTEXT_ENV, {})
|
|
||||||
|
|
||||||
|
|
||||||
def protected(callback=None):
|
def protected(callback=None):
|
||||||
"""Wrap API calls with role based access controls (RBAC).
|
"""Wrap API calls with role based access controls (RBAC).
|
||||||
|
|
||||||
@ -97,69 +85,12 @@ def protected(callback=None):
|
|||||||
def wrapper(f):
|
def wrapper(f):
|
||||||
@functools.wraps(f)
|
@functools.wraps(f)
|
||||||
def inner(self, request, *args, **kwargs):
|
def inner(self, request, *args, **kwargs):
|
||||||
request.assert_authenticated()
|
check_function = authorization.check_protection
|
||||||
|
if callback is not None:
|
||||||
|
check_function = callback
|
||||||
|
|
||||||
if request.context.is_admin:
|
protected_wrapper(
|
||||||
LOG.warning('RBAC: Bypassing authorization')
|
self, f, check_function, request, None, *args, **kwargs)
|
||||||
elif callback is not None:
|
|
||||||
prep_info = {'f_name': f.__name__,
|
|
||||||
'input_attr': kwargs}
|
|
||||||
callback(self,
|
|
||||||
request,
|
|
||||||
prep_info,
|
|
||||||
*args,
|
|
||||||
**kwargs)
|
|
||||||
else:
|
|
||||||
action = 'identity:%s' % f.__name__
|
|
||||||
creds = _build_policy_check_credentials(self,
|
|
||||||
action,
|
|
||||||
request.context_dict,
|
|
||||||
kwargs)
|
|
||||||
|
|
||||||
policy_dict = {}
|
|
||||||
|
|
||||||
# Check to see if we need to include the target entity in our
|
|
||||||
# policy checks. We deduce this by seeing if the class has
|
|
||||||
# specified a get_member() method and that kwargs contains the
|
|
||||||
# appropriate entity id.
|
|
||||||
if (hasattr(self, 'get_member_from_driver') and
|
|
||||||
self.get_member_from_driver is not None):
|
|
||||||
key = '%s_id' % self.member_name
|
|
||||||
if key in kwargs:
|
|
||||||
ref = self.get_member_from_driver(kwargs[key])
|
|
||||||
policy_dict['target'] = {self.member_name: ref}
|
|
||||||
|
|
||||||
# TODO(henry-nash): Move this entire code to a member
|
|
||||||
# method inside v3 Auth
|
|
||||||
if request.context_dict.get('subject_token_id') is not None:
|
|
||||||
window_seconds = self._token_validation_window(request)
|
|
||||||
token_ref = token_model.KeystoneToken(
|
|
||||||
token_id=request.context_dict['subject_token_id'],
|
|
||||||
token_data=self.token_provider_api.validate_token(
|
|
||||||
request.context_dict['subject_token_id'],
|
|
||||||
window_seconds=window_seconds))
|
|
||||||
policy_dict.setdefault('target', {})
|
|
||||||
policy_dict['target'].setdefault(self.member_name, {})
|
|
||||||
policy_dict['target'][self.member_name]['user_id'] = (
|
|
||||||
token_ref.user_id)
|
|
||||||
try:
|
|
||||||
user_domain_id = token_ref.user_domain_id
|
|
||||||
except exception.UnexpectedError:
|
|
||||||
user_domain_id = None
|
|
||||||
if user_domain_id:
|
|
||||||
policy_dict['target'][self.member_name].setdefault(
|
|
||||||
'user', {})
|
|
||||||
policy_dict['target'][self.member_name][
|
|
||||||
'user'].setdefault('domain', {})
|
|
||||||
policy_dict['target'][self.member_name]['user'][
|
|
||||||
'domain']['id'] = (
|
|
||||||
user_domain_id)
|
|
||||||
|
|
||||||
# Add in the kwargs, which means that any entity provided as a
|
|
||||||
# parameter for calls like create and update will be included.
|
|
||||||
policy_dict.update(kwargs)
|
|
||||||
policy.enforce(creds, action, utils.flatten_dict(policy_dict))
|
|
||||||
LOG.debug('RBAC: Authorization granted')
|
|
||||||
return f(self, request, *args, **kwargs)
|
return f(self, request, *args, **kwargs)
|
||||||
return inner
|
return inner
|
||||||
return wrapper
|
return wrapper
|
||||||
@ -178,21 +109,7 @@ def filterprotected(*filters, **callback):
|
|||||||
entities needed and then call check_protection() in the V3Controller class.
|
entities needed and then call check_protection() in the V3Controller class.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def _filterprotected(f):
|
def _handle_filters(filters, request):
|
||||||
@functools.wraps(f)
|
|
||||||
def wrapper(self, request, **kwargs):
|
|
||||||
request.assert_authenticated()
|
|
||||||
|
|
||||||
if not request.context.is_admin:
|
|
||||||
# The target dict for the policy check will include:
|
|
||||||
#
|
|
||||||
# - Any query filter parameters
|
|
||||||
# - Data from the main url (which will be in the kwargs
|
|
||||||
# parameter), which although most of our APIs do not utilize,
|
|
||||||
# in theory you could have.
|
|
||||||
#
|
|
||||||
|
|
||||||
# First build the dict of filter parameters
|
|
||||||
target = dict()
|
target = dict()
|
||||||
if filters:
|
if filters:
|
||||||
for item in filters:
|
for item in filters:
|
||||||
@ -202,38 +119,45 @@ def filterprotected(*filters, **callback):
|
|||||||
LOG.debug('RBAC: Adding query filter params (%s)', (
|
LOG.debug('RBAC: Adding query filter params (%s)', (
|
||||||
', '.join(['%s=%s' % (item, target[item])
|
', '.join(['%s=%s' % (item, target[item])
|
||||||
for item in target])))
|
for item in target])))
|
||||||
|
return target
|
||||||
|
|
||||||
|
def _filterprotected(f):
|
||||||
|
@functools.wraps(f)
|
||||||
|
def wrapper(self, request, **kwargs):
|
||||||
|
filter_attr = _handle_filters(filters, request)
|
||||||
|
check_function = authorization.check_protection
|
||||||
if 'callback' in callback and callback['callback'] is not None:
|
if 'callback' in callback and callback['callback'] is not None:
|
||||||
# A callback has been specified to load additional target
|
# A callback has been specified to load additional target
|
||||||
# data, so pass it the formal url params as well as the
|
# data, so pass it the formal url params as well as the
|
||||||
# list of filters, so it can augment these and then call
|
# list of filters, so it can augment these and then call
|
||||||
# the check_protection() method.
|
# the check_protection() method.
|
||||||
prep_info = {'f_name': f.__name__,
|
check_function = callback['callback']
|
||||||
'input_attr': kwargs,
|
|
||||||
'filter_attr': target}
|
|
||||||
callback['callback'](self,
|
|
||||||
request,
|
|
||||||
prep_info,
|
|
||||||
**kwargs)
|
|
||||||
else:
|
|
||||||
# No callback, so we are going to check the protection here
|
|
||||||
action = 'identity:%s' % f.__name__
|
|
||||||
creds = _build_policy_check_credentials(
|
|
||||||
self, action, request.context_dict, kwargs)
|
|
||||||
# Add in any formal url parameters
|
|
||||||
for key in kwargs:
|
|
||||||
target[key] = kwargs[key]
|
|
||||||
|
|
||||||
policy.enforce(creds, action, utils.flatten_dict(target))
|
protected_wrapper(
|
||||||
|
self, f, check_function, request, filter_attr, **kwargs)
|
||||||
LOG.debug('RBAC: Authorization granted')
|
|
||||||
else:
|
|
||||||
LOG.warning('RBAC: Bypassing authorization')
|
|
||||||
return f(self, request, filters, **kwargs)
|
return f(self, request, filters, **kwargs)
|
||||||
return wrapper
|
return wrapper
|
||||||
return _filterprotected
|
return _filterprotected
|
||||||
|
|
||||||
|
|
||||||
|
# Unified calls for the decorators above.
|
||||||
|
# TODO(ayoung): Continue the refactoring. Always call check_protection
|
||||||
|
# explicitly, by removing the calls to check protection from the callbacks.
|
||||||
|
# Instead, have a call to the callbacks inserted prior to the call to
|
||||||
|
# `check_protection`.
|
||||||
|
def protected_wrapper(self, f, check_function, request, filter_attr,
|
||||||
|
*args, **kwargs):
|
||||||
|
request.assert_authenticated()
|
||||||
|
if request.context.is_admin:
|
||||||
|
LOG.warning('RBAC: Bypassing authorization')
|
||||||
|
return
|
||||||
|
prep_info = {'f_name': f.__name__,
|
||||||
|
'input_attr': kwargs}
|
||||||
|
if (filter_attr):
|
||||||
|
prep_info['filter_attr'] = filter_attr
|
||||||
|
check_function(self, request, prep_info, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class V2Controller(wsgi.Application):
|
class V2Controller(wsgi.Application):
|
||||||
"""Base controller class for Identity API v2."""
|
"""Base controller class for Identity API v2."""
|
||||||
|
|
||||||
@ -682,7 +606,7 @@ class V3Controller(wsgi.Application):
|
|||||||
if domain_id:
|
if domain_id:
|
||||||
return domain_id
|
return domain_id
|
||||||
|
|
||||||
token_ref = utils.get_token_ref(request.context_dict)
|
token_ref = authorization.get_token_ref(request.context_dict)
|
||||||
|
|
||||||
if token_ref.domain_scoped:
|
if token_ref.domain_scoped:
|
||||||
return token_ref.domain_id
|
return token_ref.domain_id
|
||||||
@ -751,26 +675,7 @@ class V3Controller(wsgi.Application):
|
|||||||
they can be referenced by policy rules.
|
they can be referenced by policy rules.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if request.context.is_admin:
|
authorization.check_protection(self, request, prep_info, target_attr)
|
||||||
LOG.warning('RBAC: Bypassing authorization')
|
|
||||||
else:
|
|
||||||
action = 'identity:%s' % prep_info['f_name']
|
|
||||||
# TODO(henry-nash) need to log the target attributes as well
|
|
||||||
creds = _build_policy_check_credentials(self, action,
|
|
||||||
request.context_dict,
|
|
||||||
prep_info['input_attr'])
|
|
||||||
# Build the dict the policy engine will check against from both the
|
|
||||||
# parameters passed into the call we are protecting (which was
|
|
||||||
# stored in the prep_info by protected()), plus the target
|
|
||||||
# attributes provided.
|
|
||||||
policy_dict = {}
|
|
||||||
if target_attr:
|
|
||||||
policy_dict = {'target': target_attr}
|
|
||||||
policy_dict.update(prep_info['input_attr'])
|
|
||||||
if 'filter_attr' in prep_info:
|
|
||||||
policy_dict.update(prep_info['filter_attr'])
|
|
||||||
policy.enforce(creds, action, utils.flatten_dict(policy_dict))
|
|
||||||
LOG.debug('RBAC: Authorization granted')
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def filter_params(cls, ref):
|
def filter_params(cls, ref):
|
||||||
@ -787,11 +692,3 @@ class V3Controller(wsgi.Application):
|
|||||||
for blocked_param in blocked_keys:
|
for blocked_param in blocked_keys:
|
||||||
del ref[blocked_param]
|
del ref[blocked_param]
|
||||||
return ref
|
return ref
|
||||||
|
|
||||||
def _token_validation_window(self, request):
|
|
||||||
# NOTE(jamielennox): it's dumb that i have to put this here. We should
|
|
||||||
# only validate subject token in one place.
|
|
||||||
allow_expired = request.params.get('allow_expired')
|
|
||||||
allow_expired = strutils.bool_from_string(allow_expired, default=False)
|
|
||||||
|
|
||||||
return CONF.token.allow_expired_window if allow_expired else 0
|
|
||||||
|
@ -34,7 +34,6 @@ import passlib.hash
|
|||||||
import six
|
import six
|
||||||
from six import moves
|
from six import moves
|
||||||
|
|
||||||
from keystone.common import authorization
|
|
||||||
import keystone.conf
|
import keystone.conf
|
||||||
from keystone import exception
|
from keystone import exception
|
||||||
from keystone.i18n import _
|
from keystone.i18n import _
|
||||||
@ -526,24 +525,6 @@ def isotime(at=None, subsecond=False):
|
|||||||
return st
|
return st
|
||||||
|
|
||||||
|
|
||||||
def get_token_ref(context):
|
|
||||||
"""Retrieve KeystoneToken object from the auth context and returns it.
|
|
||||||
|
|
||||||
:param dict context: The request context.
|
|
||||||
:raises keystone.exception.Unauthorized: If auth context cannot be found.
|
|
||||||
:returns: The KeystoneToken object.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
# Retrieve the auth context that was prepared by AuthContextMiddleware.
|
|
||||||
auth_context = (context['environment']
|
|
||||||
[authorization.AUTH_CONTEXT_ENV])
|
|
||||||
return auth_context['token']
|
|
||||||
except KeyError:
|
|
||||||
msg = _("Couldn't find the auth context.")
|
|
||||||
LOG.warning(msg)
|
|
||||||
raise exception.Unauthorized(msg)
|
|
||||||
|
|
||||||
|
|
||||||
URL_RESERVED_CHARS = ":/?#[]@!$&'()*+,;="
|
URL_RESERVED_CHARS = ":/?#[]@!$&'()*+,;="
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
|
|
||||||
"""Utility methods for working with WSGI servers."""
|
"""Utility methods for working with WSGI servers."""
|
||||||
|
|
||||||
import copy
|
|
||||||
import functools
|
import functools
|
||||||
import itertools
|
import itertools
|
||||||
import re
|
import re
|
||||||
@ -35,9 +34,9 @@ from six.moves import http_client
|
|||||||
import webob.dec
|
import webob.dec
|
||||||
import webob.exc
|
import webob.exc
|
||||||
|
|
||||||
|
from keystone.common import authorization
|
||||||
from keystone.common import dependency
|
from keystone.common import dependency
|
||||||
from keystone.common import json_home
|
from keystone.common import json_home
|
||||||
from keystone.common import policy
|
|
||||||
from keystone.common import request as request_mod
|
from keystone.common import request as request_mod
|
||||||
from keystone.common import utils
|
from keystone.common import utils
|
||||||
import keystone.conf
|
import keystone.conf
|
||||||
@ -292,28 +291,7 @@ class Application(BaseApplication):
|
|||||||
does not have the admin role
|
does not have the admin role
|
||||||
|
|
||||||
"""
|
"""
|
||||||
request.assert_authenticated()
|
authorization.assert_admin(self, request)
|
||||||
|
|
||||||
if not request.context.is_admin:
|
|
||||||
user_token_ref = utils.get_token_ref(request.context_dict)
|
|
||||||
|
|
||||||
creds = copy.deepcopy(user_token_ref.metadata)
|
|
||||||
|
|
||||||
try:
|
|
||||||
creds['user_id'] = user_token_ref.user_id
|
|
||||||
except exception.UnexpectedError:
|
|
||||||
LOG.debug('Invalid user')
|
|
||||||
raise exception.Unauthorized(_('Invalid user'))
|
|
||||||
|
|
||||||
if user_token_ref.project_scoped:
|
|
||||||
creds['tenant_id'] = user_token_ref.project_id
|
|
||||||
else:
|
|
||||||
LOG.debug('Invalid tenant')
|
|
||||||
raise exception.Unauthorized(_('Invalid tenant'))
|
|
||||||
|
|
||||||
creds['roles'] = user_token_ref.role_names
|
|
||||||
# Accept either is_admin or the admin role
|
|
||||||
policy.enforce(creds, 'admin_required', {})
|
|
||||||
|
|
||||||
def _attribute_is_empty(self, ref, attribute):
|
def _attribute_is_empty(self, ref, attribute):
|
||||||
"""Determine if the attribute in ref is empty or None."""
|
"""Determine if the attribute in ref is empty or None."""
|
||||||
|
@ -41,6 +41,7 @@ from oslo_serialization import jsonutils
|
|||||||
import six
|
import six
|
||||||
from six.moves import http_client
|
from six.moves import http_client
|
||||||
|
|
||||||
|
from keystone.common import authorization
|
||||||
from keystone.common import controller
|
from keystone.common import controller
|
||||||
from keystone.common import dependency
|
from keystone.common import dependency
|
||||||
from keystone.common import utils
|
from keystone.common import utils
|
||||||
@ -327,7 +328,7 @@ class Ec2Controller(Ec2ControllerCommon, controller.V2Controller):
|
|||||||
:raises keystone.exception.Forbidden: when token is invalid
|
:raises keystone.exception.Forbidden: when token is invalid
|
||||||
|
|
||||||
"""
|
"""
|
||||||
token_ref = utils.get_token_ref(context)
|
token_ref = authorization.get_token_ref(context)
|
||||||
|
|
||||||
if token_ref.user_id != user_id:
|
if token_ref.user_id != user_id:
|
||||||
raise exception.Forbidden(_('Token belongs to another user'))
|
raise exception.Forbidden(_('Token belongs to another user'))
|
||||||
|
@ -19,9 +19,9 @@ from oslo_serialization import jsonutils
|
|||||||
from oslo_utils import timeutils
|
from oslo_utils import timeutils
|
||||||
from six.moves import http_client
|
from six.moves import http_client
|
||||||
|
|
||||||
|
from keystone.common import authorization
|
||||||
from keystone.common import controller
|
from keystone.common import controller
|
||||||
from keystone.common import dependency
|
from keystone.common import dependency
|
||||||
from keystone.common import utils
|
|
||||||
from keystone.common import validation
|
from keystone.common import validation
|
||||||
from keystone.common import wsgi
|
from keystone.common import wsgi
|
||||||
import keystone.conf
|
import keystone.conf
|
||||||
@ -92,7 +92,7 @@ class ConsumerCrudV3(controller.V3Controller):
|
|||||||
|
|
||||||
@controller.protected()
|
@controller.protected()
|
||||||
def delete_consumer(self, request, consumer_id):
|
def delete_consumer(self, request, consumer_id):
|
||||||
user_token_ref = utils.get_token_ref(request.context_dict)
|
user_token_ref = authorization.get_token_ref(request.context_dict)
|
||||||
payload = {'user_id': user_token_ref.user_id,
|
payload = {'user_id': user_token_ref.user_id,
|
||||||
'consumer_id': consumer_id}
|
'consumer_id': consumer_id}
|
||||||
_emit_user_oauth_consumer_token_invalidate(payload)
|
_emit_user_oauth_consumer_token_invalidate(payload)
|
||||||
@ -396,7 +396,7 @@ class OAuthControllerV3(controller.V3Controller):
|
|||||||
authed_roles.add(role['id'])
|
authed_roles.add(role['id'])
|
||||||
|
|
||||||
# verify the authorizing user has the roles
|
# verify the authorizing user has the roles
|
||||||
user_token = utils.get_token_ref(request.context_dict)
|
user_token = authorization.get_token_ref(request.context_dict)
|
||||||
user_id = user_token.user_id
|
user_id = user_token.user_id
|
||||||
project_id = req_token['requested_project_id']
|
project_id = req_token['requested_project_id']
|
||||||
user_roles = self.assignment_api.get_roles_for_user_and_project(
|
user_roles = self.assignment_api.get_roles_for_user_and_project(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user