def test_login_gssapi_principal_needs_keytab(requests_session): """Login with gssapi method raises if principal is provided without keytab.""" hub_url = "https://hub.example.com/myapp/endpoint" conf = PyConfigParser() conf.load_from_dict( { "HUB_URL": hub_url, "AUTH_METHOD": "gssapi", "KRB_PRINCIPAL": "*****@*****.**", } ) transport = FakeTransport() logger = mock.Mock() proxy = HubProxy(conf, transport=transport, logger=logger) proxy._login(force=True) # This is pretty dumb: login() swallows all exceptions (probably for no good reason). # The only hint there was a problem is a DEBUG log message, so we detect the error # that way. logger.debug.assert_called_with( "Failed to create new session: Cannot specify a principal without a keytab" )
def run_task(self, task_info): TaskClass = self.task_container[task_info["method"]] # add *task_manager* attribute to foreground tasks if TaskClass.foreground: # TODO: TaskClass.task_manager = self hub = self.hub else: # create a new session for the task hub = HubProxy(self.conf, client_type="worker") task = TaskClass(hub, self.conf, task_info["id"], task_info["args"]) # redirect stdout and stderr thread = kobo.worker.logger.LoggingThread(hub, task_info["id"]) sys.stdout = kobo.worker.logger.LoggingIO(open(os.devnull, "w"), thread) sys.stderr = sys.stdout thread.start() failed = False try: task.run() except ShutdownException: thread.stop() if TaskClass.foreground and TaskClass.exclusive: # close task (shutdown-worker and similar control tasks) and raise hub.worker.close_task(task.task_id, task.result) raise # interrupt otherwise hub.worker.interrupt_tasks([task.task_id]) return except KeyboardInterrupt: thread.stop() # interrupt otherwise hub.worker.interrupt_tasks([task.task_id]) return except SystemExit as ex: if len(ex.args) > 0 and ex.args[0] != 0: sys.stdout.write("\nProgram has exited with return code '%s'." % ex.args[0]) failed = True except FailTaskException as ex: failed = True except: message = "ERROR: %s\n" % kobo.tback.get_exception() message += "See traceback.log for details (admin only).\n" hub.upload_task_log(StringIO(message), task.task_id, "error.log") hub.upload_task_log(StringIO(kobo.tback.Traceback().get_traceback()), task.task_id, "traceback.log", mode=0o600) failed = True finally: thread.stop() if failed: hub.worker.fail_task(task.task_id, task.result) else: hub.worker.close_task(task.task_id, task.result)
def test_login_gssapi_krb_opts(requests_session): """Login with gssapi method prepares auth using correct gssapi parameters according to config.""" hub_url = "https://hub.example.com/myapp/endpoint" login_url = "https://hub.example.com/myapp/auth/krb5login/" conf = PyConfigParser() conf.load_from_dict({ "HUB_URL": hub_url, "AUTH_METHOD": "gssapi", "CA_CERT": "/some/ca-bundle.pem", "KRB_PRINCIPAL": "*****@*****.**", "KRB_SERVICE": "SVC", "KRB_REALM": "REALM.EXAMPLE.COM", "KRB_KEYTAB": "some-keytab", "KRB_CCACHE": "some-cache", }) transport = FakeTransport() proxy = HubProxy(conf, transport=transport) mock_get = requests_session.return_value.get calls_before = len(mock_get.mock_calls) with mock.patch("requests_gssapi.HTTPSPNEGOAuth") as mock_auth: with mock.patch("gssapi.Credentials") as mock_creds: # Force a login proxy._login(force=True) get_call = mock_get.mock_calls[calls_before] # It should have prepared credentials with the details from config mock_creds.assert_called_once_with( name=gssapi.Name("*****@*****.**", gssapi.NameType.kerberos_principal), store={ "client_keytab": "some-keytab", "ccache": "FILE:some-cache" }, usage="initiate", ) # It should have prepared auth with those credentials and our configured # server principal mock_auth.assert_called_once_with( creds=mock_creds.return_value, target_name=gssapi.Name("SVC/[email protected]", gssapi.NameType.kerberos_principal), ) # It should have used the configured CA bundle when issuing the request assert get_call[2]["verify"] == "/some/ca-bundle.pem"
def __init__(self, conf, logger=None, **kwargs): kobo.log.LoggingBase.__init__(self, logger) self.conf = kobo.conf.PyConfigParser() # load default config default_config = os.path.abspath( os.path.join(os.path.dirname(__file__), "default.conf")) self.conf.load_from_file(default_config) # update data from another config if conf is not None: self.conf.load_from_conf(conf) # update data from kwargs self.conf.load_from_dict(kwargs) self.pid_dict = {} # { task_id: pid } self.task_dict = { } # { task_id: { task information obtained from self.hub.get_worker_tasks() } } self.locked = False # if task manager is locked, it waits until tasks finish and exits self.task_container = TaskContainer() # self.hub (xml-rpc hub client) is created here self.hub = HubProxy(conf, client_type="worker", logger=self._logger, **kwargs) # worker information obtained from hub self.worker_info = self.hub.worker.get_worker_info() self.update_worker_info()
def test_login_gssapi(requests_session): """Login with gssapi method obtains session cookie via SPNEGO & krb5login.""" hub_url = "https://example.com/myapp/endpoint" login_url = "https://example.com/myapp/auth/krb5login/" conf = PyConfigParser() conf.load_from_dict({ "HUB_URL": hub_url, "AUTH_METHOD": "gssapi", }) transport = FakeTransport() proxy = HubProxy(conf, transport=transport) # Proxy might have already done some calls during initialization. # We're trying to test login in isolation, so keep track of how many # mock calls there have been already. mock_get = requests_session.return_value.get calls_before = len(mock_get.mock_calls) # Force a login proxy._login(force=True) # Cookies should have been shared between session and transport assert requests_session.return_value.cookies is transport.cookiejar # Check the requests done calls = mock_get.mock_calls[calls_before:] assert calls[0][0] == "" call_args = calls[0][1] call_kwargs = calls[0][2] # It should have made a request to log in assert call_args == (login_url, ) # It should have enabled SPNEGO auth. # More details about this object are verified in a separate test. assert "HTTPSPNEGOAuth" in str(type(call_kwargs["auth"])) # It should have verified the result assert calls[1][0] == "().raise_for_status" # And that's all assert len(calls) == 2
def test_no_auto_logout(requests_session): """auto_logout argument warns of deprecation""" conf = PyConfigParser() conf.load_from_dict({"HUB_URL": 'https://example.com/hub'}) transport = FakeTransport() with pytest.deprecated_call(): HubProxy(conf, transport=transport, auto_logout=True)
def test_proxies_to_xmlrpc(requests_session): """HubProxy proxies to underlying XML-RPC ServerProxy""" conf = PyConfigParser() conf.load_from_dict({"HUB_URL": 'https://example.com/hub'}) transport = FakeTransport() proxy = HubProxy(conf, transport=transport) proxy.some_obj.some_method() # Last call should have invoked the method I requested (_, request_xml) = transport.fake_transport_calls[-1] assert b'some_obj.some_method' in request_xml
def run_task(self, task_info): TaskClass = self.task_container[task_info["method"]] # add *task_manager* attribute to foreground tasks if TaskClass.foreground: # TODO: TaskClass.task_manager = self hub = self.hub else: # create a new session for the task hub = HubProxy(self.conf, client_type="worker") task = TaskClass(hub, self.conf, task_info["id"], task_info["args"]) # redirect stdout and stderr thread = kobo.worker.logger.LoggingThread(hub, task_info["id"]) sys.stdout = kobo.worker.logger.LoggingIO(open(os.devnull, "w"), thread) sys.stderr = sys.stdout thread.start() failed = False try: task.run() except ShutdownException: thread.stop() if TaskClass.foreground and TaskClass.exclusive: # close task (shutdown-worker and similar control tasks) and raise hub.worker.close_task(task.task_id, task.result) raise # interrupt otherwise hub.worker.interrupt_tasks([task.task_id]) return except KeyboardInterrupt: thread.stop() # interrupt otherwise hub.worker.interrupt_tasks([task.task_id]) return except SystemExit, ex: if len(ex.args) > 0 and ex.args[0] != 0: sys.stdout.write("\nProgram has exited with return code '%s'." % ex.args[0]) failed = True
def run_task(self, task_info): TaskClass = self.task_container[task_info["method"]] # add *task_manager* attribute to foreground tasks if TaskClass.foreground: # TODO: TaskClass.task_manager = self hub = self.hub else: # create a new session for the task hub = HubProxy(self.conf, client_type="worker") task = TaskClass(hub, self.conf, task_info["id"], task_info["args"]) # redirect stdout and stderr thread = kobo.worker.logger.LoggingThread(hub, task_info["id"], logger=self) sys.stdout = kobo.worker.logger.LoggingIO(open(os.devnull, "w"), thread) sys.stderr = sys.stdout thread.start() failed = False try: task.run() except ShutdownException: thread.stop() if TaskClass.foreground and TaskClass.exclusive: # close task (shutdown-worker and similar control tasks) and raise hub.worker.close_task(task.task_id, task.result) raise # interrupt otherwise hub.worker.interrupt_tasks([task.task_id]) return except KeyboardInterrupt: thread.stop() # interrupt otherwise hub.worker.interrupt_tasks([task.task_id]) return except SystemExit as ex: if len(ex.args) > 0 and ex.args[0] != 0: sys.stdout.write( "\nProgram has exited with return code '%s'." % ex.args[0]) failed = True except FailTaskException as ex: failed = True except: message = "ERROR: %s\n" % kobo.tback.get_exception() message += "See traceback.log for details (admin only).\n" hub.upload_task_log(BytesIO(message.encode()), task.task_id, "error.log") hub.upload_task_log(BytesIO( kobo.tback.Traceback().get_traceback()), task.task_id, "traceback.log", mode=0o600) failed = True finally: thread.stop() if failed: hub.worker.fail_task(task.task_id, task.result) else: hub.worker.close_task(task.task_id, task.result)