Lists for Generic Checks
The Generic check had no way to identify a value inside a list. Since Lists are inherantly unstable in indexing, requiring an index to match is not practical. Lists now follow the same approach as the OrCheck: When specifying a value inside a list, each element of the lsit is checked for a match. If any of the sub lists match, the check succeeds. Only if the entry is not in the list does the check fail. If the value is nested in a dictionary under the list, all of the subordinate dictionaries are checked in a recursive manner. Change-Id: Ia286dbd3757703779d7044b3003381eab6c5c919
This commit is contained in:
parent
b3fe254031
commit
a08bc79f5c
@ -288,23 +288,52 @@ class GenericCheck(Check):
|
||||
- 'Member':%(role.name)s
|
||||
"""
|
||||
|
||||
def _find_in_dict(self, test_value, path_segments, match):
|
||||
'''Searches for a match in the dictionary.
|
||||
|
||||
test_value is a reference inside the dictionary. Since the process is
|
||||
recursive, each call to _find_in_dict will be one level deeper.
|
||||
|
||||
path_segments is the segments of the path to search. The recursion
|
||||
ends when there are no more segments of path.
|
||||
|
||||
When specifying a value inside a list, each element of the list is
|
||||
checked for a match. If the value is found within any of the sub lists
|
||||
the check succeeds; The check only fails if the entry is not in any of
|
||||
the sublists.
|
||||
|
||||
'''
|
||||
|
||||
if len(path_segments) == 0:
|
||||
return match == six.text_type(test_value)
|
||||
key, path_segments = path_segments[0], path_segments[1:]
|
||||
try:
|
||||
test_value = test_value[key]
|
||||
except KeyError:
|
||||
return False
|
||||
if isinstance(test_value, list):
|
||||
for val in test_value:
|
||||
if self._find_in_dict(val, path_segments, match):
|
||||
return True
|
||||
return False
|
||||
else:
|
||||
return self._find_in_dict(test_value, path_segments, match)
|
||||
|
||||
def __call__(self, target, creds, enforcer):
|
||||
|
||||
try:
|
||||
match = self.match % target
|
||||
except KeyError:
|
||||
# While doing GenericCheck if key not
|
||||
# present in Target return false
|
||||
return False
|
||||
|
||||
try:
|
||||
# Try to interpret self.kind as a literal
|
||||
leftval = ast.literal_eval(self.kind)
|
||||
test_value = ast.literal_eval(self.kind)
|
||||
return match == six.text_type(test_value)
|
||||
|
||||
except ValueError:
|
||||
try:
|
||||
kind_parts = self.kind.split('.')
|
||||
leftval = creds
|
||||
for kind_part in kind_parts:
|
||||
leftval = leftval[kind_part]
|
||||
except KeyError:
|
||||
return False
|
||||
return match == six.text_type(leftval)
|
||||
pass
|
||||
|
||||
path_segments = self.kind.split('.')
|
||||
return self._find_in_dict(creds, path_segments, match)
|
||||
|
@ -23,6 +23,7 @@ import six.moves.urllib.request as urlrequest
|
||||
|
||||
from oslo_policy import _checks
|
||||
from oslo_policy.tests import base
|
||||
from oslo_policy.tests import token_fixture
|
||||
|
||||
|
||||
class CheckRegisterTestCase(test_base.BaseTestCase):
|
||||
@ -220,6 +221,57 @@ class GenericCheckTestCase(base.PolicyBaseTestCase):
|
||||
check = _checks.GenericCheck('q.v', 'APPLES')
|
||||
self.assertFalse(check({}, credentials, self.enforcer))
|
||||
|
||||
def test_single_entry_in_list_accepted(self):
|
||||
check = _checks.GenericCheck('a.b.c.d', 'APPLES')
|
||||
credentials = {'a': {'b': {'c': {'d': ['APPLES']}}}}
|
||||
self.assertTrue(check({}, credentials, self.enforcer))
|
||||
|
||||
def test_multiple_entry_in_list_accepted(self):
|
||||
check = _checks.GenericCheck('a.b.c.d', 'APPLES')
|
||||
credentials = {'a': {'b': {'c': {'d': ['Bananas',
|
||||
'APPLES',
|
||||
'Grapes']}}}}
|
||||
self.assertTrue(check({}, credentials, self.enforcer))
|
||||
|
||||
def test_multiple_entry_in_nested_list_accepted(self):
|
||||
check = _checks.GenericCheck('a.b.c.d', 'APPLES')
|
||||
credentials = {'a': {'b': [{'c':
|
||||
{'d': ['BANANAS', 'APPLES', 'GRAPES']}},
|
||||
{}]}}
|
||||
self.assertTrue(check({}, credentials, self.enforcer))
|
||||
|
||||
def test_multiple_entries_one_matches(self):
|
||||
check = _checks.GenericCheck(
|
||||
'token.catalog.endpoints.id',
|
||||
token_fixture.REGION_ONE_PUBLIC_KEYSTONE_ENDPOINT_ID)
|
||||
credentials = token_fixture.SCOPED_TOKEN_FIXTURE
|
||||
self.assertTrue(check({}, credentials, self.enforcer))
|
||||
|
||||
def test_generic_role_check_matches(self):
|
||||
check = _checks.GenericCheck(
|
||||
'token.roles.name', 'role1')
|
||||
credentials = token_fixture.SCOPED_TOKEN_FIXTURE
|
||||
self.assertTrue(check({}, credentials, self.enforcer))
|
||||
|
||||
def test_generic_missing_role_does_not_matches(self):
|
||||
check = _checks.GenericCheck(
|
||||
'token.roles.name', 'missing')
|
||||
credentials = token_fixture.SCOPED_TOKEN_FIXTURE
|
||||
self.assertFalse(check({}, credentials, self.enforcer))
|
||||
|
||||
def test_multiple_nested_lists_accepted(self):
|
||||
check = _checks.GenericCheck('a.b.c.d', 'APPLES')
|
||||
credentials = {'a': {'b': [{'a': ''},
|
||||
{'c':
|
||||
{'d': ['BANANAS', 'APPLES', 'GRAPES']}},
|
||||
{}]}}
|
||||
self.assertTrue(check({}, credentials, self.enforcer))
|
||||
|
||||
def test_entry_not_in_list_rejected(self):
|
||||
check = _checks.GenericCheck('a.b.c.d', 'APPLES')
|
||||
credentials = {'a': {'b': {'c': {'d': ['PEACHES', 'PEARS']}}}}
|
||||
self.assertFalse(check({}, credentials, self.enforcer))
|
||||
|
||||
|
||||
class FalseCheckTestCase(test_base.BaseTestCase):
|
||||
def test_str(self):
|
||||
|
164
oslo_policy/tests/token_fixture.py
Normal file
164
oslo_policy/tests/token_fixture.py
Normal file
@ -0,0 +1,164 @@
|
||||
# Copyright (c) 2015 OpenStack Foundation.
|
||||
# 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.
|
||||
|
||||
REGION_ONE_PUBLIC_KEYSTONE_ENDPOINT_ID = '8cd4b957090f4ca5842a22e9a74099cd'
|
||||
|
||||
|
||||
SCOPED_TOKEN_FIXTURE = {
|
||||
"token": {
|
||||
"methods": [
|
||||
"password"
|
||||
],
|
||||
"roles": [
|
||||
{
|
||||
"id": "f03fda8f8a3249b2a70fb1f176a7b631",
|
||||
"name": "role1"
|
||||
},
|
||||
{
|
||||
"id": "f03fda8f8a3249b2a70fb1f176a7b631",
|
||||
"name": "role2"
|
||||
}
|
||||
],
|
||||
"issued_at": "2002-01-18T21:14:07Z",
|
||||
"expires_at": "2038-01-18T21:14:07Z",
|
||||
"project": {
|
||||
"id": "tenant_id1",
|
||||
"domain": {
|
||||
"id": "domain_id1",
|
||||
"name": "domain_name1"
|
||||
},
|
||||
"enabled": True,
|
||||
"description": "no description avialable",
|
||||
"name": "tenant_name1"
|
||||
},
|
||||
"catalog": [
|
||||
{
|
||||
"endpoints": [
|
||||
{
|
||||
"id": "3b5e554bcf114f2483e8a1be7a0506d1",
|
||||
"interface": "admin",
|
||||
"url": "http://127.0.0.1:8776/v1/" +
|
||||
"64b6f3fbcc53435e8a60fcf89bb6617a",
|
||||
"region": "regionOne"
|
||||
},
|
||||
{
|
||||
"id": "54abd2dc463c4ba4a72915498f8ecad1",
|
||||
"interface": "internal",
|
||||
"url": "http://127.0.0.1:8776/v1/" +
|
||||
"64b6f3fbcc53435e8a60fcf89bb6617a",
|
||||
"region": "regionOne"
|
||||
},
|
||||
{
|
||||
"id": "70a7efa4b1b941968357cc43ae1419ee",
|
||||
"interface": "public",
|
||||
"url": "http://127.0.0.1:8776/v1/" +
|
||||
"64b6f3fbcc53435e8a60fcf89bb6617a",
|
||||
"region": "regionOne"
|
||||
}
|
||||
],
|
||||
"id": "5707c3fc0a294703a3c638e9cf6a6c3a",
|
||||
"type": "volume",
|
||||
"name": "volume"
|
||||
},
|
||||
{
|
||||
"endpoints": [
|
||||
{
|
||||
"id": "92217a3b95394492859bc49fd474382f",
|
||||
"interface": "admin",
|
||||
"url": "http://127.0.0.1:9292/v1",
|
||||
"region": "regionOne"
|
||||
},
|
||||
{
|
||||
"id": "f20563bdf66f4efa8a1f11d99b672be1",
|
||||
"interface": "internal",
|
||||
"url": "http://127.0.0.1:9292/v1",
|
||||
"region": "regionOne"
|
||||
},
|
||||
{
|
||||
"id": "375f9ba459a447738fb60fe5fc26e9aa",
|
||||
"interface": "public",
|
||||
"url": "http://127.0.0.1:9292/v1",
|
||||
"region": "regionOne"
|
||||
}
|
||||
],
|
||||
"id": "15c21aae6b274a8da52e0a068e908aac",
|
||||
"type": "image",
|
||||
"name": "glance"
|
||||
},
|
||||
{
|
||||
"endpoints": [
|
||||
{
|
||||
"id": "edbd9f50f66746ae9ed11dc3b1ae35da",
|
||||
"interface": "admin",
|
||||
"url": "http://127.0.0.1:8774/v1.1/" +
|
||||
"64b6f3fbcc53435e8a60fcf89bb6617a",
|
||||
"region": "regionOne"
|
||||
},
|
||||
{
|
||||
"id": "9e03c46c80a34a159cb39f5cb0498b92",
|
||||
"interface": "internal",
|
||||
"url": "http://127.0.0.1:8774/v1.1/" +
|
||||
"64b6f3fbcc53435e8a60fcf89bb6617a",
|
||||
"region": "regionOne"
|
||||
},
|
||||
{
|
||||
"id": "1df0b44d92634d59bd0e0d60cf7ce432",
|
||||
"interface": "public",
|
||||
"url":
|
||||
"http://127.0.0.1:8774/v1.1/" +
|
||||
"64b6f3fbcc53435e8a60fcf89bb6617a",
|
||||
"region": "regionOne"
|
||||
}
|
||||
],
|
||||
"id": "2f404fdb89154c589efbc10726b029ec",
|
||||
"type": "compute",
|
||||
"name": "nova"
|
||||
},
|
||||
{
|
||||
"endpoints": [
|
||||
{
|
||||
"id": "a4501e141a4b4e14bf282e7bffd81dc5",
|
||||
"interface": "admin",
|
||||
"url": "http://127.0.0.1:35357/v3",
|
||||
"region": "RegionOne"
|
||||
},
|
||||
{
|
||||
"id": "3d17e3227bfc4483b58de5eaa584e360",
|
||||
"interface": "internal",
|
||||
"url": "http://127.0.0.1:35357/v3",
|
||||
"region": "RegionOne"
|
||||
},
|
||||
{
|
||||
"id": REGION_ONE_PUBLIC_KEYSTONE_ENDPOINT_ID,
|
||||
"interface": "public",
|
||||
"url": "http://127.0.0.1:5000/v3",
|
||||
"region": "RegionOne"
|
||||
}
|
||||
],
|
||||
"id": "c5d926d566424e4fba4f80c37916cde5",
|
||||
"type": "identity",
|
||||
"name": "keystone"
|
||||
}
|
||||
],
|
||||
"user": {
|
||||
"domain": {
|
||||
"id": "domain_id1",
|
||||
"name": "domain_name1"
|
||||
},
|
||||
"name": "user_name1",
|
||||
"id": "user_id1"
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user