Specify POLICY_CHECK_FUNCTION as a string

We don't want code in our settings.py and local_settings.py, and in
particular we don't want to have to import Python objects from all over
to set them as setting values -- instead, we can specify those as import
path strings. This also solves problems with importing order and loops.

This change is backwards-compatible, in the sense that you can still
import the objects directly and set them as the setting values.

Partially-Implements: blueprint ini-based-configuration
Change-Id: I8a346e55bb98e4e22e0c14a614c45d493d20feb4
This commit is contained in:
Radomir Dopieralski 2016-11-25 12:57:13 +01:00
parent 11f6e3de48
commit f5685ebe46
10 changed files with 58 additions and 38 deletions

View File

@ -45,6 +45,7 @@ from horizon.decorators import _current_component # noqa
from horizon.decorators import require_auth # noqa
from horizon.decorators import require_perms # noqa
from horizon import loaders
from horizon.utils import settings as utils_settings
# Name of the panel group for panels to be displayed without a group.
@ -144,7 +145,7 @@ class HorizonComponent(object):
return self._can_access(context['request'])
def _can_access(self, request):
policy_check = getattr(settings, "POLICY_CHECK_FUNCTION", None)
policy_check = utils_settings.import_setting("POLICY_CHECK_FUNCTION")
# this check is an OR check rather than an AND check that is the
# default in the policy engine, so calling each rule individually

View File

@ -33,6 +33,7 @@ import six
from horizon import messages
from horizon.utils import functions
from horizon.utils import html
from horizon.utils import settings as utils_settings
LOG = logging.getLogger(__name__)
@ -129,7 +130,7 @@ class BaseAction(html.HTMLElement):
return True
def _allowed(self, request, datum):
policy_check = getattr(settings, "POLICY_CHECK_FUNCTION", None)
policy_check = utils_settings.import_setting("POLICY_CHECK_FUNCTION")
if policy_check and self.policy_rules:
target = self.get_policy_target(request, datum)

28
horizon/utils/settings.py Normal file
View File

@ -0,0 +1,28 @@
# 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 six
from django.conf import settings
from django.utils.module_loading import import_string
def import_object(name_or_object):
if isinstance(name_or_object, six.string_types):
return import_string(name_or_object)
return name_or_object
def import_setting(name):
"""Imports an object specified either directly or as a module path."""
value = getattr(settings, name, None)
return import_object(value)

View File

@ -27,7 +27,6 @@ from mox3.mox import IgnoreArg # noqa
from mox3.mox import IsA # noqa
from horizon.workflows import views
from openstack_auth import policy as policy_backend
from openstack_dashboard import api
from openstack_dashboard.dashboards.identity.projects import workflows
@ -100,7 +99,7 @@ class TenantsViewTests(test.BaseAdminViewTests):
class ProjectsViewNonAdminTests(test.TestCase):
@override_settings(POLICY_CHECK_FUNCTION=policy_backend.check)
@override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check')
@test.create_stubs({api.keystone: ('tenant_list',
'domain_lookup')})
def test_index(self):

View File

@ -12,13 +12,13 @@
# under the License.
from django.conf import settings
from horizon.utils import settings as utils_settings
def check(actions, request, target=None):
"""Wrapper of the configurable policy method."""
policy_check = getattr(settings, "POLICY_CHECK_FUNCTION", None)
policy_check = utils_settings.import_setting("POLICY_CHECK_FUNCTION")
if policy_check:
return policy_check(actions, request, target)

View File

@ -305,14 +305,7 @@ THEME_COLLECTION_DIR = 'themes'
# Theme Cookie Name
THEME_COOKIE_NAME = 'theme'
def check(actions, request, target=None):
# Note(Itxaka): This is to prevent circular dependencies and apps not ready
# If you do django imports in your settings, you are gonna have a bad time
from openstack_auth import policy
return policy.check(actions, request, target)
POLICY_CHECK_FUNCTION = check
POLICY_CHECK_FUNCTION = 'openstack_auth.policy.check'
CSRF_COOKIE_AGE = None

View File

@ -617,7 +617,7 @@ class NeutronApiTests(test.APITestCase):
@override_settings(OPENSTACK_NEUTRON_NETWORK={'enable_distributed_router':
True},
POLICY_CHECK_FUNCTION=policy.check)
POLICY_CHECK_FUNCTION='openstack_auth.policy.check')
@test.create_stubs({api.neutron: ('is_extension_supported',)})
def _test_get_dvr_permission_with_policy_check(self, policy_check_allowed,
operation):
@ -655,7 +655,7 @@ class NeutronApiTests(test.APITestCase):
@override_settings(OPENSTACK_NEUTRON_NETWORK={'enable_distributed_router':
True},
POLICY_CHECK_FUNCTION=policy.check)
POLICY_CHECK_FUNCTION='openstack_auth.policy.check')
def test_get_dvr_permission_dvr_unsupported_operation(self):
self.assertRaises(ValueError,
api.neutron.get_feature_permission,
@ -675,7 +675,7 @@ class NeutronApiTests(test.APITestCase):
# above. l3-ha check only checks l3-ha specific code.
@override_settings(OPENSTACK_NEUTRON_NETWORK={'enable_ha_router': True},
POLICY_CHECK_FUNCTION=policy.check)
POLICY_CHECK_FUNCTION='openstack_auth.policy.check')
@test.create_stubs({api.neutron: ('is_extension_supported', )})
def _test_get_router_ha_permission_with_policy_check(self, ha_enabled):
self.mox.StubOutWithMock(policy, 'check')

View File

@ -11,46 +11,45 @@
# limitations under the License.
from django.test.utils import override_settings # noqa
from openstack_auth import policy as policy_backend
from openstack_dashboard.api.rest import policy
from openstack_dashboard.test import helpers as test
class PolicyRestTestCase(test.TestCase):
@override_settings(POLICY_CHECK_FUNCTION=policy_backend.check)
@override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check')
def test_policy(self, body='{"rules": []}'):
request = self.mock_rest_request(body=body)
response = policy.Policy().post(request)
self.assertStatusCode(response, 200)
self.assertEqual({"allowed": True}, response.json)
@override_settings(POLICY_CHECK_FUNCTION=policy_backend.check)
@override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check')
def test_rule_alone(self):
body = '{"rules": [["compute", "compute:get_all" ]]}'
self.test_policy(body)
@override_settings(POLICY_CHECK_FUNCTION=policy_backend.check)
@override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check')
def test_multiple_rule(self):
body = '{"rules": [["compute", "compute:get_all"],' \
' ["compute", "compute:start"]]}'
self.test_policy(body)
@override_settings(POLICY_CHECK_FUNCTION=policy_backend.check)
@override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check')
def test_rule_with_empty_target(self):
body = '{"rules": [["compute", "compute:get_all"],' \
' ["compute", "compute:start"]],' \
' "target": {}}'
self.test_policy(body)
@override_settings(POLICY_CHECK_FUNCTION=policy_backend.check)
@override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check')
def test_rule_with_target(self):
body = '{"rules": [["compute", "compute:get_all"],' \
' ["compute", "compute:start"]],' \
' "target": {"project_id": "1"}}'
self.test_policy(body)
@override_settings(POLICY_CHECK_FUNCTION=policy_backend.check)
@override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check')
def test_policy_fail(self):
# admin only rule, default test case user should fail
request = self.mock_rest_request(
@ -59,7 +58,7 @@ class PolicyRestTestCase(test.TestCase):
self.assertStatusCode(response, 200)
self.assertEqual({"allowed": False}, response.json)
@override_settings(POLICY_CHECK_FUNCTION=policy_backend.check)
@override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check')
def test_policy_error(self):
# admin only rule, default test case user should fail
request = self.mock_rest_request(
@ -69,7 +68,7 @@ class PolicyRestTestCase(test.TestCase):
class AdminPolicyRestTestCase(test.BaseAdminViewTests):
@override_settings(POLICY_CHECK_FUNCTION=policy_backend.check)
@override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check')
def test_rule_with_target(self):
body = '{"rules": [["compute", "compute:unlock_override"]]}'
request = self.mock_rest_request(body=body)

View File

@ -12,14 +12,13 @@
# under the License.
from django.test.utils import override_settings
from openstack_auth import policy as policy_backend
from openstack_dashboard import policy
from openstack_dashboard.test import helpers as test
class PolicyTestCase(test.TestCase):
@override_settings(POLICY_CHECK_FUNCTION=policy_backend.check)
@override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check')
def test_policy_check_set(self):
value = policy.check((("identity", "admin_required"),),
request=self.request)
@ -33,7 +32,7 @@ class PolicyTestCase(test.TestCase):
class PolicyBackendTestCaseAdmin(test.BaseAdminViewTests):
@override_settings(POLICY_CHECK_FUNCTION=policy_backend.check)
@override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check')
def test_policy_check_set_admin(self):
value = policy.check((("identity", "admin_required"),),
request=self.request)

View File

@ -31,14 +31,14 @@ class PolicyBackendTestCase(test.TestCase):
policy_backend.reset()
self.assertIsNone(policy_backend._ENFORCER)
@override_settings(POLICY_CHECK_FUNCTION=policy_backend.check)
@override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check')
def test_check_admin_required_false(self):
policy_backend.reset()
value = policy.check((("identity", "admin_required"),),
request=self.request)
self.assertFalse(value)
@override_settings(POLICY_CHECK_FUNCTION=policy_backend.check)
@override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check')
def test_check_identity_rule_not_found_false(self):
policy_backend.reset()
value = policy.check((("identity", "i_dont_exist"),),
@ -47,14 +47,14 @@ class PolicyBackendTestCase(test.TestCase):
# identity is admin_required
self.assertFalse(value)
@override_settings(POLICY_CHECK_FUNCTION=policy_backend.check)
@override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check')
def test_check_nova_context_is_admin_false(self):
policy_backend.reset()
value = policy.check((("compute", "context_is_admin"),),
request=self.request)
self.assertFalse(value)
@override_settings(POLICY_CHECK_FUNCTION=policy_backend.check)
@override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check')
def test_compound_check_false(self):
policy_backend.reset()
value = policy.check((("identity", "admin_required"),
@ -62,7 +62,7 @@ class PolicyBackendTestCase(test.TestCase):
request=self.request)
self.assertFalse(value)
@override_settings(POLICY_CHECK_FUNCTION=policy_backend.check)
@override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check')
def test_scope_not_found(self):
policy_backend.reset()
value = policy.check((("dummy", "default"),),
@ -71,14 +71,14 @@ class PolicyBackendTestCase(test.TestCase):
class PolicyBackendTestCaseAdmin(test.BaseAdminViewTests):
@override_settings(POLICY_CHECK_FUNCTION=policy_backend.check)
@override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check')
def test_check_admin_required_true(self):
policy_backend.reset()
value = policy.check((("identity", "admin_required"),),
request=self.request)
self.assertTrue(value)
@override_settings(POLICY_CHECK_FUNCTION=policy_backend.check)
@override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check')
def test_check_identity_rule_not_found_true(self):
policy_backend.reset()
value = policy.check((("identity", "i_dont_exist"),),
@ -87,7 +87,7 @@ class PolicyBackendTestCaseAdmin(test.BaseAdminViewTests):
# identity is admin_required
self.assertTrue(value)
@override_settings(POLICY_CHECK_FUNCTION=policy_backend.check)
@override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check')
def test_compound_check_true(self):
policy_backend.reset()
value = policy.check((("identity", "admin_required"),
@ -95,7 +95,7 @@ class PolicyBackendTestCaseAdmin(test.BaseAdminViewTests):
request=self.request)
self.assertTrue(value)
@override_settings(POLICY_CHECK_FUNCTION=policy_backend.check)
@override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check')
def test_check_nova_context_is_admin_true(self):
policy_backend.reset()
value = policy.check((("compute", "context_is_admin"),),