From 6b617bc32aa2680868b8e24058a60986427852d0 Mon Sep 17 00:00:00 2001 From: Felipe Monteiro Date: Sun, 7 Jan 2018 19:47:30 +0000 Subject: [PATCH] Add RBAC tests to Armada to sanity-check RBAC implementation This PS adds negative RBAC API tests to Armada to sanity-check its RBAC implementation. One of the use cases for Armada even having an API server is RBAC. To that end, we should validate that it is working as intended in the negative case. Change-Id: If00f4ba45f694aa2ac556e7f4a940010a6d0a8a8 --- armada/tests/test_utils.py | 21 ++++++++++ .../tests/unit/api/test_armada_controller.py | 15 +++++++ armada/tests/unit/api/test_test_controller.py | 40 +++++++++++++++++++ .../tests/unit/api/test_tiller_controller.py | 25 ++++++++++++ .../unit/api/test_validation_controller.py | 30 ++++++++++++++ 5 files changed, 131 insertions(+) create mode 100644 armada/tests/unit/api/test_test_controller.py create mode 100644 armada/tests/unit/api/test_validation_controller.py diff --git a/armada/tests/test_utils.py b/armada/tests/test_utils.py index 079232e0..036f3a62 100644 --- a/armada/tests/test_utils.py +++ b/armada/tests/test_utils.py @@ -1,5 +1,6 @@ # Copyright 2010 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. +# Copyright 2015 Hewlett-Packard Development Company, L.P. # Copyright 2017 AT&T Intellectual Property. # All Rights Reserved. # @@ -19,6 +20,8 @@ import random import string import uuid +import testtools + def rand_uuid_hex(): """Generate a random UUID hex string @@ -86,3 +89,21 @@ def rand_password(length=15): pre = upper + digit + punc password = pre + ''.join(random.choice(seed) for x in range(length - 3)) return password + + +def attr(**kwargs): + """A decorator which applies the testtools attr decorator + + This decorator applies the testtools.testcase.attr if it is in the list of + attributes to testtools we want to apply. + """ + + def decorator(f): + if 'type' in kwargs and isinstance(kwargs['type'], str): + f = testtools.testcase.attr(kwargs['type'])(f) + elif 'type' in kwargs and isinstance(kwargs['type'], list): + for attr in kwargs['type']: + f = testtools.testcase.attr(attr)(f) + return f + + return decorator diff --git a/armada/tests/unit/api/test_armada_controller.py b/armada/tests/unit/api/test_armada_controller.py index 6efa743a..e0540c00 100644 --- a/armada/tests/unit/api/test_armada_controller.py +++ b/armada/tests/unit/api/test_armada_controller.py @@ -18,6 +18,8 @@ import mock from oslo_config import cfg from armada.api.controller import armada as armada_api +from armada.common.policies import base as policy_base +from armada.tests import test_utils from armada.tests.unit.api import base CONF = cfg.CONF @@ -99,3 +101,16 @@ class ArmadaControllerTest(base.BaseControllerTest): }, params=options) self.assertEqual(result.status_code, 400) + + +class ArmadaControllerNegativeRbacTest(base.BaseControllerTest): + + @test_utils.attr(type=['negative']) + def test_armada_apply_resource_insufficient_permissions(self): + """Tests the POST /api/v1.0/apply endpoint returns 403 following failed + authorization. + """ + rules = {'armada:create_endpoints': policy_base.RULE_ADMIN_REQUIRED} + self.policy.set_rules(rules) + resp = self.app.simulate_post('/api/v1.0/apply') + self.assertEqual(403, resp.status_code) diff --git a/armada/tests/unit/api/test_test_controller.py b/armada/tests/unit/api/test_test_controller.py new file mode 100644 index 00000000..c28bcf60 --- /dev/null +++ b/armada/tests/unit/api/test_test_controller.py @@ -0,0 +1,40 @@ +# Copyright 2017 AT&T Intellectual Property. All other 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 armada.common.policies import base as policy_base +from armada.tests import test_utils +from armada.tests.unit.api import base + + +class TestControllerNegativeRbacTest(base.BaseControllerTest): + + @test_utils.attr(type=['negative']) + def test_test_release_insufficient_permissions(self): + """Tests the GET /api/v1.0/test/{release} endpoint returns 403 + following failed authorization. + """ + rules = {'armada:test_release': policy_base.RULE_ADMIN_REQUIRED} + self.policy.set_rules(rules) + resp = self.app.simulate_get('/api/v1.0/test/test-release') + self.assertEqual(403, resp.status_code) + + @test_utils.attr(type=['negative']) + def test_tests_manifest_insufficient_permissions(self): + """Tests the POST /api/v1.0/tests endpoint returns 403 following failed + authorization. + """ + rules = {'armada:tests_manifest': policy_base.RULE_ADMIN_REQUIRED} + self.policy.set_rules(rules) + resp = self.app.simulate_post('/api/v1.0/tests') + self.assertEqual(403, resp.status_code) diff --git a/armada/tests/unit/api/test_tiller_controller.py b/armada/tests/unit/api/test_tiller_controller.py index 163761f0..7c6c4217 100644 --- a/armada/tests/unit/api/test_tiller_controller.py +++ b/armada/tests/unit/api/test_tiller_controller.py @@ -17,6 +17,8 @@ import mock from oslo_config import cfg from armada.api.controller import tiller as tiller_controller +from armada.common.policies import base as policy_base +from armada.tests import test_utils from armada.tests.unit.api import base CONF = cfg.CONF @@ -115,3 +117,26 @@ class TillerControllerTest(base.BaseControllerTest): mock_tiller.assert_called_once_with(tiller_host='fake_host', tiller_port='98765') mock_tiller.return_value.list_releases.assert_called_once_with() + + +class TillerControllerNegativeRbacTest(base.BaseControllerTest): + + @test_utils.attr(type=['negative']) + def test_list_tiller_releases_insufficient_permissions(self): + """Tests the GET /api/v1.0/releases endpoint returns 403 following + failed authorization. + """ + rules = {'tiller:get_release': policy_base.RULE_ADMIN_REQUIRED} + self.policy.set_rules(rules) + resp = self.app.simulate_get('/api/v1.0/releases') + self.assertEqual(403, resp.status_code) + + @test_utils.attr(type=['negative']) + def test_get_tiller_status_insufficient_permissions(self): + """Tests the GET /api/v1.0/status endpoint returns 403 following + failed authorization. + """ + rules = {'tiller:get_status': policy_base.RULE_ADMIN_REQUIRED} + self.policy.set_rules(rules) + resp = self.app.simulate_get('/api/v1.0/status') + self.assertEqual(403, resp.status_code) diff --git a/armada/tests/unit/api/test_validation_controller.py b/armada/tests/unit/api/test_validation_controller.py new file mode 100644 index 00000000..15d0dbcb --- /dev/null +++ b/armada/tests/unit/api/test_validation_controller.py @@ -0,0 +1,30 @@ +# Copyright 2017 AT&T Intellectual Property. All other 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 armada.common.policies import base as policy_base +from armada.tests import test_utils +from armada.tests.unit.api import base + + +class ValidationControllerNegativeRbacTest(base.BaseControllerTest): + + @test_utils.attr(type=['negative']) + def test_validate_manifest_insufficient_permissions(self): + """Tests the POST /api/v1.0/validate endpoint returns 403 following + failed authorization. + """ + rules = {'armada:validate_manifest': policy_base.RULE_ADMIN_REQUIRED} + self.policy.set_rules(rules) + resp = self.app.simulate_post('/api/v1.0/validate') + self.assertEqual(403, resp.status_code)