Sync policy module from oslo-incubator
The policy module has not had a sync since back in November. There have been a number of changes that should be pulled into Kilo. Current HEAD in OSLO: --------------------- commit 9bf01f9d98487cb13e3d95ad2a580fe8fc6f2479 Date: Fri Feb 13 14:18:58 2015 -0500 Switch from oslo.config to oslo_config Changes merged with this patch: --------------------- 2aacb111 Change oslo.config to oslo_config 2fbf5065 Remove oslo.log code and clean up versionutils API 262279b1 switch to oslo_serialization 07e9b32a Improving docstrings for policy API e67f5cd0 Merge "Don't log missing policy.d as a warning" 99d991ce Merge "Fixed a problem with neutron http policy check" b19af080 Don't log missing policy.d as a warning 2324c775 Add rule overwrite flag to Enforcer class 6166a960 Fixed a problem with neutron http policy check Closes-bug: 1288178 Change-Id: I6987029b9c15f3d35fa591014859f5f96c98f3a3
This commit is contained in:
parent
7cd5fe6bb5
commit
1c28ead900
|
@ -1,3 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2012 OpenStack Foundation.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
|
@ -22,22 +24,43 @@ string written in the new policy language.
|
|||
In the list-of-lists representation, each check inside the innermost
|
||||
list is combined as with an "and" conjunction--for that check to pass,
|
||||
all the specified checks must pass. These innermost lists are then
|
||||
combined as with an "or" conjunction. This is the original way of
|
||||
expressing policies, but there now exists a new way: the policy
|
||||
language.
|
||||
|
||||
In the policy language, each check is specified the same way as in the
|
||||
list-of-lists representation: a simple "a:b" pair that is matched to
|
||||
the correct code to perform that check. However, conjunction
|
||||
operators are available, allowing for more expressiveness in crafting
|
||||
policies.
|
||||
|
||||
As an example, take the following rule, expressed in the list-of-lists
|
||||
representation::
|
||||
combined as with an "or" conjunction. As an example, take the following
|
||||
rule, expressed in the list-of-lists representation::
|
||||
|
||||
[["role:admin"], ["project_id:%(project_id)s", "role:projectadmin"]]
|
||||
|
||||
In the policy language, this becomes::
|
||||
This is the original way of expressing policies, but there now exists a
|
||||
new way: the policy language.
|
||||
|
||||
In the policy language, each check is specified the same way as in the
|
||||
list-of-lists representation: a simple "a:b" pair that is matched to
|
||||
the correct class to perform that check::
|
||||
|
||||
+===========================================================================+
|
||||
| TYPE | SYNTAX |
|
||||
+===========================================================================+
|
||||
|User's Role | role:admin |
|
||||
+---------------------------------------------------------------------------+
|
||||
|Rules already defined on policy | rule:admin_required |
|
||||
+---------------------------------------------------------------------------+
|
||||
|Against URL's¹ | http://my-url.org/check |
|
||||
+---------------------------------------------------------------------------+
|
||||
|User attributes² | project_id:%(target.project.id)s |
|
||||
+---------------------------------------------------------------------------+
|
||||
|Strings | <variable>:'xpto2035abc' |
|
||||
| | 'myproject':<variable> |
|
||||
+---------------------------------------------------------------------------+
|
||||
| | project_id:xpto2035abc |
|
||||
|Literals | domain_id:20 |
|
||||
| | True:%(user.enabled)s |
|
||||
+===========================================================================+
|
||||
|
||||
¹URL checking must return 'True' to be valid
|
||||
²User attributes (obtained through the token): user_id, domain_id or project_id
|
||||
|
||||
Conjunction operators are available, allowing for more expressiveness
|
||||
in crafting policies. So, in the policy language, the previous check in
|
||||
list-of-lists becomes::
|
||||
|
||||
role:admin or (project_id:%(project_id)s and role:projectadmin)
|
||||
|
||||
|
@ -46,26 +69,16 @@ policy rule::
|
|||
|
||||
project_id:%(project_id)s and not role:dunce
|
||||
|
||||
It is possible to perform policy checks on the following user
|
||||
attributes (obtained through the token): user_id, domain_id or
|
||||
project_id::
|
||||
|
||||
domain_id:<some_value>
|
||||
|
||||
Attributes sent along with API calls can be used by the policy engine
|
||||
(on the right side of the expression), by using the following syntax::
|
||||
|
||||
<some_value>:user.id
|
||||
<some_value>:%(user.id)s
|
||||
|
||||
Contextual attributes of objects identified by their IDs are loaded
|
||||
from the database. They are also available to the policy engine and
|
||||
can be checked through the `target` keyword::
|
||||
|
||||
<some_value>:target.role.name
|
||||
|
||||
All these attributes (related to users, API calls, and context) can be
|
||||
checked against each other or against constants, be it literals (True,
|
||||
<a_number>) or strings.
|
||||
<some_value>:%(target.role.name)s
|
||||
|
||||
Finally, two special policy checks should be mentioned; the policy
|
||||
check "@" will always accept an access, and the policy check "!" will
|
||||
|
@ -78,6 +91,7 @@ as it allows particular rules to be explicitly disabled.
|
|||
import abc
|
||||
import ast
|
||||
import copy
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
|
||||
|
@ -88,8 +102,7 @@ import six.moves.urllib.parse as urlparse
|
|||
import six.moves.urllib.request as urlrequest
|
||||
|
||||
from cinder.openstack.common import fileutils
|
||||
from cinder.openstack.common._i18n import _, _LE, _LW
|
||||
from cinder.openstack.common import log as logging
|
||||
from cinder.openstack.common._i18n import _, _LE, _LI
|
||||
|
||||
|
||||
policy_opts = [
|
||||
|
@ -199,16 +212,19 @@ class Enforcer(object):
|
|||
: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 cache or config file.
|
||||
:param overwrite: Whether to overwrite existing rules when reload rules
|
||||
from config file.
|
||||
"""
|
||||
|
||||
def __init__(self, policy_file=None, rules=None,
|
||||
default_rule=None, use_conf=True):
|
||||
default_rule=None, use_conf=True, overwrite=True):
|
||||
self.default_rule = default_rule or CONF.policy_default_rule
|
||||
self.rules = Rules(rules, self.default_rule)
|
||||
|
||||
self.policy_path = None
|
||||
self.policy_file = policy_file or CONF.policy_file
|
||||
self.use_conf = use_conf
|
||||
self.overwrite = overwrite
|
||||
|
||||
def set_rules(self, rules, overwrite=True, use_conf=False):
|
||||
"""Create a new Rules object based on the provided dict of rules.
|
||||
|
@ -240,7 +256,7 @@ class Enforcer(object):
|
|||
|
||||
Policy file is cached and will be reloaded if modified.
|
||||
|
||||
:param force_reload: Whether to overwrite current rules.
|
||||
:param force_reload: Whether to reload rules from config file.
|
||||
"""
|
||||
|
||||
if force_reload:
|
||||
|
@ -250,12 +266,13 @@ class Enforcer(object):
|
|||
if not self.policy_path:
|
||||
self.policy_path = self._get_policy_path(self.policy_file)
|
||||
|
||||
self._load_policy_file(self.policy_path, force_reload)
|
||||
self._load_policy_file(self.policy_path, force_reload,
|
||||
overwrite=self.overwrite)
|
||||
for path in CONF.policy_dirs:
|
||||
try:
|
||||
path = self._get_policy_path(path)
|
||||
except cfg.ConfigFilesNotFoundError:
|
||||
LOG.warn(_LW("Can not find policy directory: %s"), path)
|
||||
LOG.info(_LI("Can not find policy directory: %s"), path)
|
||||
continue
|
||||
self._walk_through_policy_directory(path,
|
||||
self._load_policy_file,
|
||||
|
@ -272,9 +289,9 @@ class Enforcer(object):
|
|||
def _load_policy_file(self, path, force_reload, overwrite=True):
|
||||
reloaded, data = fileutils.read_cached_file(
|
||||
path, force_reload=force_reload)
|
||||
if reloaded or not self.rules:
|
||||
if reloaded or not self.rules or not overwrite:
|
||||
rules = Rules.load_json(data, self.default_rule)
|
||||
self.set_rules(rules, overwrite)
|
||||
self.set_rules(rules, overwrite=overwrite, use_conf=True)
|
||||
LOG.debug("Rules successfully reloaded")
|
||||
|
||||
def _get_policy_path(self, path):
|
||||
|
@ -894,7 +911,17 @@ class HttpCheck(Check):
|
|||
"""
|
||||
|
||||
url = ('http:' + self.match) % target
|
||||
data = {'target': jsonutils.dumps(target),
|
||||
|
||||
# Convert instances of object() in target temporarily to
|
||||
# empty dict to avoid circular reference detection
|
||||
# errors in jsonutils.dumps().
|
||||
temp_target = copy.deepcopy(target)
|
||||
for key in target.keys():
|
||||
element = target.get(key)
|
||||
if type(element) is object:
|
||||
temp_target[key] = {}
|
||||
|
||||
data = {'target': jsonutils.dumps(temp_target),
|
||||
'credentials': jsonutils.dumps(creds)}
|
||||
post_data = urlparse.urlencode(data)
|
||||
f = urlrequest.urlopen(url, post_data)
|
||||
|
|
Loading…
Reference in New Issue