panko/panko/api/rbac.py
Ghanshyam Mann 6da394a59a [goal] Deprecate the JSON formatted policy file
As per the community goal of migrating the policy file
the format from JSON to YAML[1], we need to do two things:

1. Change the default value of '[oslo_policy] policy_file''
config option from 'policy.json' to 'policy.yaml' with
upgrade checks.

2. Deprecate the JSON formatted policy file on the project side
via warning in doc and releasenotes.

Also replace policy.json to policy.yaml ref from doc and tests.

[1]https://governance.openstack.org/tc/goals/selected/wallaby/migrate-policy-format-from-json-to-yaml.html

Change-Id: Ie6e22b0b47c5148290f7b76c95967cd9a343343c
2021-02-11 12:40:40 -06:00

117 lines
3.6 KiB
Python

#
# Copyright 2012 New Dream Network, LLC (DreamHost)
# Copyright 2014 Hewlett-Packard Company
#
# 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.
"""Access Control Lists (ACL's) control access the API server."""
from oslo_config import cfg
from oslo_policy import opts
from oslo_policy import policy
import pecan
from panko import policies
_ENFORCER = None
# TODO(gmann): Remove setting the default value of config policy_file
# once oslo_policy change the default value to 'policy.yaml'.
# https://github.com/openstack/oslo.policy/blob/a626ad12fe5a3abd49d70e3e5b95589d279ab578/oslo_policy/opts.py#L49
DEFAULT_POLICY_FILE = 'policy.yaml'
opts.set_defaults(cfg.CONF, DEFAULT_POLICY_FILE)
def init():
global _ENFORCER
if not _ENFORCER:
_ENFORCER = policy.Enforcer(pecan.request.cfg)
_ENFORCER.load_rules()
_ENFORCER.register_defaults(policies.list_policies())
def reset():
global _ENFORCER
if _ENFORCER:
_ENFORCER.clear()
_ENFORCER = None
def _has_rule(name):
return name in _ENFORCER.rules.keys()
def enforce(policy_name, request):
"""Return the user and project the request should be limited to.
:param request: HTTP request
:param policy_name: the policy name to validate authz against.
"""
init()
rule_method = "telemetry:" + policy_name
headers = request.headers
policy_dict = dict()
policy_dict['roles'] = headers.get('X-Roles', "").split(",")
policy_dict['user_id'] = (headers.get('X-User-Id'))
policy_dict['project_id'] = (headers.get('X-Project-Id'))
# maintain backward compat with Juno and previous by allowing the action if
# there is no rule defined for it
if ((_has_rule('default') or _has_rule(rule_method)) and
not _ENFORCER.enforce(rule_method, {}, policy_dict)):
pecan.core.abort(status_code=403, detail='RBAC Authorization Failed')
# TODO(fabiog): these methods are still used because the scoping part is really
# convoluted and difficult to separate out.
def get_limited_to(headers):
"""Return the user and project the request should be limited to.
:param headers: HTTP headers dictionary
:return: A tuple of (user, project), set to None if there's no limit on
one of these.
"""
init()
policy_dict = dict()
policy_dict['roles'] = headers.get('X-Roles', "").split(",")
policy_dict['user_id'] = (headers.get('X-User-Id'))
policy_dict['project_id'] = (headers.get('X-Project-Id'))
# maintain backward compat with Juno and previous by using context_is_admin
# rule if the segregation rule (added in Kilo) is not defined
rule_name = 'segregation' if _has_rule(
'segregation') else 'context_is_admin'
if not _ENFORCER.enforce(rule_name,
{},
policy_dict):
return headers.get('X-User-Id'), headers.get('X-Project-Id')
return None, None
def get_limited_to_project(headers):
"""Return the project the request should be limited to.
:param headers: HTTP headers dictionary
:return: A project, or None if there's no limit on it.
"""
return get_limited_to(headers)[1]