diff --git a/cylc/flow/cfgspec/globalcfg.py b/cylc/flow/cfgspec/globalcfg.py index 01b21bf915e..74fde0e4002 100644 --- a/cylc/flow/cfgspec/globalcfg.py +++ b/cylc/flow/cfgspec/globalcfg.py @@ -21,7 +21,6 @@ from cylc.flow import LOG from cylc.flow import __version__ as CYLC_VERSION from cylc.flow.hostuserutil import get_user_home -from cylc.flow.network.authorisation import Priv from cylc.flow.parsec.config import ParsecConfig, ConfigNode as Conf from cylc.flow.parsec.exceptions import ParsecError from cylc.flow.parsec.upgrade import upgrader @@ -597,37 +596,6 @@ host if you have to use the *hardwired* self-identification method. ''') - # suite - with Conf('authentication', desc=''' - Authentication of client programs with suite server programs can be - configured here, and overridden in suites if necessary with - :cylc:conf:`flow.cylc[cylc][authentication]`. - - The suite-specific passphrase must be installed on a user's account to - authorize full control privileges (see - :ref:`ConnectionAuthentication`). In the future we plan to move to a - more traditional user account model so that each authorized user can - have their own password. - '''): - # Allow owners to grant public shutdown rights at the most, not full - # control. - Conf( - 'public', - VDR.V_STRING, - default=Priv.STATE_TOTALS.name.lower().replace('_', '-'), - options=[ - level.name.lower().replace('_', '-') - for level in [ - Priv.IDENTITY, Priv.DESCRIPTION, - Priv.STATE_TOTALS, Priv.READ, Priv.SHUTDOWN - ] - ], - desc=''' - This sets the client privilege level for public access - i.e. - no suite passphrase required. - ''' - ) - # suite with Conf('suite servers', desc=''' Configure allowed suite hosts and ports for starting up (running or diff --git a/cylc/flow/cfgspec/suite.py b/cylc/flow/cfgspec/suite.py index a8ada794f9a..2ec28986bde 100644 --- a/cylc/flow/cfgspec/suite.py +++ b/cylc/flow/cfgspec/suite.py @@ -21,7 +21,6 @@ from cylc.flow import LOG from cylc.flow.parsec.exceptions import UpgradeError -from cylc.flow.network.authorisation import Priv from cylc.flow.parsec.config import ParsecConfig, ConfigNode as Conf from cylc.flow.parsec.OrderedDict import OrderedDictWithDefaults from cylc.flow.parsec.upgrade import upgrader @@ -270,22 +269,6 @@ with Conf('reference test'): Conf('expected task failures', VDR.V_STRING_LIST) - with Conf('authentication'): - # Allow owners to grant public shutdown rights at the most, not - # full control. - Conf( - 'public', - VDR.V_STRING, - default=Priv.STATE_TOTALS.name.lower().replace('_', '-'), - options=[ - level.name.lower().replace('_', '-') - for level in [ - Priv.IDENTITY, Priv.DESCRIPTION, - Priv.STATE_TOTALS, Priv.READ, Priv.SHUTDOWN - ] - ] - ) - with Conf('scheduling', desc=''' This section allows cylc to determine when tasks are ready to run. '''): @@ -1306,6 +1289,7 @@ def upg(cfg, descr): u.obsolete('7.8.1', ['cylc', 'events', 'reset timer']) u.obsolete('7.8.1', ['cylc', 'events', 'reset inactivity timer']) u.obsolete('7.8.1', ['runtime', '__MANY__', 'events', 'reset timer']) + u.obsolete('8.0.0', ['cylc', 'authentication']) u.obsolete('8.0.0', ['cylc', 'log resolved dependencies']) u.obsolete('8.0.0', ['cylc', 'reference test', 'allow task failures']) u.obsolete('8.0.0', ['cylc', 'reference test', 'live mode suite timeout']) diff --git a/cylc/flow/network/authorisation.py b/cylc/flow/network/authorisation.py index 61888b533d5..7369eb8e2ba 100644 --- a/cylc/flow/network/authorisation.py +++ b/cylc/flow/network/authorisation.py @@ -15,60 +15,17 @@ # along with this program. If not, see . """Network authorisation layer.""" -from enum import IntEnum from functools import wraps from cylc.flow import LOG -class Priv(IntEnum): - """Cylc privilege levels. - - In Cylc configurations use the lower-case form of each privilege level - e.g. ``control`` for ``Priv.CONTROL``. - - These levels are ordered (by the integer associated with each) from 0. - Each privilege level grants access to the levels below it. - - """ - - CONTROL = 6 - """Provides full control of a suite.""" - - SHUTDOWN = 5 # (Not used yet - for the post-passphrase era.) - """Allows issuing of the shutdown command.""" - - READ = 4 - """Permits read access to the suite's state.""" - - STATE_TOTALS = 3 - """Provides access to the count of tasks in each state.""" - - DESCRIPTION = 2 - """Permits reading of suite metadata.""" - - IDENTITY = 1 - """Provides read access to the suite name, owner and Cylc version.""" - - NONE = 0 - """No access.""" - - @classmethod - def parse(cls, key): - """Obtain a privilege enumeration from a string.""" - return cls.__members__[key.upper().replace('-', '_')] - - -def authorise(req_priv_level): +def authorise(): """Add authorisation to an endpoint. This decorator extracts the `user` field from the incoming message to determine the client's privilege level. - Args: - req_priv_level (cylc.flow.network.Priv): A privilege level for the - method. - Wrapped function args: user The authenticated user (determined server side) @@ -86,20 +43,11 @@ def _authorise(self, *args, user='?', meta=None, **kwargs): host = meta.get('host', '?') prog = meta.get('prog', '?') - usr_priv_level = self._get_priv_level(user) - if usr_priv_level < req_priv_level: - LOG.warn( - "[client-connect] DENIED (privilege '%s' < '%s') %s@%s:%s", - usr_priv_level, req_priv_level, user, host, prog) - raise Exception('Authorisation failure') + # Hardcoded, for new - but much of this functionality can be + # removed more swingingly. LOG.info( '[client-command] %s %s@%s:%s', fcn.__name__, user, host, prog) return fcn(self, *args, **kwargs) - # add authorisation level to docstring - _authorise.__doc__ += ( - f'Authentication:\n{" " * 12}' - f':py:obj:`{__loader__.name}.{str(req_priv_level)}`\n' - ) return _authorise return wrapper diff --git a/cylc/flow/network/server.py b/cylc/flow/network/server.py index 0c4235e1b91..e446bd4a51a 100644 --- a/cylc/flow/network/server.py +++ b/cylc/flow/network/server.py @@ -15,7 +15,7 @@ # along with this program. If not, see . """Server for suite runtime API.""" -import getpass +import getpass # noqa: F401 from queue import Queue from textwrap import dedent from time import sleep @@ -24,9 +24,8 @@ import zmq from cylc.flow import LOG -from cylc.flow.cfgspec.glbl_cfg import glbl_cfg from cylc.flow.network import encode_, decode_, ZMQSocketBase -from cylc.flow.network.authorisation import Priv, authorise +from cylc.flow.network.authorisation import authorise from cylc.flow.network.graphql import ( CylcGraphQLBackend, IgnoreFieldMiddleware, instantiate_middleware ) @@ -254,30 +253,13 @@ def _receiver(self, message): return {'data': response} - def _get_public_priv(self): - """Return the public privilege level of this suite.""" - if self.schd.config.cfg['cylc']['authentication']['public']: - return Priv.parse( - self.schd.config.cfg['cylc']['authentication']['public']) - return Priv.parse(glbl_cfg().get(['authentication', 'public'])) - - def _get_priv_level(self, user): - """Return the privilege level for the given user for this suite.""" - if user == getpass.getuser(): - return Priv.CONTROL - if self.public_priv is None: - # cannot do this on initialisation as the suite configuration has - # not yet been parsed - self.public_priv = self._get_public_priv() - return self.public_priv - def register_endpoints(self): """Register all exposed methods.""" self.endpoints = {name: obj for name, obj in self.__class__.__dict__.items() if hasattr(obj, 'exposed')} - @authorise(Priv.IDENTITY) + @authorise() @expose def api(self, endpoint=None): """Return information about this API. @@ -310,7 +292,7 @@ def api(self, endpoint=None): return '%s\n%s' % (head, tail) return 'No method by name "%s"' % endpoint - @authorise(Priv.READ) + @authorise() @expose def graphql(self, request_string=None, variables=None): """Return the GraphQL scheme execution result. @@ -353,7 +335,7 @@ def graphql(self, request_string=None, variables=None): return errors return executed.data - @authorise(Priv.READ) + @authorise() @expose def get_graph_raw(self, start_point_string, stop_point_string, group_nodes=None, ungroup_nodes=None, @@ -418,7 +400,7 @@ def get_graph_raw(self, start_point_string, stop_point_string, ungroup_all=ungroup_all) # UIServer Data Commands - @authorise(Priv.READ) + @authorise() @expose def pb_entire_workflow(self): """Send the entire data-store in a single Protobuf message. @@ -431,7 +413,7 @@ def pb_entire_workflow(self): pb_msg = self.schd.data_store_mgr.get_entire_workflow() return pb_msg.SerializeToString() - @authorise(Priv.READ) + @authorise() @expose def pb_data_elements(self, element_type): """Send the specified data elements in delta form. diff --git a/tests/functional/deprecations/01-cylc8-basic.t b/tests/functional/deprecations/01-cylc8-basic.t index 0e75c56b26c..aab50a722f8 100755 --- a/tests/functional/deprecations/01-cylc8-basic.t +++ b/tests/functional/deprecations/01-cylc8-basic.t @@ -29,6 +29,7 @@ TEST_NAME=${TEST_NAME_BASE}-cmp cylc validate -v "${SUITE_NAME}" 2>&1 \ | sed -n -e 's/^WARNING - \( \* (.*$\)/\1/p' > 'val.out' cmp_ok val.out <<__END__ + * (8.0.0) [cylc][authentication] - DELETED (OBSOLETE) * (8.0.0) [cylc][log resolved dependencies] - DELETED (OBSOLETE) * (8.0.0) [cylc][reference test][allow task failures] - DELETED (OBSOLETE) * (8.0.0) [cylc][reference test][live mode suite timeout] - DELETED (OBSOLETE) diff --git a/tests/functional/deprecations/01-cylc8-basic/flow.cylc b/tests/functional/deprecations/01-cylc8-basic/flow.cylc index e941ff78ce1..fa4c8e1dcac 100644 --- a/tests/functional/deprecations/01-cylc8-basic/flow.cylc +++ b/tests/functional/deprecations/01-cylc8-basic/flow.cylc @@ -4,6 +4,7 @@ [cylc] log resolved dependencies = abort if any task fails = + authentication = [[reference test]] allow task failures = live mode suite timeout =