From 01a1a1ff843b780e836e32525b2d85e864577b8a Mon Sep 17 00:00:00 2001 From: Ricardo Dias Date: Tue, 24 Apr 2018 17:32:54 +0100 Subject: [PATCH] qa/tasks/mgr/dashboard: Adapted tests to work with new authentication system Signed-off-by: Ricardo Dias --- qa/tasks/mgr/dashboard/helper.py | 100 +++++++++++++++--- qa/tasks/mgr/dashboard/test_auth.py | 7 +- qa/tasks/mgr/dashboard/test_cephfs.py | 27 +++-- .../dashboard/test_cluster_configuration.py | 6 +- qa/tasks/mgr/dashboard/test_dashboard.py | 28 ++++- .../dashboard/test_erasure_code_profile.py | 21 +++- qa/tasks/mgr/dashboard/test_host.py | 10 +- qa/tasks/mgr/dashboard/test_monitor.py | 11 +- qa/tasks/mgr/dashboard/test_osd.py | 16 +-- qa/tasks/mgr/dashboard/test_perf_counters.py | 7 +- qa/tasks/mgr/dashboard/test_pool.py | 30 ++++-- qa/tasks/mgr/dashboard/test_rbd.py | 43 ++++++-- qa/tasks/mgr/dashboard/test_rgw.py | 81 +++++++------- qa/tasks/mgr/dashboard/test_summary.py | 20 +++- 14 files changed, 303 insertions(+), 104 deletions(-) diff --git a/qa/tasks/mgr/dashboard/helper.py b/qa/tasks/mgr/dashboard/helper.py index f6f524b51f6..0be556b2d13 100644 --- a/qa/tasks/mgr/dashboard/helper.py +++ b/qa/tasks/mgr/dashboard/helper.py @@ -10,6 +10,7 @@ import time import requests import six +from teuthology.exceptions import CommandFailedError from ..mgr_test_case import MgrTestCase @@ -17,15 +18,6 @@ from ..mgr_test_case import MgrTestCase log = logging.getLogger(__name__) -def authenticate(func): - def decorate(self, *args, **kwargs): - self._ceph_cmd(['dashboard', 'set-login-credentials', 'admin', 'admin']) - self._post('/api/auth', {'username': 'admin', 'password': 'admin'}) - self.assertStatus(201) - return func(self, *args, **kwargs) - return decorate - - class DashboardTestCase(MgrTestCase): MGRS_REQUIRED = 2 MDSS_REQUIRED = 1 @@ -35,13 +27,86 @@ class DashboardTestCase(MgrTestCase): _session = None _resp = None + _loggedin = False + _base_uri = None + + AUTO_AUTHENTICATE = True + + AUTH_ROLES = ['administrator'] + + @classmethod + def create_user(cls, username, password, roles): + try: + cls._ceph_cmd(['dashboard', 'ac-user-show', username]) + cls._ceph_cmd(['dashboard', 'ac-user-delete', username]) + except CommandFailedError as ex: + if ex.exitstatus != 2: + raise ex + + cls._ceph_cmd(['dashboard', 'ac-user-create', username, password]) + + set_roles_args = ['dashboard', 'ac-user-set-roles', username] + for idx, role in enumerate(roles): + if isinstance(role, str): + set_roles_args.append(role) + else: + assert isinstance(role, dict) + rolename = 'test_role_{}'.format(idx) + try: + cls._ceph_cmd(['dashboard', 'ac-role-show', rolename]) + cls._ceph_cmd(['dashboard', 'ac-role-delete', rolename]) + except CommandFailedError as ex: + if ex.exitstatus != 2: + raise ex + cls._ceph_cmd(['dashboard', 'ac-role-create', rolename]) + for mod, perms in role.items(): + args = ['dashboard', 'ac-role-add-scope-perms', rolename, mod] + args.extend(perms) + cls._ceph_cmd(args) + set_roles_args.append(rolename) + cls._ceph_cmd(set_roles_args) + + @classmethod + def login(cls, username, password): + if cls._loggedin: + cls.logout() + cls._post('/api/auth', {'username': username, 'password': password}) + cls._loggedin = True + + @classmethod + def logout(cls): + if cls._loggedin: + cls._delete('/api/auth') + cls._loggedin = False + + @classmethod + def delete_user(cls, username, roles=None): + if roles is None: + roles = [] + cls._ceph_cmd(['dashboard', 'ac-user-delete', username]) + for idx, role in enumerate(roles): + if isinstance(role, dict): + cls._ceph_cmd(['dashboard', 'ac-role-delete', 'test_role_{}'.format(idx)]) + + @classmethod + def RunAs(cls, username, password, roles): + def wrapper(func): + def execute(self, *args, **kwargs): + self.create_user(username, password, roles) + self.login(username, password) + res = func(self, *args, **kwargs) + self.logout() + self.delete_user(username, roles) + return res + return execute + return wrapper @classmethod def setUpClass(cls): super(DashboardTestCase, cls).setUpClass() cls._assign_ports("dashboard", "server_port") cls._load_module("dashboard") - cls.base_uri = cls._get_uri("dashboard").rstrip('/') + cls._base_uri = cls._get_uri("dashboard").rstrip('/') if cls.CEPHFS: cls.mds_cluster.clear_firewall() @@ -72,6 +137,14 @@ class DashboardTestCase(MgrTestCase): cls._session = requests.Session() cls._resp = None + cls.create_user('admin', 'admin', cls.AUTH_ROLES) + if cls.AUTO_AUTHENTICATE: + cls.login('admin', 'admin') + + def setUp(self): + if not self._loggedin and self.AUTO_AUTHENTICATE: + self.login('admin', 'admin') + @classmethod def tearDownClass(cls): super(DashboardTestCase, cls).tearDownClass() @@ -79,7 +152,7 @@ class DashboardTestCase(MgrTestCase): # pylint: disable=inconsistent-return-statements @classmethod def _request(cls, url, method, data=None, params=None): - url = "{}{}".format(cls.base_uri, url) + url = "{}{}".format(cls._base_uri, url) log.info("request %s to %s", method, url) if method == 'GET': cls._resp = cls._session.get(url, params=params, verify=False) @@ -155,7 +228,10 @@ class DashboardTestCase(MgrTestCase): @classmethod def _task_request(cls, method, url, data, timeout): res = cls._request(url, method, data) - cls._assertIn(cls._resp.status_code, [200, 201, 202, 204, 400]) + cls._assertIn(cls._resp.status_code, [200, 201, 202, 204, 400, 403]) + + if cls._resp.status_code == 403: + return None if cls._resp.status_code != 202: log.info("task finished immediately") diff --git a/qa/tasks/mgr/dashboard/test_auth.py b/qa/tasks/mgr/dashboard/test_auth.py index 6f2cc794697..c0d89ad7f71 100644 --- a/qa/tasks/mgr/dashboard/test_auth.py +++ b/qa/tasks/mgr/dashboard/test_auth.py @@ -8,15 +8,18 @@ from .helper import DashboardTestCase class AuthTest(DashboardTestCase): + + AUTO_AUTHENTICATE = False + def setUp(self): self.reset_session() - self._ceph_cmd(['dashboard', 'set-login-credentials', 'admin', 'admin']) def test_a_set_login_credentials(self): - self._ceph_cmd(['dashboard', 'set-login-credentials', 'admin2', 'admin2']) + self.create_user('admin2', 'admin2', ['administrator']) self._post("/api/auth", {'username': 'admin2', 'password': 'admin2'}) self.assertStatus(201) self.assertJsonBody({"username": "admin2"}) + self.delete_user('admin2') def test_login_valid(self): self._post("/api/auth", {'username': 'admin', 'password': 'admin'}) diff --git a/qa/tasks/mgr/dashboard/test_cephfs.py b/qa/tasks/mgr/dashboard/test_cephfs.py index 9560a957d25..e4a2ed4cc44 100644 --- a/qa/tasks/mgr/dashboard/test_cephfs.py +++ b/qa/tasks/mgr/dashboard/test_cephfs.py @@ -1,13 +1,24 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import -from .helper import DashboardTestCase, authenticate +from .helper import DashboardTestCase class CephfsTest(DashboardTestCase): CEPHFS = True - @authenticate + AUTH_ROLES = ['cephfs-manager'] + + @DashboardTestCase.RunAs('test', 'test', ['block-manager']) + def test_access_permissions(self): + fs_id = self.fs.get_namespace_id() + self._get("/api/cephfs/{}/clients".format(fs_id)) + self.assertStatus(403) + self._get("/api/cephfs/{}".format(fs_id)) + self.assertStatus(403) + self._get("/api/cephfs/{}/mds_counters".format(fs_id)) + self.assertStatus(403) + def test_cephfs_clients(self): fs_id = self.fs.get_namespace_id() data = self._get("/api/cephfs/{}/clients".format(fs_id)) @@ -16,7 +27,6 @@ class CephfsTest(DashboardTestCase): self.assertIn('status', data) self.assertIn('data', data) - @authenticate def test_cephfs_get(self): fs_id = self.fs.get_namespace_id() data = self._get("/api/cephfs/{}/".format(fs_id)) @@ -29,7 +39,6 @@ class CephfsTest(DashboardTestCase): self.assertIsNotNone(data['standbys']) self.assertIsNotNone(data['versions']) - @authenticate def test_cephfs_mds_counters(self): fs_id = self.fs.get_namespace_id() data = self._get("/api/cephfs/{}/mds_counters".format(fs_id)) @@ -38,17 +47,15 @@ class CephfsTest(DashboardTestCase): self.assertIsInstance(data, dict) self.assertIsNotNone(data) - @authenticate def test_cephfs_mds_counters_wrong(self): self._get("/api/cephfs/baadbaad/mds_counters") self.assertStatus(400) self.assertJsonBody({ - "component": 'cephfs', - "code": "invalid_cephfs_id", - "detail": "Invalid cephfs ID baadbaad" - }) + "component": 'cephfs', + "code": "invalid_cephfs_id", + "detail": "Invalid cephfs ID baadbaad" + }) - @authenticate def test_cephfs_list(self): data = self._get("/api/cephfs/") self.assertStatus(200) diff --git a/qa/tasks/mgr/dashboard/test_cluster_configuration.py b/qa/tasks/mgr/dashboard/test_cluster_configuration.py index d0e8c450c56..8728b59c48f 100644 --- a/qa/tasks/mgr/dashboard/test_cluster_configuration.py +++ b/qa/tasks/mgr/dashboard/test_cluster_configuration.py @@ -2,11 +2,11 @@ from __future__ import absolute_import import time -from .helper import DashboardTestCase, authenticate +from .helper import DashboardTestCase class ClusterConfigurationTest(DashboardTestCase): - @authenticate + def test_list(self): data = self._get('/api/cluster_conf') self.assertStatus(200) @@ -15,7 +15,6 @@ class ClusterConfigurationTest(DashboardTestCase): for conf in data: self._validate_single(conf) - @authenticate def test_get(self): data = self._get('/api/cluster_conf/admin_socket') self.assertStatus(200) @@ -25,7 +24,6 @@ class ClusterConfigurationTest(DashboardTestCase): data = self._get('/api/cluster_conf/fantasy_name') self.assertStatus(404) - @authenticate def test_get_specific_db_config_option(self): def _get_mon_allow_pool_delete_config(): data = self._get('/api/cluster_conf/mon_allow_pool_delete') diff --git a/qa/tasks/mgr/dashboard/test_dashboard.py b/qa/tasks/mgr/dashboard/test_dashboard.py index fa7001797ad..7587a400f6c 100644 --- a/qa/tasks/mgr/dashboard/test_dashboard.py +++ b/qa/tasks/mgr/dashboard/test_dashboard.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import -from .helper import DashboardTestCase, authenticate +from .helper import DashboardTestCase class DashboardTest(DashboardTestCase): CEPHFS = True - @authenticate def test_health(self): data = self._get("/api/dashboard/health") self.assertStatus(200) @@ -36,3 +35,28 @@ class DashboardTest(DashboardTestCase): self.assertIsNotNone(data['mgr_map']) self.assertIsNotNone(data['df']) + + + @DashboardTestCase.RunAs('test', 'test', ['pool-manager']) + def test_health_permissions(self): + data = self._get("/api/dashboard/health") + self.assertStatus(200) + + self.assertIn('health', data) + self.assertNotIn('mon_status', data) + self.assertNotIn('fs_map', data) + self.assertNotIn('osd_map', data) + self.assertNotIn('clog', data) + self.assertNotIn('audit_log', data) + self.assertIn('pools', data) + self.assertNotIn('mgr_map', data) + self.assertIn('df', data) + self.assertIsNotNone(data['health']) + self.assertIsNotNone(data['pools']) + + cluster_pools = self.ceph_cluster.mon_manager.list_pools() + self.assertEqual(len(cluster_pools), len(data['pools'])) + for pool in data['pools']: + self.assertIn(pool['pool_name'], cluster_pools) + + self.assertIsNotNone(data['df']) diff --git a/qa/tasks/mgr/dashboard/test_erasure_code_profile.py b/qa/tasks/mgr/dashboard/test_erasure_code_profile.py index 9cd0e78a238..cf5012f8dde 100644 --- a/qa/tasks/mgr/dashboard/test_erasure_code_profile.py +++ b/qa/tasks/mgr/dashboard/test_erasure_code_profile.py @@ -4,11 +4,27 @@ from __future__ import absolute_import import unittest -from .helper import DashboardTestCase, authenticate +from .helper import DashboardTestCase class ECPTest(DashboardTestCase): + AUTH_ROLES = ['pool-manager'] + + @DashboardTestCase.RunAs('test', 'test', ['block-manager']) + def test_read_access_permissions(self): + self._get("/api/erasure_code_profile") + self.assertStatus(403) + + @DashboardTestCase.RunAs('test', 'test', ['read-only']) + def test_write_access_permissions(self): + self._get("/api/erasure_code_profile") + self.assertStatus(200) + data = {'name': 'ecp32', 'k': 3, 'm': 2} + self._post('/api/erasure_code_profile', data) + self.assertStatus(403) + self._delete('/api/erasure_code_profile/default') + self.assertStatus(403) @classmethod def tearDownClass(cls): @@ -16,7 +32,6 @@ class ECPTest(DashboardTestCase): cls._ceph_cmd(['osd', 'erasure-code-profile', 'rm', 'ecp32']) cls._ceph_cmd(['osd', 'erasure-code-profile', 'rm', 'lrc']) - @authenticate def test_list(self): data = self._get('/api/erasure_code_profile') self.assertStatus(200) @@ -37,7 +52,6 @@ class ECPTest(DashboardTestCase): self.assertEqual(get_data, default[0]) - @authenticate def test_create(self): data = {'name': 'ecp32', 'k': 3, 'm': 2} self._post('/api/erasure_code_profile', data) @@ -62,7 +76,6 @@ class ECPTest(DashboardTestCase): self._delete('/api/erasure_code_profile/ecp32') self.assertStatus(204) - @authenticate def test_create_plugin(self): data = {'name': 'lrc', 'k': '2', 'm': '2', 'l': '2', 'plugin': 'lrc'} self._post('/api/erasure_code_profile', data) diff --git a/qa/tasks/mgr/dashboard/test_host.py b/qa/tasks/mgr/dashboard/test_host.py index efa28d91329..f6a8d25ccb4 100644 --- a/qa/tasks/mgr/dashboard/test_host.py +++ b/qa/tasks/mgr/dashboard/test_host.py @@ -1,12 +1,18 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import -from .helper import DashboardTestCase, authenticate +from .helper import DashboardTestCase class HostControllerTest(DashboardTestCase): - @authenticate + AUTH_ROLES = ['read-only'] + + @DashboardTestCase.RunAs('test', 'test', ['block-manager']) + def test_access_permissions(self): + self._get('/api/host') + self.assertStatus(403) + def test_host_list(self): data = self._get('/api/host') self.assertStatus(200) diff --git a/qa/tasks/mgr/dashboard/test_monitor.py b/qa/tasks/mgr/dashboard/test_monitor.py index 0b199cdb193..0cf7e25a282 100644 --- a/qa/tasks/mgr/dashboard/test_monitor.py +++ b/qa/tasks/mgr/dashboard/test_monitor.py @@ -1,11 +1,18 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import -from .helper import DashboardTestCase, authenticate +from .helper import DashboardTestCase class MonitorTest(DashboardTestCase): - @authenticate + AUTH_ROLES = ['cluster-manager'] + + @DashboardTestCase.RunAs('test', 'test', ['block-manager']) + def test_access_permissions(self): + self._get('/api/monitor') + self.assertStatus(403) + + def test_monitor_default(self): data = self._get("/api/monitor") self.assertStatus(200) diff --git a/qa/tasks/mgr/dashboard/test_osd.py b/qa/tasks/mgr/dashboard/test_osd.py index f322544b36f..f4f0b0ea86c 100644 --- a/qa/tasks/mgr/dashboard/test_osd.py +++ b/qa/tasks/mgr/dashboard/test_osd.py @@ -4,15 +4,23 @@ from __future__ import absolute_import import json -from .helper import DashboardTestCase, authenticate, JObj, JAny, JList, JLeaf, JTuple +from .helper import DashboardTestCase, JObj, JAny, JList, JLeaf, JTuple class OsdTest(DashboardTestCase): + AUTH_ROLES = ['cluster-manager'] + + @DashboardTestCase.RunAs('test', 'test', ['block-manager']) + def test_access_permissions(self): + self._get('/api/osd') + self.assertStatus(403) + self._get('/api/osd/0') + self.assertStatus(403) + def assert_in_and_not_none(self, data, properties): self.assertSchema(data, JObj({p: JAny(none=False) for p in properties}, allow_unknown=True)) - @authenticate def test_list(self): data = self._get('/api/osd') self.assertStatus(200) @@ -28,7 +36,6 @@ class OsdTest(DashboardTestCase): self.assertSchema(data['stats_history']['op_out_bytes'], JList(JTuple([JLeaf(int), JLeaf(float)]))) - @authenticate def test_details(self): data = self._get('/api/osd/0') self.assertStatus(200) @@ -37,7 +44,6 @@ class OsdTest(DashboardTestCase): self.assert_in_and_not_none(data['histogram']['osd'], ['op_w_latency_in_bytes_histogram', 'op_r_latency_out_bytes_histogram']) - @authenticate def test_scrub(self): self._post('/api/osd/0/scrub?deep=False') self.assertStatus(200) @@ -63,14 +69,12 @@ class OsdFlagsTest(DashboardTestCase): cls._put('/api/osd/flags', data={'flags': flags}) return sorted(cls._resp.json()) - @authenticate def test_list_osd_flags(self): flags = self._get('/api/osd/flags') self.assertStatus(200) self.assertEqual(len(flags), 3) self.assertEqual(sorted(flags), self._initial_flags) - @authenticate def test_add_osd_flag(self): flags = self._put_flags([ 'sortbitwise', 'recovery_deletes', 'purged_snapdirs', 'noout', diff --git a/qa/tasks/mgr/dashboard/test_perf_counters.py b/qa/tasks/mgr/dashboard/test_perf_counters.py index 276cd434866..069e667b927 100644 --- a/qa/tasks/mgr/dashboard/test_perf_counters.py +++ b/qa/tasks/mgr/dashboard/test_perf_counters.py @@ -1,12 +1,11 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import -from .helper import DashboardTestCase, authenticate +from .helper import DashboardTestCase class PerfCountersControllerTest(DashboardTestCase): - @authenticate def test_perf_counters_list(self): data = self._get('/api/perf_counters') self.assertStatus(200) @@ -34,28 +33,24 @@ class PerfCountersControllerTest(DashboardTestCase): self.assertIn('value', counter) - @authenticate def test_perf_counters_mon_get(self): mon = self.mons()[0] data = self._get('/api/perf_counters/mon/{}'.format(mon)) self.assertStatus(200) self._validate_perf(mon, 'mon', data, allow_empty=False) - @authenticate def test_perf_counters_mgr_get(self): mgr = self.mgr_cluster.mgr_ids[0] data = self._get('/api/perf_counters/mgr/{}'.format(mgr)) self.assertStatus(200) self._validate_perf(mgr, 'mgr', data, allow_empty=False) - @authenticate def test_perf_counters_mds_get(self): for mds in self.mds_cluster.mds_ids: data = self._get('/api/perf_counters/mds/{}'.format(mds)) self.assertStatus(200) self._validate_perf(mds, 'mds', data, allow_empty=True) - @authenticate def test_perf_counters_osd_get(self): for osd in self.ceph_cluster.mon_manager.get_osd_dump(): osd = osd['osd'] diff --git a/qa/tasks/mgr/dashboard/test_pool.py b/qa/tasks/mgr/dashboard/test_pool.py index 212ae8355a8..729519bbf1d 100644 --- a/qa/tasks/mgr/dashboard/test_pool.py +++ b/qa/tasks/mgr/dashboard/test_pool.py @@ -5,12 +5,14 @@ import logging import six -from .helper import DashboardTestCase, authenticate +from .helper import DashboardTestCase log = logging.getLogger(__name__) class PoolTest(DashboardTestCase): + AUTH_ROLES = ['pool-manager'] + @classmethod def tearDownClass(cls): super(PoolTest, cls).tearDownClass() @@ -18,7 +20,23 @@ class PoolTest(DashboardTestCase): cls._ceph_cmd(['osd', 'pool', 'delete', name, name, '--yes-i-really-really-mean-it']) cls._ceph_cmd(['osd', 'erasure-code-profile', 'rm', 'ecprofile']) - @authenticate + @DashboardTestCase.RunAs('test', 'test', [{'pool': ['create', 'update', 'delete']}]) + def test_read_access_permissions(self): + self._get('/api/pool') + self.assertStatus(403) + self._get('/api/pool/bla') + self.assertStatus(403) + + @DashboardTestCase.RunAs('test', 'test', [{'pool': ['read', 'update', 'delete']}]) + def test_create_access_permissions(self): + self._post('/api/pool/', {}) + self.assertStatus(403) + + @DashboardTestCase.RunAs('test', 'test', [{'pool': ['read', 'create', 'update']}]) + def test_delete_access_permissions(self): + self._delete('/api/pool/ddd') + self.assertStatus(403) + def test_pool_list(self): data = self._get("/api/pool") self.assertStatus(200) @@ -35,7 +53,6 @@ class PoolTest(DashboardTestCase): self.assertNotIn('stats', pool) self.assertIn(pool['pool_name'], cluster_pools) - @authenticate def test_pool_list_attrs(self): data = self._get("/api/pool?attrs=type,flags") self.assertStatus(200) @@ -50,7 +67,6 @@ class PoolTest(DashboardTestCase): self.assertNotIn('stats', pool) self.assertIn(pool['pool_name'], cluster_pools) - @authenticate def test_pool_list_stats(self): data = self._get("/api/pool?stats=true") self.assertStatus(200) @@ -66,7 +82,6 @@ class PoolTest(DashboardTestCase): self.assertIn('flags_names', pool) self.assertIn(pool['pool_name'], cluster_pools) - @authenticate def test_pool_get(self): cluster_pools = self.ceph_cluster.mon_manager.list_pools() pool = self._get("/api/pool/{}?stats=true&attrs=type,flags,stats" @@ -77,7 +92,6 @@ class PoolTest(DashboardTestCase): self.assertIn('stats', pool) self.assertNotIn('flags_names', pool) - @authenticate def _pool_create(self, data): try: self._post('/api/pool/', data) @@ -143,7 +157,6 @@ class PoolTest(DashboardTestCase): for data in pools: self._pool_create(data) - @authenticate def test_pool_create_fail(self): data = {'pool_type': u'replicated', 'rule_name': u'dnf', 'pg_num': u'8', 'pool': u'sadfs'} self._post('/api/pool/', data) @@ -154,7 +167,6 @@ class PoolTest(DashboardTestCase): 'detail': "[errno -2] specified rule dnf doesn't exist" }) - @authenticate def test_pool_info(self): info_data = self._get("/api/pool/_info") self.assertEqual(set(info_data), @@ -172,5 +184,3 @@ class PoolTest(DashboardTestCase): all(isinstance(n, six.string_types) for n in info_data['compression_algorithms'])) self.assertTrue( all(isinstance(n, six.string_types) for n in info_data['compression_modes'])) - - diff --git a/qa/tasks/mgr/dashboard/test_rbd.py b/qa/tasks/mgr/dashboard/test_rbd.py index 80705aaac91..e0068297035 100644 --- a/qa/tasks/mgr/dashboard/test_rbd.py +++ b/qa/tasks/mgr/dashboard/test_rbd.py @@ -7,11 +7,7 @@ from .helper import DashboardTestCase, JObj, JLeaf, JList class RbdTest(DashboardTestCase): - - @classmethod - def authenticate(cls): - cls._ceph_cmd(['dashboard', 'set-login-credentials', 'admin', 'admin']) - cls._post('/api/auth', {'username': 'admin', 'password': 'admin'}) + AUTH_ROLES = ['pool-manager', 'block-manager'] @classmethod def create_pool(cls, name, pg_num, pool_type, application='rbd'): @@ -25,6 +21,42 @@ class RbdTest(DashboardTestCase): data['flags'] = ['ec_overwrites'] cls._post("/api/pool", data) + @DashboardTestCase.RunAs('test', 'test', [{'rbd-image': ['create', 'update', 'delete']}]) + def test_read_access_permissions(self): + self._get('/api/block/image') + self.assertStatus(403) + self._get('/api/block/image/pool/image') + self.assertStatus(403) + + @DashboardTestCase.RunAs('test', 'test', [{'rbd-image': ['read', 'update', 'delete']}]) + def test_create_access_permissions(self): + self.create_image('pool', 'name', 0) + self.assertStatus(403) + self.create_snapshot('pool', 'image', 'snapshot') + self.assertStatus(403) + self.copy_image('src_pool', 'src_image', 'dest_pool', 'dest_image') + self.assertStatus(403) + self.clone_image('parent_pool', 'parent_image', 'parent_snap', 'pool', 'name') + self.assertStatus(403) + + @DashboardTestCase.RunAs('test', 'test', [{'rbd-image': ['read', 'create', 'delete']}]) + def test_update_access_permissions(self): + self.edit_image('pool', 'image') + self.assertStatus(403) + self.update_snapshot('pool', 'image', 'snapshot', None, None) + self.assertStatus(403) + self._task_post('/api/block/image/rbd/rollback_img/snap/snap1/rollback') + self.assertStatus(403) + self.flatten_image('pool', 'image') + self.assertStatus(403) + + @DashboardTestCase.RunAs('test', 'test', [{'rbd-image': ['read', 'create', 'update']}]) + def test_delete_access_permissions(self): + self.remove_image('pool', 'image') + self.assertStatus(403) + self.remove_snapshot('pool', 'image', 'snapshot') + self.assertStatus(403) + @classmethod def create_image(cls, pool, name, size, **kwargs): data = {'name': name, 'pool_name': pool, 'size': size} @@ -80,7 +112,6 @@ class RbdTest(DashboardTestCase): @classmethod def setUpClass(cls): super(RbdTest, cls).setUpClass() - cls.authenticate() cls.create_pool('rbd', 10, 'replicated') cls.create_pool('rbd_iscsi', 10, 'replicated') diff --git a/qa/tasks/mgr/dashboard/test_rgw.py b/qa/tasks/mgr/dashboard/test_rgw.py index b913b22aa3d..846eff4122e 100644 --- a/qa/tasks/mgr/dashboard/test_rgw.py +++ b/qa/tasks/mgr/dashboard/test_rgw.py @@ -1,10 +1,11 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import -import urllib import logging -logger = logging.getLogger(__name__) -from .helper import DashboardTestCase, authenticate +from .helper import DashboardTestCase + + +logger = logging.getLogger(__name__) class RgwTestCase(DashboardTestCase): @@ -12,6 +13,8 @@ class RgwTestCase(DashboardTestCase): maxDiff = None create_test_user = False + AUTH_ROLES = ['rgw-manager'] + @classmethod def setUpClass(cls): super(RgwTestCase, cls).setUpClass() @@ -49,7 +52,10 @@ class RgwTestCase(DashboardTestCase): def tearDownClass(cls): if cls.create_test_user: cls._radosgw_admin_cmd(['user', 'rm', '--uid=teuth-test-user']) - super(DashboardTestCase, cls).tearDownClass() + super(RgwTestCase, cls).tearDownClass() + + def setUp(self): + super(RgwTestCase, self).setUp() def get_rgw_user(self, uid): return self._get('/api/rgw/user/{}'.format(uid)) @@ -68,17 +74,20 @@ class RgwTestCase(DashboardTestCase): class RgwApiCredentialsTest(RgwTestCase): + AUTH_ROLES = ['rgw-manager'] + def setUp(self): # Restart the Dashboard module to ensure that the connection to the # RGW Admin Ops API is re-established with the new credentials. + self.logout() self._ceph_cmd(['mgr', 'module', 'disable', 'dashboard']) self._ceph_cmd(['mgr', 'module', 'enable', 'dashboard', '--force']) # Set the default credentials. self._ceph_cmd(['dashboard', 'set-rgw-api-user-id', '']) self._ceph_cmd(['dashboard', 'set-rgw-api-secret-key', 'admin']) self._ceph_cmd(['dashboard', 'set-rgw-api-access-key', 'admin']) + super(RgwApiCredentialsTest, self).setUp() - @authenticate def test_no_access_secret_key(self): self._ceph_cmd(['dashboard', 'set-rgw-api-secret-key', '']) self._ceph_cmd(['dashboard', 'set-rgw-api-access-key', '']) @@ -87,9 +96,8 @@ class RgwApiCredentialsTest(RgwTestCase): self.assertIn('detail', resp) self.assertIn('component', resp) self.assertIn('No RGW credentials found', resp['detail']) - self.assertEquals(resp['component'], 'rgw') + self.assertEqual(resp['component'], 'rgw') - @authenticate def test_success(self): data = self._get('/api/rgw/status') self.assertStatus(200) @@ -97,7 +105,6 @@ class RgwApiCredentialsTest(RgwTestCase): self.assertIn('message', data) self.assertTrue(data['available']) - @authenticate def test_invalid_user_id(self): self._ceph_cmd(['dashboard', 'set-rgw-api-user-id', 'xyz']) data = self._get('/api/rgw/status') @@ -111,12 +118,13 @@ class RgwApiCredentialsTest(RgwTestCase): class RgwBucketTest(RgwTestCase): + AUTH_ROLES = ['rgw-manager'] + @classmethod def setUpClass(cls): cls.create_test_user = True super(RgwBucketTest, cls).setUpClass() - @authenticate def test_all(self): # Create a new bucket. self._post( @@ -134,7 +142,7 @@ class RgwBucketTest(RgwTestCase): self.assertIn('creation_time', data) self.assertIn('name', data['bucket']) self.assertIn('bucket_id', data['bucket']) - self.assertEquals(data['bucket']['name'], 'teuth-test-bucket') + self.assertEqual(data['bucket']['name'], 'teuth-test-bucket') # List all buckets. data = self._get('/api/rgw/bucket') @@ -149,8 +157,8 @@ class RgwBucketTest(RgwTestCase): self.assertIn('bucket', data) self.assertIn('bucket_quota', data) self.assertIn('owner', data) - self.assertEquals(data['bucket'], 'teuth-test-bucket') - self.assertEquals(data['owner'], 'admin') + self.assertEqual(data['bucket'], 'teuth-test-bucket') + self.assertEqual(data['owner'], 'admin') # Update the bucket. self._put( @@ -162,7 +170,7 @@ class RgwBucketTest(RgwTestCase): self.assertStatus(200) data = self._get('/api/rgw/bucket/teuth-test-bucket') self.assertStatus(200) - self.assertEquals(data['owner'], 'teuth-test-user') + self.assertEqual(data['owner'], 'teuth-test-user') # Delete the bucket. self._delete('/api/rgw/bucket/teuth-test-bucket') @@ -174,7 +182,16 @@ class RgwBucketTest(RgwTestCase): class RgwDaemonTest(DashboardTestCase): - @authenticate + AUTH_ROLES = ['rgw-manager'] + + + @DashboardTestCase.RunAs('test', 'test', [{'rgw': ['create', 'update', 'delete']}]) + def test_read_access_permissions(self): + self._get('/api/rgw/daemon') + self.assertStatus(403) + self._get('/api/rgw/daemon/id') + self.assertStatus(403) + def test_list(self): data = self._get('/api/rgw/daemon') self.assertStatus(200) @@ -184,7 +201,6 @@ class RgwDaemonTest(DashboardTestCase): self.assertIn('version', data) self.assertIn('server_hostname', data) - @authenticate def test_get(self): data = self._get('/api/rgw/daemon') self.assertStatus(200) @@ -196,7 +212,6 @@ class RgwDaemonTest(DashboardTestCase): self.assertIn('rgw_status', data) self.assertTrue(data['rgw_metadata']) - @authenticate def test_status(self): self._radosgw_admin_cmd([ 'user', 'create', '--uid=admin', '--display-name=admin', @@ -215,6 +230,8 @@ class RgwDaemonTest(DashboardTestCase): class RgwUserTest(RgwTestCase): + AUTH_ROLES = ['rgw-manager'] + @classmethod def setUpClass(cls): super(RgwUserTest, cls).setUpClass() @@ -232,21 +249,18 @@ class RgwUserTest(RgwTestCase): self.assertIn('tenant', data) self.assertIn('user_id', data) - @authenticate def test_get(self): data = self.get_rgw_user('admin') self.assertStatus(200) self._assert_user_data(data) - self.assertEquals(data['user_id'], 'admin') + self.assertEqual(data['user_id'], 'admin') - @authenticate def test_list(self): data = self._get('/api/rgw/user') self.assertStatus(200) self.assertGreaterEqual(len(data), 1) self.assertIn('admin', data) - @authenticate def test_create_update_delete(self): # Create a new user. self._post('/api/rgw/user', params={ @@ -256,14 +270,14 @@ class RgwUserTest(RgwTestCase): self.assertStatus(201) data = self.jsonBody() self._assert_user_data(data) - self.assertEquals(data['user_id'], 'teuth-test-user') - self.assertEquals(data['display_name'], 'display name') + self.assertEqual(data['user_id'], 'teuth-test-user') + self.assertEqual(data['display_name'], 'display name') # Get the user. data = self.get_rgw_user('teuth-test-user') self.assertStatus(200) self._assert_user_data(data) - self.assertEquals(data['user_id'], 'teuth-test-user') + self.assertEqual(data['user_id'], 'teuth-test-user') # Update the user. self._put( @@ -291,12 +305,13 @@ class RgwUserTest(RgwTestCase): class RgwUserCapabilityTest(RgwTestCase): + AUTH_ROLES = ['rgw-manager'] + @classmethod def setUpClass(cls): cls.create_test_user = True super(RgwUserCapabilityTest, cls).setUpClass() - @authenticate def test_set(self): self._post( '/api/rgw/user/teuth-test-user/capability', @@ -318,7 +333,6 @@ class RgwUserCapabilityTest(RgwTestCase): self.assertEqual(data['caps'][0]['type'], 'usage') self.assertEqual(data['caps'][0]['perm'], 'read') - @authenticate def test_delete(self): self._delete( '/api/rgw/user/teuth-test-user/capability', @@ -336,12 +350,13 @@ class RgwUserCapabilityTest(RgwTestCase): class RgwUserKeyTest(RgwTestCase): + AUTH_ROLES = ['rgw-manager'] + @classmethod def setUpClass(cls): cls.create_test_user = True super(RgwUserKeyTest, cls).setUpClass() - @authenticate def test_create_s3(self): self._post( '/api/rgw/user/teuth-test-user/key', @@ -358,7 +373,6 @@ class RgwUserKeyTest(RgwTestCase): self.assertIsInstance(key, object) self.assertEqual(key['secret_key'], 'aaabbbccc') - @authenticate def test_create_swift(self): self._post( '/api/rgw/user/teuth-test-user/key', @@ -374,7 +388,6 @@ class RgwUserKeyTest(RgwTestCase): key = self.find_in_list('secret_key', 'xxxyyyzzz', data) self.assertIsInstance(key, object) - @authenticate def test_delete_s3(self): self._delete( '/api/rgw/user/teuth-test-user/key', @@ -384,7 +397,6 @@ class RgwUserKeyTest(RgwTestCase): }) self.assertStatus(204) - @authenticate def test_delete_swift(self): self._delete( '/api/rgw/user/teuth-test-user/key', @@ -397,6 +409,8 @@ class RgwUserKeyTest(RgwTestCase): class RgwUserQuotaTest(RgwTestCase): + AUTH_ROLES = ['rgw-manager'] + @classmethod def setUpClass(cls): cls.create_test_user = True @@ -414,13 +428,11 @@ class RgwUserQuotaTest(RgwTestCase): self.assertIn('max_size_kb', data['bucket_quota']) self.assertIn('max_size', data['bucket_quota']) - @authenticate def test_get_quota(self): data = self._get('/api/rgw/user/teuth-test-user/quota') self.assertStatus(200) self._assert_quota(data) - @authenticate def test_set_user_quota(self): self._put( '/api/rgw/user/teuth-test-user/quota', @@ -439,7 +451,6 @@ class RgwUserQuotaTest(RgwTestCase): self.assertTrue(data['user_quota']['enabled']) self.assertEqual(data['user_quota']['max_size_kb'], 2048) - @authenticate def test_set_bucket_quota(self): self._put( '/api/rgw/user/teuth-test-user/quota', @@ -461,12 +472,13 @@ class RgwUserQuotaTest(RgwTestCase): class RgwUserSubuserTest(RgwTestCase): + AUTH_ROLES = ['rgw-manager'] + @classmethod def setUpClass(cls): cls.create_test_user = True super(RgwUserSubuserTest, cls).setUpClass() - @authenticate def test_create_swift(self): self._post( '/api/rgw/user/teuth-test-user/subuser', @@ -487,7 +499,6 @@ class RgwUserSubuserTest(RgwTestCase): key = self.find_in_list('user', 'teuth-test-user:tux', data['swift_keys']) self.assertIsInstance(key, object) - @authenticate def test_create_s3(self): self._post( '/api/rgw/user/teuth-test-user/subuser', @@ -511,7 +522,6 @@ class RgwUserSubuserTest(RgwTestCase): self.assertIsInstance(key, object) self.assertEqual(key['secret_key'], 'xxx') - @authenticate def test_delete_w_purge(self): self._delete( '/api/rgw/user/teuth-test-user/subuser/teuth-test-subuser2') @@ -524,7 +534,6 @@ class RgwUserSubuserTest(RgwTestCase): data['swift_keys']) self.assertIsNone(key) - @authenticate def test_delete_wo_purge(self): self._delete( '/api/rgw/user/teuth-test-user/subuser/teuth-test-subuser', diff --git a/qa/tasks/mgr/dashboard/test_summary.py b/qa/tasks/mgr/dashboard/test_summary.py index 1bea22e09c1..1a5d1e9918f 100644 --- a/qa/tasks/mgr/dashboard/test_summary.py +++ b/qa/tasks/mgr/dashboard/test_summary.py @@ -1,12 +1,11 @@ from __future__ import absolute_import -from .helper import DashboardTestCase, authenticate +from .helper import DashboardTestCase class SummaryTest(DashboardTestCase): CEPHFS = True - @authenticate def test_summary(self): data = self._get("/api/summary") self.assertStatus(200) @@ -22,3 +21,20 @@ class SummaryTest(DashboardTestCase): self.assertIsNotNone(data['mgr_id']) self.assertIsNotNone(data['have_mon_connection']) self.assertEqual(data['rbd_mirroring'], {'errors': 0, 'warnings': 0}) + + @DashboardTestCase.RunAs('test', 'test', ['pool-manager']) + def test_summary_permissions(self): + data = self._get("/api/summary") + self.assertStatus(200) + + self.assertIn('health_status', data) + self.assertIn('mgr_id', data) + self.assertIn('have_mon_connection', data) + self.assertNotIn('rbd_mirroring', data) + self.assertIn('executing_tasks', data) + self.assertIn('finished_tasks', data) + self.assertIn('version', data) + self.assertIsNotNone(data['health_status']) + self.assertIsNotNone(data['mgr_id']) + self.assertIsNotNone(data['have_mon_connection']) + -- 2.39.5