Policy in code

This patch introduces the beginning implementation for registering
default policy rules in code. Default rules are defined under
murano.common.policies. Each API's policies are defined in a
sub-folder under that path and __init__.py contains all the
default policies in code which are registered in the ``init``
enforcer function in murano/common/policy.py.

The default rules for the environments API was removed from the
policy.json and moved into code under
murano.common.policies.environment. This can be gradually done
for the rest of the APIs in follow-up patches.

This commit does the following:
  - Creates the ``policies`` module that contains all the default
    policies in code.
  - Adds the base policy rules into code (the admin_api,
    context_is_admin, and default rules).
  - Adds the environment default policy module with default
    policy rules for the environments API.

Partially Implements: blueprint policy-in-code

Change-Id: Iebf2c60d1d31b73829fad189ada7ceee28e714bd
This commit is contained in:
Felipe Monteiro 2017-05-25 20:32:27 +01:00
parent 176637fe4b
commit 5b01f9464b
5 changed files with 159 additions and 18 deletions

View File

@ -19,13 +19,6 @@
"list_deployments_all_environments": "rule:default",
"statuses_deployments": "rule:default",
"list_environments": "rule:default",
"list_environments_all_tenants": "rule:admin_api",
"show_environment": "rule:default",
"update_environment": "rule:default",
"create_environment": "rule:default",
"delete_environment": "rule:default",
"list_env_templates": "rule:default",
"create_env_template": "rule:default",
"show_env_template": "rule:default",

View File

@ -0,0 +1,24 @@
# Copyright 2017 AT&T Corporation.
# All 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 itertools
from murano.common.policies import environment
def list_rules():
return itertools.chain(
environment.list_rules()
)

View File

@ -0,0 +1,36 @@
# Copyright 2017 AT&T Corporation.
# All 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.
from oslo_policy import policy
RULE_ADMIN_API = 'rule:admin_api'
RULE_DEFAULT = 'rule:default'
rules = [
policy.RuleDefault(
name='context_is_admin',
check_str='role:admin'),
policy.RuleDefault(
name='admin_api',
check_str='is_admin:1'),
policy.RuleDefault(
name='default',
check_str='')
]
def list_rules():
return rules

View File

@ -0,0 +1,66 @@
# Copyright 2017 AT&T Corporation.
# All 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.
from oslo_policy import policy
from murano.common.policies import base
environment_policies = [
policy.DocumentedRuleDefault(
name='list_environments',
check_str=base.RULE_DEFAULT,
description='List environments in a project.',
operations=[{'path': '/v1/environments',
'method': 'GET'}]),
policy.DocumentedRuleDefault(
name='list_environments_all_tenants',
check_str=base.RULE_ADMIN_API,
description='List environments across all projects.',
operations=[{'path': '/v1/environments?all_tenants=true',
'method': 'GET'}]),
policy.DocumentedRuleDefault(
name='show_environment',
check_str=base.RULE_DEFAULT,
description='Show details for an environment or shows the environment '
'model.',
operations=[{'path': '/v1/environments/{environment_id}',
'method': 'GET'},
{'path': '/v1/environments/{environment_id}/model',
'method': 'GET'}]),
policy.DocumentedRuleDefault(
name='update_environment',
check_str=base.RULE_DEFAULT,
description='Update or rename an environment.',
operations=[{'path': '/v1/environments/{environment_id}',
'method': 'PUT'},
{'path': '/v1/environments/{environment_id}/model',
'method': 'PATCH'}]),
policy.DocumentedRuleDefault(
name='create_environment',
check_str=base.RULE_DEFAULT,
description='Create an environment.',
operations=[{'path': '/v1/environments/{environment_id}',
'method': 'POST'}]),
policy.DocumentedRuleDefault(
name='delete_environment',
check_str=base.RULE_DEFAULT,
description='Delete an environment.',
operations=[{'path': '/v1/environments/{environment_id}',
'method': 'DELETE'}])
]
def list_rules():
return environment_policies

View File

@ -19,6 +19,8 @@ from oslo_log import log as logging
from oslo_policy import policy
from webob import exc as exceptions
from murano.common import policies
LOG = logging.getLogger(__name__)
CONF = cfg.CONF
@ -33,6 +35,14 @@ def reset():
_ENFORCER = None
def init(default_rule=None, use_conf=True):
global _ENFORCER
if not _ENFORCER:
LOG.debug("Enforcer is not present, recreating.")
_ENFORCER = policy.Enforcer(CONF, use_conf=use_conf)
register_rules(_ENFORCER)
def set_rules(data, default_rule=None, overwrite=True):
default_rule = default_rule or cfg.CONF.policy_default_rule
if not _ENFORCER:
@ -54,19 +64,27 @@ def set_rules(data, default_rule=None, overwrite=True):
_ENFORCER.set_rules(rules, overwrite=overwrite)
def init(default_rule=None, use_conf=True):
global _ENFORCER
if not _ENFORCER:
LOG.debug("Enforcer is not present, recreating.")
_ENFORCER = policy.Enforcer(CONF, use_conf=use_conf)
_ENFORCER.load_rules()
def check(rule, ctxt, target=None, do_raise=True, exc=None):
"""Verify that the rule is valid on the target in this context.
def check(rule, ctxt, target=None, do_raise=True,
exc=exceptions.HTTPForbidden):
:param rule: String representing the action to be checked, which should
be colon-separated for clarity.
:param ctxt: Request context from which user credentials are extracted.
:param target: Dictionary representing the object of the action for object
creation; this should be a dictionary representing the
location of the object, e.g. {'environment_id':
object.environment_id}
:param do_raise: Whether to raise an exception or not if the check fails.
:param exc: Class of the exception to raise if the check fails.
:raises exceptions.HTTPForbidden: If verification fails. Or if 'exc' is
specified it will raise an exception of
that type.
"""
if target is None:
target = {}
creds = ctxt.to_dict()
if not exc:
exc = exceptions.HTTPForbidden
try:
result = _ENFORCER.enforce(rule, target, creds, do_raise, exc)
@ -94,5 +112,9 @@ def check_is_admin(context):
:param context: Murano request context
:returns: A non-False value if context role is admin.
"""
return check('context_is_admin', context,
context.to_dict(), do_raise=False)
return check('context_is_admin', context, context.to_dict(),
do_raise=False)
def register_rules(enforcer):
enforcer.register_defaults(policies.list_rules())