From 3c2f451b24cda08468bd19300d0799bd5549c431 Mon Sep 17 00:00:00 2001 From: Ricardo Dias Date: Tue, 24 Apr 2018 13:48:38 +0100 Subject: [PATCH] mgr/dashboard: removed `@AuthRequired` decorator Now all controllers require authentication by default. No disable authentication, a boolean parameter can be passed in the `@ApiController` decorator. Fixes: http://tracker.ceph.com/issues/23796 Signed-off-by: Ricardo Dias --- .../mgr/dashboard/controllers/__init__.py | 39 +++++++------------ src/pybind/mgr/dashboard/controllers/auth.py | 2 +- .../mgr/dashboard/controllers/cephfs.py | 5 +-- .../controllers/cluster_configuration.py | 3 +- .../mgr/dashboard/controllers/dashboard.py | 3 +- src/pybind/mgr/dashboard/controllers/docs.py | 3 +- .../controllers/erasure_code_profile.py | 3 +- .../mgr/dashboard/controllers/grafana.py | 4 +- src/pybind/mgr/dashboard/controllers/host.py | 3 +- .../mgr/dashboard/controllers/logging.py | 2 +- .../mgr/dashboard/controllers/monitor.py | 3 +- src/pybind/mgr/dashboard/controllers/osd.py | 3 +- .../dashboard/controllers/perf_counters.py | 9 +---- src/pybind/mgr/dashboard/controllers/pool.py | 3 +- src/pybind/mgr/dashboard/controllers/rbd.py | 4 +- .../dashboard/controllers/rbd_mirroring.py | 3 +- src/pybind/mgr/dashboard/controllers/rgw.py | 6 +-- .../mgr/dashboard/controllers/summary.py | 4 +- src/pybind/mgr/dashboard/controllers/task.py | 3 +- .../mgr/dashboard/controllers/tcmu_iscsi.py | 3 +- .../mgr/dashboard/tests/test_controllers.py | 6 +-- .../mgr/dashboard/tests/test_exceptions.py | 2 +- .../mgr/dashboard/tests/test_grafana.py | 2 +- .../mgr/dashboard/tests/test_rest_tasks.py | 2 +- src/pybind/mgr/dashboard/tests/test_tools.py | 8 ++-- 25 files changed, 44 insertions(+), 84 deletions(-) diff --git a/src/pybind/mgr/dashboard/controllers/__init__.py b/src/pybind/mgr/dashboard/controllers/__init__.py index a86c753cff50f..328eb271d892c 100644 --- a/src/pybind/mgr/dashboard/controllers/__init__.py +++ b/src/pybind/mgr/dashboard/controllers/__init__.py @@ -21,9 +21,10 @@ from ..services.exception import serialize_dashboard_exception class Controller(object): - def __init__(self, path, base_url=None): + def __init__(self, path, base_url=None, secure=True): self.path = path self.base_url = base_url + self.secure = secure if self.path and self.path[0] != "/": self.path = "/" + self.path @@ -44,19 +45,19 @@ class Controller(object): 'tools.sessions.on': True, 'tools.sessions.name': Session.NAME, 'tools.session_expire_at_browser_close.on': True, - 'tools.dashboard_exception_handler.on': True + 'tools.dashboard_exception_handler.on': True, + 'tools.authenticate.on': self.secure, } if not hasattr(cls, '_cp_config'): cls._cp_config = {} - if 'tools.authenticate.on' not in cls._cp_config: - config['tools.authenticate.on'] = False cls._cp_config.update(config) return cls class ApiController(Controller): - def __init__(self, path): - super(ApiController, self).__init__(path, base_url="/api") + def __init__(self, path, secure=True): + super(ApiController, self).__init__(path, base_url="/api", + secure=secure) def __call__(self, cls): cls = super(ApiController, self).__call__(cls) @@ -65,24 +66,10 @@ class ApiController(Controller): class UiApiController(Controller): - def __init__(self, path): - super(UiApiController, self).__init__(path, base_url="/ui-api") - - -def AuthRequired(enabled=True): - if not isinstance(enabled, bool): - raise TypeError('AuthRequired used incorrectly. ' - 'You are likely missing parentheses!') - - def decorate(cls): - if not hasattr(cls, '_cp_config'): - cls._cp_config = { - 'tools.authenticate.on': enabled - } - else: - cls._cp_config['tools.authenticate.on'] = enabled - return cls - return decorate + def __init__(self, path, security_scope=None, secure=True): + super(UiApiController, self).__init__(path, base_url="/ui-api", + security_scope=security_scope, + secure=secure) def Endpoint(method=None, path=None, path_params=None, query_params=None, @@ -434,8 +421,8 @@ class BaseController(object): path_params = [p['name'] for p in self.path_params] query_params = [p['name'] for p in self.query_params] return [p for p in func_params - if p['name'] not in path_params and - p['name'] not in query_params] + if p['name'] not in path_params + and p['name'] not in query_params] @property def group(self): diff --git a/src/pybind/mgr/dashboard/controllers/auth.py b/src/pybind/mgr/dashboard/controllers/auth.py index 17e5eb9fa4ef4..033e5ea27c961 100644 --- a/src/pybind/mgr/dashboard/controllers/auth.py +++ b/src/pybind/mgr/dashboard/controllers/auth.py @@ -12,7 +12,7 @@ from ..services.auth import AuthManager from ..tools import Session -@ApiController('/auth') +@ApiController('/auth', secure=False) class Auth(RESTController): """ Provide login and logout actions. diff --git a/src/pybind/mgr/dashboard/controllers/cephfs.py b/src/pybind/mgr/dashboard/controllers/cephfs.py index b6cc36d21c959..90fa5c9c0b8c0 100644 --- a/src/pybind/mgr/dashboard/controllers/cephfs.py +++ b/src/pybind/mgr/dashboard/controllers/cephfs.py @@ -5,15 +5,14 @@ from collections import defaultdict import cherrypy -from ..exceptions import DashboardException -from . import ApiController, AuthRequired, RESTController +from . import ApiController, RESTController from .. import mgr +from ..exceptions import DashboardException from ..services.ceph_service import CephService from ..tools import ViewCache @ApiController('/cephfs') -@AuthRequired() class CephFS(RESTController): def __init__(self): super(CephFS, self).__init__() diff --git a/src/pybind/mgr/dashboard/controllers/cluster_configuration.py b/src/pybind/mgr/dashboard/controllers/cluster_configuration.py index 0e724cf1a4acc..03597d5afbbef 100644 --- a/src/pybind/mgr/dashboard/controllers/cluster_configuration.py +++ b/src/pybind/mgr/dashboard/controllers/cluster_configuration.py @@ -3,13 +3,12 @@ from __future__ import absolute_import import cherrypy +from . import ApiController, RESTController from .. import mgr from ..services.ceph_service import CephService -from . import ApiController, RESTController, AuthRequired @ApiController('/cluster_conf') -@AuthRequired() class ClusterConfiguration(RESTController): def _append_config_option_values(self, options): diff --git a/src/pybind/mgr/dashboard/controllers/dashboard.py b/src/pybind/mgr/dashboard/controllers/dashboard.py index 4e21810b4b496..87bf62089bdb6 100644 --- a/src/pybind/mgr/dashboard/controllers/dashboard.py +++ b/src/pybind/mgr/dashboard/controllers/dashboard.py @@ -4,7 +4,7 @@ from __future__ import absolute_import import collections import json -from . import ApiController, AuthRequired, Endpoint, BaseController +from . import ApiController, Endpoint, BaseController from .. import mgr from ..services.ceph_service import CephService from ..tools import NotificationQueue @@ -14,7 +14,6 @@ LOG_BUFFER_SIZE = 30 @ApiController('/dashboard') -@AuthRequired() class Dashboard(BaseController): def __init__(self): super(Dashboard, self).__init__() diff --git a/src/pybind/mgr/dashboard/controllers/docs.py b/src/pybind/mgr/dashboard/controllers/docs.py index b61bea997bbb9..3438c83999743 100644 --- a/src/pybind/mgr/dashboard/controllers/docs.py +++ b/src/pybind/mgr/dashboard/controllers/docs.py @@ -3,12 +3,11 @@ from __future__ import absolute_import import cherrypy -from . import Controller, BaseController, AuthRequired, Endpoint, ENDPOINT_MAP +from . import Controller, BaseController, Endpoint, ENDPOINT_MAP from .. import logger @Controller('/docs') -@AuthRequired() class Docs(BaseController): @classmethod diff --git a/src/pybind/mgr/dashboard/controllers/erasure_code_profile.py b/src/pybind/mgr/dashboard/controllers/erasure_code_profile.py index b5178ea9bbb14..9c9f0d3f591f2 100644 --- a/src/pybind/mgr/dashboard/controllers/erasure_code_profile.py +++ b/src/pybind/mgr/dashboard/controllers/erasure_code_profile.py @@ -3,7 +3,7 @@ from __future__ import absolute_import from cherrypy import NotFound -from . import ApiController, AuthRequired, RESTController +from . import ApiController, RESTController from ..services.ceph_service import CephService from .. import mgr @@ -16,7 +16,6 @@ def _serialize_ecp(name, ecp): @ApiController('/erasure_code_profile') -@AuthRequired() class ErasureCodeProfile(RESTController): """ create() supports additional key-value arguments that are passed to the diff --git a/src/pybind/mgr/dashboard/controllers/grafana.py b/src/pybind/mgr/dashboard/controllers/grafana.py index cffb6d0b97681..e7ae55f3a02d4 100644 --- a/src/pybind/mgr/dashboard/controllers/grafana.py +++ b/src/pybind/mgr/dashboard/controllers/grafana.py @@ -5,7 +5,7 @@ import cherrypy import requests from six.moves.urllib.parse import urlparse # pylint: disable=import-error -from . import ApiController, BaseController, AuthRequired, Proxy, Endpoint +from . import ApiController, BaseController, Proxy, Endpoint from .. import logger from ..settings import Settings @@ -102,7 +102,6 @@ class GrafanaRestClient(object): @ApiController('/grafana') -@AuthRequired() class Grafana(BaseController): @Endpoint() @@ -117,7 +116,6 @@ class Grafana(BaseController): @ApiController('/grafana/proxy') -@AuthRequired() class GrafanaProxy(BaseController): @Proxy() def __call__(self, path, **params): diff --git a/src/pybind/mgr/dashboard/controllers/host.py b/src/pybind/mgr/dashboard/controllers/host.py index ff08112afa1a7..76c2afea3b010 100644 --- a/src/pybind/mgr/dashboard/controllers/host.py +++ b/src/pybind/mgr/dashboard/controllers/host.py @@ -1,12 +1,11 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import -from . import ApiController, AuthRequired, RESTController +from . import ApiController, RESTController from .. import mgr @ApiController('/host') -@AuthRequired() class Host(RESTController): def list(self): return mgr.list_servers() diff --git a/src/pybind/mgr/dashboard/controllers/logging.py b/src/pybind/mgr/dashboard/controllers/logging.py index 33c0558f0016f..9c7d6de7ee2ea 100644 --- a/src/pybind/mgr/dashboard/controllers/logging.py +++ b/src/pybind/mgr/dashboard/controllers/logging.py @@ -2,7 +2,7 @@ from . import UiApiController, BaseController, Endpoint from .. import logger -@UiApiController('/logging') +@UiApiController('/logging', secure=False) class Logging(BaseController): @Endpoint('POST', path='js-error') diff --git a/src/pybind/mgr/dashboard/controllers/monitor.py b/src/pybind/mgr/dashboard/controllers/monitor.py index 12bba726b8676..be3a85fe24b95 100644 --- a/src/pybind/mgr/dashboard/controllers/monitor.py +++ b/src/pybind/mgr/dashboard/controllers/monitor.py @@ -3,12 +3,11 @@ from __future__ import absolute_import import json -from . import ApiController, AuthRequired, Endpoint, BaseController +from . import ApiController, Endpoint, BaseController from .. import mgr @ApiController('/monitor') -@AuthRequired() class Monitor(BaseController): @Endpoint() def __call__(self): diff --git a/src/pybind/mgr/dashboard/controllers/osd.py b/src/pybind/mgr/dashboard/controllers/osd.py index 77b275a0ccc42..0b462ef9c4008 100644 --- a/src/pybind/mgr/dashboard/controllers/osd.py +++ b/src/pybind/mgr/dashboard/controllers/osd.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import -from . import ApiController, AuthRequired, RESTController +from . import ApiController, RESTController from .. import mgr, logger from ..services.ceph_service import CephService from ..services.exception import handle_send_command_error @@ -9,7 +9,6 @@ from ..tools import str_to_bool @ApiController('/osd') -@AuthRequired() class Osd(RESTController): def list(self): osds = self.get_osd_map() diff --git a/src/pybind/mgr/dashboard/controllers/perf_counters.py b/src/pybind/mgr/dashboard/controllers/perf_counters.py index cced79f1883ac..68a82dc6a831b 100644 --- a/src/pybind/mgr/dashboard/controllers/perf_counters.py +++ b/src/pybind/mgr/dashboard/controllers/perf_counters.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import -from . import ApiController, AuthRequired, RESTController +from . import ApiController, RESTController from .. import mgr from ..services.ceph_service import CephService @@ -39,43 +39,36 @@ class PerfCounter(RESTController): @ApiController('perf_counters/mds') -@AuthRequired() class MdsPerfCounter(PerfCounter): service_type = 'mds' @ApiController('perf_counters/mon') -@AuthRequired() class MonPerfCounter(PerfCounter): service_type = 'mon' @ApiController('perf_counters/osd') -@AuthRequired() class OsdPerfCounter(PerfCounter): service_type = 'osd' @ApiController('perf_counters/rgw') -@AuthRequired() class RgwPerfCounter(PerfCounter): service_type = 'rgw' @ApiController('perf_counters/rbd-mirror') -@AuthRequired() class RbdMirrorPerfCounter(PerfCounter): service_type = 'rbd-mirror' @ApiController('perf_counters/mgr') -@AuthRequired() class MgrPerfCounter(PerfCounter): service_type = 'mgr' @ApiController('perf_counters') -@AuthRequired() class PerfCounters(RESTController): def list(self): return mgr.get_all_perf_counters() diff --git a/src/pybind/mgr/dashboard/controllers/pool.py b/src/pybind/mgr/dashboard/controllers/pool.py index ae61330923130..09f7c75d1ff83 100644 --- a/src/pybind/mgr/dashboard/controllers/pool.py +++ b/src/pybind/mgr/dashboard/controllers/pool.py @@ -3,7 +3,7 @@ from __future__ import absolute_import import cherrypy -from . import ApiController, RESTController, Endpoint, AuthRequired +from . import ApiController, RESTController, Endpoint from .. import mgr from ..services.ceph_service import CephService from ..services.exception import handle_send_command_error @@ -11,7 +11,6 @@ from ..tools import str_to_bool @ApiController('/pool') -@AuthRequired() class Pool(RESTController): @classmethod diff --git a/src/pybind/mgr/dashboard/controllers/rbd.py b/src/pybind/mgr/dashboard/controllers/rbd.py index 05409fd9d6d6d..3eca70a6ab105 100644 --- a/src/pybind/mgr/dashboard/controllers/rbd.py +++ b/src/pybind/mgr/dashboard/controllers/rbd.py @@ -11,7 +11,7 @@ import six import rbd -from . import ApiController, AuthRequired, RESTController, Task +from . import ApiController, RESTController, Task from .. import mgr from ..services.ceph_service import CephService from ..tools import ViewCache @@ -113,7 +113,6 @@ def _sort_features(features, enable=True): @ApiController('/block/image') -@AuthRequired() class Rbd(RESTController): RESOURCE_ID = "pool_name/image_name" @@ -375,7 +374,6 @@ class Rbd(RESTController): @ApiController('/block/image/:pool_name/:image_name/snap') -@AuthRequired() class RbdSnapshot(RESTController): RESOURCE_ID = "snapshot_name" diff --git a/src/pybind/mgr/dashboard/controllers/rbd_mirroring.py b/src/pybind/mgr/dashboard/controllers/rbd_mirroring.py index ceb299170ed23..a1823ed5e7d6a 100644 --- a/src/pybind/mgr/dashboard/controllers/rbd_mirroring.py +++ b/src/pybind/mgr/dashboard/controllers/rbd_mirroring.py @@ -8,7 +8,7 @@ from functools import partial import rbd -from . import ApiController, AuthRequired, Endpoint, BaseController +from . import ApiController, Endpoint, BaseController from .. import logger, mgr from ..services.ceph_service import CephService from ..tools import ViewCache @@ -155,7 +155,6 @@ def get_daemons_and_pools(): # pylint: disable=R0915 @ApiController('/rbdmirror') -@AuthRequired() class RbdMirror(BaseController): def __init__(self): diff --git a/src/pybind/mgr/dashboard/controllers/rgw.py b/src/pybind/mgr/dashboard/controllers/rgw.py index e1b551aafe64e..ee989a137fa2f 100644 --- a/src/pybind/mgr/dashboard/controllers/rgw.py +++ b/src/pybind/mgr/dashboard/controllers/rgw.py @@ -4,7 +4,7 @@ from __future__ import absolute_import import json import cherrypy -from . import ApiController, BaseController, RESTController, AuthRequired, Endpoint +from . import ApiController, BaseController, RESTController, Endpoint from .. import logger from ..services.ceph_service import CephService from ..services.rgw_client import RgwClient @@ -13,7 +13,6 @@ from ..exceptions import DashboardException @ApiController('/rgw') -@AuthRequired() class Rgw(BaseController): @Endpoint() @@ -37,7 +36,6 @@ class Rgw(BaseController): @ApiController('/rgw/daemon') -@AuthRequired() class RgwDaemon(RESTController): def list(self): @@ -97,7 +95,6 @@ class RgwRESTController(RESTController): @ApiController('/rgw/bucket') -@AuthRequired() class RgwBucket(RgwRESTController): def list(self): @@ -128,7 +125,6 @@ class RgwBucket(RgwRESTController): @ApiController('/rgw/user') -@AuthRequired() class RgwUser(RgwRESTController): def list(self): diff --git a/src/pybind/mgr/dashboard/controllers/summary.py b/src/pybind/mgr/dashboard/controllers/summary.py index d01ee1d1e33e9..59ff0f4015cf2 100644 --- a/src/pybind/mgr/dashboard/controllers/summary.py +++ b/src/pybind/mgr/dashboard/controllers/summary.py @@ -3,15 +3,15 @@ from __future__ import absolute_import import json + +from . import ApiController, Endpoint, BaseController from .. import mgr -from . import AuthRequired, ApiController, Endpoint, BaseController from ..controllers.rbd_mirroring import get_daemons_and_pools from ..tools import ViewCacheNoDataException from ..tools import TaskManager @ApiController('/summary') -@AuthRequired() class Summary(BaseController): def _health_status(self): health_data = mgr.get("health") diff --git a/src/pybind/mgr/dashboard/controllers/task.py b/src/pybind/mgr/dashboard/controllers/task.py index 537f34158f2b5..9380f07015ae7 100644 --- a/src/pybind/mgr/dashboard/controllers/task.py +++ b/src/pybind/mgr/dashboard/controllers/task.py @@ -1,12 +1,11 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import -from . import ApiController, AuthRequired, RESTController +from . import ApiController, RESTController from ..tools import TaskManager @ApiController('/task') -@AuthRequired() class Task(RESTController): def list(self, name=None): executing_t, finished_t = TaskManager.list_serializable(name) diff --git a/src/pybind/mgr/dashboard/controllers/tcmu_iscsi.py b/src/pybind/mgr/dashboard/controllers/tcmu_iscsi.py index 89e7c8ed890a0..4043b0deeb347 100644 --- a/src/pybind/mgr/dashboard/controllers/tcmu_iscsi.py +++ b/src/pybind/mgr/dashboard/controllers/tcmu_iscsi.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import -from . import ApiController, AuthRequired, RESTController +from . import ApiController, RESTController from .. import mgr from ..services.ceph_service import CephService @@ -9,7 +9,6 @@ SERVICE_TYPE = 'tcmu-runner' @ApiController('/tcmuiscsi') -@AuthRequired() class TcmuIscsi(RESTController): # pylint: disable=too-many-nested-blocks def list(self): # pylint: disable=unused-argument diff --git a/src/pybind/mgr/dashboard/tests/test_controllers.py b/src/pybind/mgr/dashboard/tests/test_controllers.py index 8981d3b611a84..333f7a3774290 100644 --- a/src/pybind/mgr/dashboard/tests/test_controllers.py +++ b/src/pybind/mgr/dashboard/tests/test_controllers.py @@ -6,7 +6,7 @@ from ..controllers import BaseController, RESTController, Controller, \ ApiController, Endpoint -@Controller("/btest/{key}", base_url="/ui") +@Controller("/btest/{key}", base_url="/ui", secure=False) class BTest(BaseController): @Endpoint() def test1(self, key, opt=1): @@ -38,7 +38,7 @@ class BTest(BaseController): return {'key': key, 'opt': opt} -@ApiController("/rtest/{key}") +@ApiController("/rtest/{key}", secure=False) class RTest(RESTController): RESOURCE_ID = 'skey/ekey' @@ -72,7 +72,7 @@ class RTest(RESTController): return {'key': key, 'skey': skey, 'ekey': ekey, 'opt': opt} -@Controller("/") +@Controller("/", secure=False) class Root(BaseController): @Endpoint(json_response=False) def __call__(self): diff --git a/src/pybind/mgr/dashboard/tests/test_exceptions.py b/src/pybind/mgr/dashboard/tests/test_exceptions.py index 8998cd38d81c1..a6c38d84ef049 100644 --- a/src/pybind/mgr/dashboard/tests/test_exceptions.py +++ b/src/pybind/mgr/dashboard/tests/test_exceptions.py @@ -13,7 +13,7 @@ from ..tools import ViewCache, TaskManager, NotificationQueue # pylint: disable=W0613 -@Controller('foo') +@Controller('foo', secure=False) class FooResource(RESTController): @Endpoint() diff --git a/src/pybind/mgr/dashboard/tests/test_grafana.py b/src/pybind/mgr/dashboard/tests/test_grafana.py index 975fcb62d4bc6..f88cb72635808 100644 --- a/src/pybind/mgr/dashboard/tests/test_grafana.py +++ b/src/pybind/mgr/dashboard/tests/test_grafana.py @@ -25,7 +25,7 @@ class Grafana(TestCase): url='//localhost:3000', username='admin', password='admin') -@Controller('grafana/mocked') +@Controller('/grafana/mocked', secure=False) class GrafanaMockInstance(BaseController): @Proxy() def __call__(self, path, **params): diff --git a/src/pybind/mgr/dashboard/tests/test_rest_tasks.py b/src/pybind/mgr/dashboard/tests/test_rest_tasks.py index ea7bba23171de..6e8f01b40b773 100644 --- a/src/pybind/mgr/dashboard/tests/test_rest_tasks.py +++ b/src/pybind/mgr/dashboard/tests/test_rest_tasks.py @@ -9,7 +9,7 @@ from ..controllers.task import Task as TaskController from ..tools import NotificationQueue, TaskManager -@Controller('test/task') +@Controller('/test/task', secure=False) class TaskTest(RESTController): sleep_time = 0.0 diff --git a/src/pybind/mgr/dashboard/tests/test_tools.py b/src/pybind/mgr/dashboard/tests/test_tools.py index aaadd1e8af53a..bd27822931e62 100644 --- a/src/pybind/mgr/dashboard/tests/test_tools.py +++ b/src/pybind/mgr/dashboard/tests/test_tools.py @@ -15,7 +15,7 @@ from ..tools import is_valid_ipv6_address, dict_contains_path # pylint: disable=W0613 -@Controller('/foo') +@Controller('/foo', secure=False) class FooResource(RESTController): elems = [] @@ -40,20 +40,20 @@ class FooResource(RESTController): return dict(key=key, newdata=newdata) -@Controller('/foo/:key/:method') +@Controller('/foo/:key/:method', secure=False) class FooResourceDetail(RESTController): def list(self, key, method): return {'detail': (key, [method])} -@ApiController('/rgw/proxy') +@ApiController('/rgw/proxy', secure=False) class GenerateControllerRoutesController(BaseController): @Proxy() def __call__(self, path, **params): pass -@ApiController('/fooargs') +@ApiController('/fooargs', secure=False) class FooArgs(RESTController): def set(self, code, name=None, opt1=None, opt2=None): return {'code': code, 'name': name, 'opt1': opt1, 'opt2': opt2} -- 2.39.5