![Felipe Monteiro](/assets/img/avatar_default.png)
This PS implements documentation substitution and the rendered-documents endpoint. Each time the rendered-documents is queried, the documents for the reqeust revision_id dynamically undergo secret substitution. All functional tests related to secret substitution have been unskipped. Deckhand currently does not real testing for verifying that secret substitution works for encrypted documents. This will only happen when integration testing is added to Deckhand to test its interaction with Keystone and Barbican. Included in this PS: - basic implementation for secret substitution - introduction of jsonpath_ng for searching for and updating jsonpaths in documents - rendered-documents endpoint - unit tests - all relevant functional tests unskipped - additional bucket controller tests include RBAC tests and framework testing RBAC via unit tests Change-Id: I86f269a5b616b518e5f742a4005891412226fe2a
132 lines
4.5 KiB
Python
132 lines
4.5 KiB
Python
# Copyright 2017 AT&T Intellectual Property. All other rights reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
import functools
|
|
import six
|
|
|
|
import falcon
|
|
from oslo_config import cfg
|
|
from oslo_log import log as logging
|
|
from oslo_policy import policy
|
|
|
|
from deckhand import errors
|
|
from deckhand import policies
|
|
|
|
CONF = cfg.CONF
|
|
LOG = logging.getLogger(__name__)
|
|
_ENFORCER = None
|
|
|
|
|
|
def reset():
|
|
global _ENFORCER
|
|
if _ENFORCER:
|
|
_ENFORCER.clear()
|
|
_ENFORCER = None
|
|
|
|
|
|
def init(policy_file=None, rules=None, default_rule=None, use_conf=True):
|
|
"""Init an Enforcer class.
|
|
|
|
:param policy_file: Custom policy file to use, if none is specified,
|
|
``CONF.policy_file`` will be used.
|
|
:param rules: Default dictionary / Rules to use. It will be
|
|
considered just in the first instantiation.
|
|
:param default_rule: Default rule to use; ``CONF.default_rule`` will
|
|
be used if none is specified.
|
|
:param use_conf: Whether to load rules from config file.
|
|
"""
|
|
|
|
global _ENFORCER
|
|
|
|
if not _ENFORCER:
|
|
_ENFORCER = policy.Enforcer(CONF,
|
|
policy_file=policy_file,
|
|
rules=rules,
|
|
default_rule=default_rule,
|
|
use_conf=use_conf)
|
|
register_rules(_ENFORCER)
|
|
|
|
|
|
def _do_enforce_rbac(action, context, do_raise=True):
|
|
init()
|
|
|
|
credentials = context.to_policy_values()
|
|
target = {'project_id': context.project_id,
|
|
'user_id': context.user_id}
|
|
exc = errors.PolicyNotAuthorized
|
|
|
|
try:
|
|
# `oslo.policy` supports both enforce and authorize. authorize is
|
|
# stricter because it'll raise an exception if the policy action is
|
|
# not found in the list of registered rules. This means that attempting
|
|
# to enforce anything not found in ``deckhand.policies`` will error out
|
|
# with a 'Policy not registered' message.
|
|
return _ENFORCER.authorize(
|
|
action, target, context.to_dict(), do_raise=do_raise,
|
|
exc=exc, action=action)
|
|
except policy.PolicyNotRegistered as e:
|
|
LOG.exception('Policy not registered.')
|
|
raise falcon.HTTPForbidden(description=six.text_type(e))
|
|
except Exception as e:
|
|
LOG.debug(
|
|
'Policy check for %(action)s failed with credentials '
|
|
'%(credentials)s',
|
|
{'action': action, 'credentials': credentials})
|
|
raise falcon.HTTPForbidden(description=six.text_type(e))
|
|
|
|
|
|
def authorize(action):
|
|
"""Verifies whether a policy action can be performed given the credentials
|
|
found in the falcon request context.
|
|
|
|
:param action: The policy action to enforce.
|
|
:returns: ``True`` if policy enforcement succeeded, else ``False``.
|
|
:raises: falcon.HTTPForbidden if policy enforcement failed or if the policy
|
|
action isn't registered under ``deckhand.policies``.
|
|
"""
|
|
def decorator(func):
|
|
@functools.wraps(func)
|
|
def handler(*args, **kwargs):
|
|
# args[1] is always the falcon Request object.
|
|
context = args[1].context
|
|
_do_enforce_rbac(action, context)
|
|
return func(*args, **kwargs)
|
|
return handler
|
|
|
|
return decorator
|
|
|
|
|
|
def conditional_authorize(action, context, do_raise=True):
|
|
"""Conditionally authorize a policy action.
|
|
|
|
:param action: The policy action to enforce.
|
|
:param context: The falcon request context object.
|
|
:param do_raise: Whether to raise the exception if policy enforcement
|
|
fails. ``True`` by default.
|
|
:raises: falcon.HTTPForbidden if policy enforcement failed or if the policy
|
|
action isn't registered under ``deckhand.policies``.
|
|
|
|
Example::
|
|
|
|
# If any requested documents' metadata.storagePolicy == 'cleartext'.
|
|
if cleartext_documents:
|
|
policy.conditional_authorize('deckhand:create_cleartext_documents',
|
|
req.context)
|
|
"""
|
|
return _do_enforce_rbac(action, context, do_raise=do_raise)
|
|
|
|
|
|
def register_rules(enforcer):
|
|
enforcer.register_defaults(policies.list_rules())
|