def start_manhole(self, config, details=None): """ Start a Manhole service within this process. **Usage:** This procedure is registered under * ``crossbar.node.<node_id>.worker.<worker_id>.start_manhole`` - for native workers * ``crossbar.node.<node_id>.controller.start_manhole`` - for node controllers The procedure takes a Manhole service configuration which defines a listening endpoint for the service and a list of users including passwords, e.g. .. code-block:: javascript { "endpoint": { "type": "tcp", "port": 6022 }, "users": [ { "user": "******", "password": "******" } ] } **Errors:** The procedure may raise the following errors: * ``crossbar.error.invalid_configuration`` - the provided configuration is invalid * ``crossbar.error.already_started`` - the Manhole service is already running (or starting) * ``crossbar.error.feature_unavailable`` - the required support packages are not installed **Events:** The procedure will publish an event when the service **is starting** to * ``crossbar.node.<node_id>.worker.<worker_id>.on_manhole_starting`` - for native workers * ``crossbar.node.<node_id>.controller.on_manhole_starting`` - for node controllers and publish an event when the service **has started** to * ``crossbar.node.<node_id>.worker.<worker_id>.on_manhole_started`` - for native workers * ``crossbar.node.<node_id>.controller.on_manhole_started`` - for node controllers :param config: Manhole service configuration. :type config: dict """ self.log.debug("{cls}.start_manhole(config = {config})", cls=self.__class__.__name__, config=config) if not _HAS_MANHOLE: emsg = "Could not start manhole: required packages are missing ({})".format( _MANHOLE_MISSING_REASON) self.log.error(emsg) raise ApplicationError(u"crossbar.error.feature_unavailable", emsg) if self._manhole_service: emsg = "Could not start manhole - already running (or starting)" self.log.warn(emsg) raise ApplicationError(u"crossbar.error.already_started", emsg) try: checkconfig.check_manhole(config) except Exception as e: emsg = "Could not start manhole: invalid configuration ({})".format( e) self.log.error(emsg) raise ApplicationError(u'crossbar.error.invalid_configuration', emsg) # setup user authentication # checker = checkers.InMemoryUsernamePasswordDatabaseDontUse() for user in config['users']: checker.addUser(user['user'], user['password']) # setup manhole namespace # namespace = {'session': self} from twisted.conch.manhole_ssh import (ConchFactory, TerminalRealm, TerminalSession) from twisted.conch.manhole import ColoredManhole class PatchedTerminalSession(TerminalSession): # get rid of # exceptions.AttributeError: TerminalSession instance has no attribute 'windowChanged' def windowChanged(self, winSize): pass rlm = TerminalRealm() rlm.sessionFactory = PatchedTerminalSession # monkey patch rlm.chainedProtocolFactory.protocolFactory = lambda _: ColoredManhole( namespace) ptl = portal.Portal(rlm, [checker]) factory = ConchFactory(ptl) factory.noisy = False self._manhole_service = ManholeService(config, details.caller) starting_topic = '{}.on_manhole_starting'.format(self._uri_prefix) starting_info = self._manhole_service.marshal() # the caller gets a progressive result .. if details.progress: details.progress(starting_info) # .. while all others get an event self.publish(starting_topic, starting_info, options=PublishOptions(exclude=details.caller)) try: self._manhole_service.port = yield create_listening_port_from_config( config['endpoint'], self.cbdir, factory, self._reactor, self.log) except Exception as e: self._manhole_service = None emsg = "Manhole service endpoint cannot listen: {}".format(e) self.log.error(emsg) raise ApplicationError(u"crossbar.error.cannot_listen", emsg) # alright, manhole has started self._manhole_service.started = datetime.utcnow() self._manhole_service.status = 'started' started_topic = '{}.on_manhole_started'.format(self._uri_prefix) started_info = self._manhole_service.marshal() self.publish(started_topic, started_info, options=PublishOptions(exclude=details.caller)) returnValue(started_info)
def start_manhole(self, config, details=None): """ Start a Manhole service within this process. **Usage:** This procedure is registered under * ``crossbar.node.<node_id>.worker.<worker_id>.start_manhole`` - for native workers * ``crossbar.node.<node_id>.controller.start_manhole`` - for node controllers The procedure takes a Manhole service configuration which defines a listening endpoint for the service and a list of users including passwords, e.g. .. code-block:: javascript { "endpoint": { "type": "tcp", "port": 6022 }, "users": [ { "user": "******", "password": "******" } ] } **Errors:** The procedure may raise the following errors: * ``crossbar.error.invalid_configuration`` - the provided configuration is invalid * ``crossbar.error.already_started`` - the Manhole service is already running (or starting) * ``crossbar.error.feature_unavailable`` - the required support packages are not installed **Events:** The procedure will publish an event when the service **is starting** to * ``crossbar.node.<node_id>.worker.<worker_id>.on_manhole_starting`` - for native workers * ``crossbar.node.<node_id>.controller.on_manhole_starting`` - for node controllers and publish an event when the service **has started** to * ``crossbar.node.<node_id>.worker.<worker_id>.on_manhole_started`` - for native workers * ``crossbar.node.<node_id>.controller.on_manhole_started`` - for node controllers :param config: Manhole service configuration. :type config: dict """ self.log.debug("{cls}.start_manhole(config = {config})", cls=self.__class__.__name__, config=config) if not _HAS_MANHOLE: emsg = "Could not start manhole: required packages are missing ({})".format(_MANHOLE_MISSING_REASON) self.log.error(emsg) raise ApplicationError(u"crossbar.error.feature_unavailable", emsg) if self._manhole_service: emsg = "Could not start manhole - already running (or starting)" self.log.warn(emsg) raise ApplicationError(u"crossbar.error.already_started", emsg) try: checkconfig.check_manhole(config) except Exception as e: emsg = "Could not start manhole: invalid configuration ({})".format(e) self.log.error(emsg) raise ApplicationError(u'crossbar.error.invalid_configuration', emsg) # setup user authentication # checker = checkers.InMemoryUsernamePasswordDatabaseDontUse() for user in config['users']: checker.addUser(user['user'], user['password']) # setup manhole namespace # namespace = {'session': self} class PatchedTerminalSession(TerminalSession): # get rid of # exceptions.AttributeError: TerminalSession instance has no attribute 'windowChanged' def windowChanged(self, winSize): pass rlm = TerminalRealm() rlm.sessionFactory = PatchedTerminalSession # monkey patch rlm.chainedProtocolFactory.protocolFactory = lambda _: ColoredManhole(namespace) ptl = portal.Portal(rlm, [checker]) factory = ConchFactory(ptl) factory.noisy = False self._manhole_service = ManholeService(config, details.caller) starting_topic = '{}.on_manhole_starting'.format(self._uri_prefix) starting_info = self._manhole_service.marshal() # the caller gets a progressive result .. if details.progress: details.progress(starting_info) # .. while all others get an event self.publish(starting_topic, starting_info, options=PublishOptions(exclude=details.caller)) try: self._manhole_service.port = yield create_listening_port_from_config(config['endpoint'], self.cbdir, factory, self._reactor, self.log) except Exception as e: self._manhole_service = None emsg = "Manhole service endpoint cannot listen: {}".format(e) self.log.error(emsg) raise ApplicationError(u"crossbar.error.cannot_listen", emsg) # alright, manhole has started self._manhole_service.started = datetime.utcnow() self._manhole_service.status = 'started' started_topic = '{}.on_manhole_started'.format(self._uri_prefix) started_info = self._manhole_service.marshal() self.publish(started_topic, started_info, options=PublishOptions(exclude=details.caller)) returnValue(started_info)
def start_manhole(self, config, details=None): """ Start a Manhole service within this process. **Usage:** This procedure is registered under * ``crossbar.node.<node_id>.worker.<worker_id>.start_manhole`` - for native workers * ``crossbar.node.<node_id>.controller.start_manhole`` - for node controllers The procedure takes a Manhole service configuration which defines a listening endpoint for the service and a list of users including passwords, e.g. .. code-block:: javascript { "endpoint": { "type": "tcp", "port": 6022 }, "users": [ { "user": "******", "password": "******" } ] } **Errors:** The procedure may raise the following errors: * ``crossbar.error.invalid_configuration`` - the provided configuration is invalid * ``crossbar.error.already_started`` - the Manhole service is already running (or starting) * ``crossbar.error.feature_unavailable`` - the required support packages are not installed **Events:** The procedure will publish an event when the service **is starting** to * ``crossbar.node.<node_id>.worker.<worker_id>.on_manhole_starting`` - for native workers * ``crossbar.node.<node_id>.controller.on_manhole_starting`` - for node controllers and publish an event when the service **has started** to * ``crossbar.node.<node_id>.worker.<worker_id>.on_manhole_started`` - for native workers * ``crossbar.node.<node_id>.controller.on_manhole_started`` - for node controllers :param config: Manhole service configuration. :type config: dict """ self.log.debug("{cls}.start_manhole(config = {config})", cls=self.__class__.__name__, config=config) if not _HAS_MANHOLE: emsg = "Could not start manhole: required packages are missing ({})".format( _MANHOLE_MISSING_REASON) self.log.error(emsg) raise ApplicationError(u"crossbar.error.feature_unavailable", emsg) if self._manhole_service: emsg = "Could not start manhole - already running (or starting)" self.log.warn(emsg) raise ApplicationError(u"crossbar.error.already_started", emsg) try: self.personality.check_manhole(self.personality, config) except Exception as e: emsg = "Could not start manhole: invalid configuration ({})".format( e) self.log.error(emsg) raise ApplicationError(u'crossbar.error.invalid_configuration', emsg) from twisted.conch.ssh import keys from twisted.conch.manhole_ssh import (ConchFactory, TerminalRealm, TerminalSession) from twisted.conch.manhole import ColoredManhole from twisted.conch.checkers import SSHPublicKeyDatabase class PublicKeyChecker(SSHPublicKeyDatabase): def __init__(self, userKeys): self.userKeys = {} for username, keyData in userKeys.items(): self.userKeys[username] = keys.Key.fromString( data=keyData).blob() def checkKey(self, credentials): username = credentials.username.decode('utf8') if username in self.userKeys: keyBlob = self.userKeys[username] return keyBlob == credentials.blob # setup user authentication # authorized_keys = { 'oberstet': 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCz7K1QwDhaq/Bi8o0uqiJQuVFCDQL5rbRvMClLHRx9KE3xP2Fh2eapzXuYGSgtG9Fyz1UQd+1oNM3wuNnT/DsBUBQrECP4bpFIHcJkMaFTARlCagkXosWsadzNnkW0osUCuHYMrzBJuXWF2GH+0OFCtVu+8E+4Mhvchu9xsHG8PM92SpI6aP0TtmT9D/0Bsm9JniRj8kndeS+iWG4s/pEGj7Rg7eGnbyQJt/9Jc1nWl6PngGbwp63dMVmh+8LP49PtfnxY8m9fdwpL4oW9U8beYqm8hyfBPN2yDXaehg6RILjIa7LU2/6bu96ZgnIz26zi/X9XlnJQt2aahWJs1+GR oberstet@thinkpad-t430s' } checker = PublicKeyChecker(authorized_keys) # setup manhole namespace # namespace = {'session': self} class PatchedTerminalSession(TerminalSession): # get rid of # exceptions.AttributeError: TerminalSession instance has no attribute 'windowChanged' def windowChanged(self, winSize): pass rlm = TerminalRealm() rlm.sessionFactory = PatchedTerminalSession # monkey patch rlm.chainedProtocolFactory.protocolFactory = lambda _: ColoredManhole( namespace) ptl = portal.Portal(rlm) ptl.registerChecker(checker) factory = ConchFactory(ptl) factory.noisy = False private_key = keys.Key.fromFile( os.path.join(self.cbdir, 'ssh_host_rsa_key')) public_key = private_key.public() publicKeys = {b'ssh-rsa': public_key} privateKeys = {b'ssh-rsa': private_key} factory.publicKeys = publicKeys factory.privateKeys = privateKeys self._manhole_service = ManholeService(config, details.caller) starting_topic = '{}.on_manhole_starting'.format(self._uri_prefix) starting_info = self._manhole_service.marshal() # the caller gets a progressive result .. if details.progress: details.progress(starting_info) # .. while all others get an event self.publish(starting_topic, starting_info, options=PublishOptions(exclude=details.caller)) try: self._manhole_service.port = yield create_listening_port_from_config( config['endpoint'], self.cbdir, factory, self._reactor, self.log) except Exception as e: self._manhole_service = None emsg = "Manhole service endpoint cannot listen: {}".format(e) self.log.error(emsg) raise ApplicationError(u"crossbar.error.cannot_listen", emsg) # alright, manhole has started self._manhole_service.started = datetime.utcnow() self._manhole_service.status = 'started' started_topic = '{}.on_manhole_started'.format(self._uri_prefix) started_info = self._manhole_service.marshal() self.publish(started_topic, started_info, options=PublishOptions(exclude=details.caller)) returnValue(started_info)
def start_manhole(self, config, details=None): """ Start a Manhole service within this process. **Usage:** This procedure is registered under * ``crossbar.node.<node_id>.worker.<worker_id>.start_manhole`` - for native workers * ``crossbar.node.<node_id>.controller.start_manhole`` - for node controllers The procedure takes a Manhole service configuration which defines a listening endpoint for the service and a list of users including passwords, e.g. .. code-block:: javascript { "endpoint": { "type": "tcp", "port": 6022 }, "users": [ { "user": "******", "password": "******" } ] } **Errors:** The procedure may raise the following errors: * ``crossbar.error.invalid_configuration`` - the provided configuration is invalid * ``crossbar.error.already_started`` - the Manhole service is already running (or starting) * ``crossbar.error.feature_unavailable`` - the required support packages are not installed **Events:** The procedure will publish an event when the service **is starting** to * ``crossbar.node.<node_id>.worker.<worker_id>.on_manhole_starting`` - for native workers * ``crossbar.node.<node_id>.controller.on_manhole_starting`` - for node controllers and publish an event when the service **has started** to * ``crossbar.node.<node_id>.worker.<worker_id>.on_manhole_started`` - for native workers * ``crossbar.node.<node_id>.controller.on_manhole_started`` - for node controllers :param config: Manhole service configuration. :type config: dict """ self.log.debug("{cls}.start_manhole(config = {config})", cls=self.__class__.__name__, config=config) if not _HAS_MANHOLE: emsg = "Could not start manhole: required packages are missing ({})".format(_MANHOLE_MISSING_REASON) self.log.error(emsg) raise ApplicationError(u"crossbar.error.feature_unavailable", emsg) if self._manhole_service: emsg = "Could not start manhole - already running (or starting)" self.log.warn(emsg) raise ApplicationError(u"crossbar.error.already_started", emsg) try: self.personality.check_manhole(self.personality, config) except Exception as e: emsg = "Could not start manhole: invalid configuration ({})".format(e) self.log.error(emsg) raise ApplicationError(u'crossbar.error.invalid_configuration', emsg) from twisted.conch.ssh import keys from twisted.conch.manhole_ssh import ( ConchFactory, TerminalRealm, TerminalSession) from twisted.conch.manhole import ColoredManhole from twisted.conch.checkers import SSHPublicKeyDatabase class PublicKeyChecker(SSHPublicKeyDatabase): def __init__(self, userKeys): self.userKeys = {} for username, keyData in userKeys.items(): self.userKeys[username] = keys.Key.fromString(data=keyData).blob() def checkKey(self, credentials): username = credentials.username.decode('utf8') if username in self.userKeys: keyBlob = self.userKeys[username] return keyBlob == credentials.blob # setup user authentication # authorized_keys = { 'oberstet': 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCz7K1QwDhaq/Bi8o0uqiJQuVFCDQL5rbRvMClLHRx9KE3xP2Fh2eapzXuYGSgtG9Fyz1UQd+1oNM3wuNnT/DsBUBQrECP4bpFIHcJkMaFTARlCagkXosWsadzNnkW0osUCuHYMrzBJuXWF2GH+0OFCtVu+8E+4Mhvchu9xsHG8PM92SpI6aP0TtmT9D/0Bsm9JniRj8kndeS+iWG4s/pEGj7Rg7eGnbyQJt/9Jc1nWl6PngGbwp63dMVmh+8LP49PtfnxY8m9fdwpL4oW9U8beYqm8hyfBPN2yDXaehg6RILjIa7LU2/6bu96ZgnIz26zi/X9XlnJQt2aahWJs1+GR oberstet@thinkpad-t430s' } checker = PublicKeyChecker(authorized_keys) # setup manhole namespace # namespace = {'session': self} class PatchedTerminalSession(TerminalSession): # get rid of # exceptions.AttributeError: TerminalSession instance has no attribute 'windowChanged' def windowChanged(self, winSize): pass rlm = TerminalRealm() rlm.sessionFactory = PatchedTerminalSession # monkey patch rlm.chainedProtocolFactory.protocolFactory = lambda _: ColoredManhole(namespace) ptl = portal.Portal(rlm) ptl.registerChecker(checker) factory = ConchFactory(ptl) factory.noisy = False private_key = keys.Key.fromFile(os.path.join(self.cbdir, 'ssh_host_rsa_key')) public_key = private_key.public() publicKeys = { b'ssh-rsa': public_key } privateKeys = { b'ssh-rsa': private_key } factory.publicKeys = publicKeys factory.privateKeys = privateKeys self._manhole_service = ManholeService(config, details.caller) starting_topic = '{}.on_manhole_starting'.format(self._uri_prefix) starting_info = self._manhole_service.marshal() # the caller gets a progressive result .. if details.progress: details.progress(starting_info) # .. while all others get an event self.publish(starting_topic, starting_info, options=PublishOptions(exclude=details.caller)) try: self._manhole_service.port = yield create_listening_port_from_config(config['endpoint'], self.cbdir, factory, self._reactor, self.log) except Exception as e: self._manhole_service = None emsg = "Manhole service endpoint cannot listen: {}".format(e) self.log.error(emsg) raise ApplicationError(u"crossbar.error.cannot_listen", emsg) # alright, manhole has started self._manhole_service.started = datetime.utcnow() self._manhole_service.status = 'started' started_topic = '{}.on_manhole_started'.format(self._uri_prefix) started_info = self._manhole_service.marshal() self.publish(started_topic, started_info, options=PublishOptions(exclude=details.caller)) returnValue(started_info)
def start_manhole(self, config, details=None): """ Start a manhole (SSH) within this worker. :param config: Manhole configuration. :type config: obj """ if self.debug: log.msg("{}.start_manhole".format(self.__class__.__name__), config) if not _HAS_MANHOLE: emsg = "ERROR: could not start manhole - required packages are missing ({})".format( _MANHOLE_MISSING_REASON) log.msg(emsg) raise ApplicationError("crossbar.error.feature_unavailable", emsg) if self._manhole_service: emsg = "ERROR: could not start manhole - already running (or starting)" log.msg(emsg) raise ApplicationError("crossbar.error.already_started", emsg) try: checkconfig.check_manhole(config) except Exception as e: emsg = "ERROR: could not start manhole - invalid configuration ({})".format( e) log.msg(emsg) raise ApplicationError('crossbar.error.invalid_configuration', emsg) # setup user authentication # checker = checkers.InMemoryUsernamePasswordDatabaseDontUse() for user in config['users']: checker.addUser(user['user'], user['password']) # setup manhole namespace # namespace = {'session': self} class PatchedTerminalSession(TerminalSession): # get rid of # exceptions.AttributeError: TerminalSession instance has no attribute 'windowChanged' def windowChanged(self, winSize): pass rlm = TerminalRealm() rlm.sessionFactory = PatchedTerminalSession # monkey patch rlm.chainedProtocolFactory.protocolFactory = lambda _: ColoredManhole( namespace) ptl = portal.Portal(rlm, [checker]) factory = ConchFactory(ptl) factory.noisy = False self._manhole_service = ManholeService(config, details.caller) starting_topic = '{}.on_manhole_starting'.format(self._uri_prefix) starting_info = self._manhole_service.marshal() # the caller gets a progressive result .. if details.progress: details.progress(starting_info) # .. while all others get an event self.publish(starting_topic, starting_info, options=PublishOptions(exclude=[details.caller])) try: self._manhole_service.port = yield create_listening_port_from_config( config['endpoint'], factory, self.cbdir, reactor) except Exception as e: self._manhole_service = None emsg = "ERROR: manhole service endpoint cannot listen - {}".format( e) log.msg(emsg) raise ApplicationError("crossbar.error.cannot_listen", emsg) # alright, manhole has started self._manhole_service.started = datetime.utcnow() self._manhole_service.status = 'started' started_topic = '{}.on_manhole_started'.format(self._uri_prefix) started_info = self._manhole_service.marshal() self.publish(started_topic, started_info, options=PublishOptions(exclude=[details.caller])) returnValue(started_info)
def start_manhole(self, config, details = None): """ Start a manhole (SSH) within this worker. :param config: Manhole configuration. :type config: obj """ if self.debug: log.msg("{}.start_manhole".format(self.__class__.__name__), config) if not _HAS_MANHOLE: emsg = "ERROR: could not start manhole - required packages are missing ({})".format(_MANHOLE_MISSING_REASON) log.msg(emsg) raise ApplicationError("crossbar.error.feature_unavailable", emsg) if self._manhole_service: emsg = "ERROR: could not start manhole - already running (or starting)" log.msg(emsg) raise ApplicationError("crossbar.error.already_started", emsg) try: checkconfig.check_manhole(config) except Exception as e: emsg = "ERROR: could not start manhole - invalid configuration ({})".format(e) log.msg(emsg) raise ApplicationError('crossbar.error.invalid_configuration', emsg) ## setup user authentication ## checker = checkers.InMemoryUsernamePasswordDatabaseDontUse() for user in config['users']: checker.addUser(user['user'], user['password']) ## setup manhole namespace ## namespace = {'session': self} class PatchedTerminalSession(TerminalSession): ## get rid of ## exceptions.AttributeError: TerminalSession instance has no attribute 'windowChanged' def windowChanged(self, winSize): pass rlm = TerminalRealm() rlm.sessionFactory = PatchedTerminalSession # monkey patch rlm.chainedProtocolFactory.protocolFactory = lambda _: ColoredManhole(namespace) ptl = portal.Portal(rlm, [checker]) factory = ConchFactory(ptl) factory.noisy = False self._manhole_service = ManholeService(config, details.authid) starting_topic = '{}.on_manhole_starting'.format(self._uri_prefix) starting_info = self._manhole_service.marshal() ## the caller gets a progressive result .. if details.progress: details.progress(starting_info) ## .. while all others get an event self.publish(starting_topic, starting_info, options = PublishOptions(exclude = [details.caller])) try: self._manhole_service.port = yield create_listening_port_from_config(config['endpoint'], factory, self.cbdir, reactor) except Exception as e: self._manhole_service = None emsg = "ERROR: manhole service endpoint cannot listen - {}".format(e) log.msg(emsg) raise ApplicationError("crossbar.error.cannot_listen", emsg) ## alright, manhole has started self._manhole_service.started = datetime.utcnow() self._manhole_service.status = 'started' started_topic = '{}.on_manhole_started'.format(self._uri_prefix) started_info = self._manhole_service.marshal() self.publish(started_topic, started_info, options = PublishOptions(exclude = [details.caller])) returnValue(started_info)