]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
qa/tasks/mgr/dashboard: Adapted tests to work with new authentication system
authorRicardo Dias <rdias@suse.com>
Tue, 24 Apr 2018 16:32:54 +0000 (17:32 +0100)
committerRicardo Dias <rdias@suse.com>
Tue, 26 Jun 2018 11:28:54 +0000 (12:28 +0100)
Signed-off-by: Ricardo Dias <rdias@suse.com>
14 files changed:
qa/tasks/mgr/dashboard/helper.py
qa/tasks/mgr/dashboard/test_auth.py
qa/tasks/mgr/dashboard/test_cephfs.py
qa/tasks/mgr/dashboard/test_cluster_configuration.py
qa/tasks/mgr/dashboard/test_dashboard.py
qa/tasks/mgr/dashboard/test_erasure_code_profile.py
qa/tasks/mgr/dashboard/test_host.py
qa/tasks/mgr/dashboard/test_monitor.py
qa/tasks/mgr/dashboard/test_osd.py
qa/tasks/mgr/dashboard/test_perf_counters.py
qa/tasks/mgr/dashboard/test_pool.py
qa/tasks/mgr/dashboard/test_rbd.py
qa/tasks/mgr/dashboard/test_rgw.py
qa/tasks/mgr/dashboard/test_summary.py

index f6f524b51f68ce29c9542d5bad65e74fd88e3913..0be556b2d137de800c5c14cbc405e8cf96b42c4a 100644 (file)
@@ -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")
index 6f2cc7946977c815a4269cfef718cd410fe36bb0..c0d89ad7f7129a6150b514c7962b8f4269f06fd7 100644 (file)
@@ -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'})
index 9560a957d256fb36bbc6a2a39b75440c5e319a39..e4a2ed4cc447331b30b284d8ad9c6f3d214fdad1 100644 (file)
@@ -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)
index d0e8c450c5694838c39feb60fae10a23e12800f8..8728b59c48f1f1c605d990b740874f003bd7233f 100644 (file)
@@ -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')
index fa7001797ad2753d8d029adf6deafff0d4d182dd..7587a400f6c6765c3b262176a2e778fb8c57d793 100644 (file)
@@ -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'])
index 9cd0e78a238a98d925f9028936aa88ed50001574..cf5012f8dde4c590cd9ab48ad7971d9ed46fd6e9 100644 (file)
@@ -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)
index efa28d91329218c4af7d40173c194e6c6e1b567e..f6a8d25ccb4101b75476af0567ea1d00af5cdbe9 100644 (file)
@@ -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)
index 0b199cdb1934054ad817c1353b44954e085983cf..0cf7e25a282a6b6e4229eb34ea6095627eedac6c 100644 (file)
@@ -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)
index f322544b36f6232134455b0dd52666b6b6a499d1..f4f0b0ea86ce68688d2fc3e1e5d0d5a91974a89a 100644 (file)
@@ -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',
index 276cd434866a8bb4ad1a2ea60c4e772c46190358..069e667b927c4b594d749830dac661710c996a4e 100644 (file)
@@ -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']
index 212ae8355a870886b7016f4b731dde42ae0b6001..729519bbf1d76095ff58f009034e2cd312f76008 100644 (file)
@@ -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']))
-
-
index 80705aaac9113e9a2fd09cfc3f82b58edc4f40d8..e00682970354d336476d731aa3c5cc9c09bd6bce 100644 (file)
@@ -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')
 
index b913b22aa3de4148032aac6ee21f7843a91fc229..846eff4122e87615fc71d3f3f9b0b35c80619208 100644 (file)
@@ -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',
index 1bea22e09c18f6064e82c078c17b033e2dc67d38..1a5d1e9918f949c51a5173e2b9d5d1a4be8f86ba 100644 (file)
@@ -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'])
+