diff --git a/etc/magnum/policy.json b/etc/magnum/policy.json index 23a920e3f4..c80c277e9b 100644 --- a/etc/magnum/policy.json +++ b/etc/magnum/policy.json @@ -30,6 +30,13 @@ "pod:detail": "rule:default", "pod:get": "rule:default", "pod:get_all": "rule:default", - "pod:update": "rule:default" + "pod:update": "rule:default", + + "rc:create": "rule:default", + "rc:delete": "rule:default", + "rc:detail": "rule:default", + "rc:get": "rule:default", + "rc:get_all": "rule:default", + "rc:update": "rule:default" } diff --git a/magnum/api/controllers/v1/replicationcontroller.py b/magnum/api/controllers/v1/replicationcontroller.py index e6fe07b11b..1116fe8dab 100644 --- a/magnum/api/controllers/v1/replicationcontroller.py +++ b/magnum/api/controllers/v1/replicationcontroller.py @@ -28,6 +28,7 @@ from magnum.api import expose from magnum.api import validation from magnum.common import exception from magnum.common import k8s_manifest +from magnum.common import policy from magnum import objects @@ -228,6 +229,7 @@ class ReplicationControllersController(rest.RestController): sort_key=sort_key, sort_dir=sort_dir) + @policy.enforce_wsgi("rc") @expose.expose(ReplicationControllerCollection, types.uuid, types.uuid, int, wtypes.text, wtypes.text) def get_all(self, rc_uuid=None, marker=None, limit=None, @@ -242,6 +244,7 @@ class ReplicationControllersController(rest.RestController): return self._get_rcs_collection(marker, limit, sort_key, sort_dir) + @policy.enforce_wsgi("rc") @expose.expose(ReplicationControllerCollection, types.uuid, types.uuid, int, wtypes.text, wtypes.text) def detail(self, rc_uuid=None, marker=None, limit=None, @@ -266,6 +269,7 @@ class ReplicationControllersController(rest.RestController): sort_key, sort_dir, expand, resource_url) + @policy.enforce_wsgi("rc", "get") @expose.expose(ReplicationController, types.uuid_or_name) def get_one(self, rc_ident): """Retrieve information about the given ReplicationController. @@ -275,6 +279,7 @@ class ReplicationControllersController(rest.RestController): rpc_rc = api_utils.get_rpc_resource('ReplicationController', rc_ident) return ReplicationController.convert_with_links(rpc_rc) + @policy.enforce_wsgi("rc", "create") @expose.expose(ReplicationController, body=ReplicationController, status_code=201) @validation.enforce_bay_types('kubernetes') @@ -298,6 +303,7 @@ class ReplicationControllersController(rest.RestController): pecan.response.location = link.build_url('rcs', new_rc.uuid) return ReplicationController.convert_with_links(new_rc) + @policy.enforce_wsgi("rc", "update") @wsme.validate(types.uuid, [ReplicationControllerPatchType]) @expose.expose(ReplicationController, types.uuid_or_name, body=[ReplicationControllerPatchType]) @@ -339,6 +345,7 @@ class ReplicationControllersController(rest.RestController): rpc_rc.save() return ReplicationController.convert_with_links(rpc_rc) + @policy.enforce_wsgi("rc") @expose.expose(None, types.uuid_or_name, status_code=204) def delete(self, rc_ident): """Delete a ReplicationController. diff --git a/magnum/tests/fake_policy.py b/magnum/tests/fake_policy.py index 3ea3106f7b..42248d9124 100644 --- a/magnum/tests/fake_policy.py +++ b/magnum/tests/fake_policy.py @@ -46,7 +46,14 @@ policy_data = """ "pod:detail": "", "pod:get": "", "pod:get_all": "", - "pod:update": "" + "pod:update": "", + + "rc:create": "", + "rc:delete": "", + "rc:detail": "", + "rc:get": "", + "rc:get_all": "", + "rc:update": "" } """ diff --git a/magnum/tests/unit/api/controllers/v1/test_replicationcontroller.py b/magnum/tests/unit/api/controllers/v1/test_replicationcontroller.py index ce5fdc0933..119dc61892 100644 --- a/magnum/tests/unit/api/controllers/v1/test_replicationcontroller.py +++ b/magnum/tests/unit/api/controllers/v1/test_replicationcontroller.py @@ -14,6 +14,7 @@ import datetime import mock from oslo_config import cfg +from oslo_policy import policy from oslo_utils import timeutils from six.moves.urllib import parse as urlparse from wsme import types as wtypes @@ -496,3 +497,49 @@ class TestDelete(api_base.FunctionalTest): self.assertEqual(409, response.status_int) self.assertEqual('application/json', response.content_type) self.assertTrue(response.json['error_message']) + + +class TestRCEnforcement(api_base.FunctionalTest): + + def _common_policy_check(self, rule, func, *arg, **kwarg): + self.policy.set_rules({rule: 'project:non_fake'}) + exc = self.assertRaises(policy.PolicyNotAuthorized, + func, *arg, **kwarg) + self.assertTrue(exc.message.startswith(rule)) + self.assertTrue(exc.message.endswith('disallowed by policy')) + + def test_policy_disallow_get_all(self): + self._common_policy_check( + 'rc:get_all', self.get_json, '/rcs') + + def test_policy_disallow_get_one(self): + self._common_policy_check( + 'rc:get', self.get_json, '/rcs/111-222-333') + + def test_policy_disallow_detail(self): + self._common_policy_check( + 'rc:detail', self.get_json, '/rcs/111-222-333/detail') + + def test_policy_disallow_update(self): + rc = obj_utils.create_test_rc(self.context, + desc='test rc', + uuid=utils.generate_uuid()) + + new_image = 'rc_example_B_image' + self._common_policy_check( + 'rc:update', self.patch_json, + '/rcs/%s' % rc.uuid, + [{'path': '/images/0', 'value': new_image, 'op': 'replace'}]) + + def test_policy_disallow_create(self): + pdict = apiutils.rc_post_data() + self._common_policy_check( + 'rc:create', self.post_json, '/rcs', pdict) + + def test_policy_disallow_delete(self): + rc = obj_utils.create_test_rc(self.context, + name='test_rc', + uuid=utils.generate_uuid()) + self._common_policy_check( + 'rc:delete', self.delete, + '/rcs/%s' % rc.uuid)