From e2ea44e2b042e86c0eb3a02eb52a92457b6bf179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Thu, 20 Mar 2014 10:41:48 -0300 Subject: Refactor EIPBootstrapper to the backend --- src/leap/bitmask/backend.py | 84 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) (limited to 'src/leap/bitmask/backend.py') diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index 45ea451c..e4efa09f 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -32,6 +32,7 @@ from leap.bitmask.config.providerconfig import ProviderConfig from leap.bitmask.crypto.srpregister import SRPRegister from leap.bitmask.provider import get_provider_path from leap.bitmask.provider.providerbootstrapper import ProviderBootstrapper +from leap.bitmask.services.eip.eipbootstrapper import EIPBootstrapper # Frontend side from PySide import QtCore @@ -238,6 +239,60 @@ class Register(object): logger.error("Could not load provider configuration.") +class EIP(object): + """ + Interfaces with setup and launch of EIP + """ + + zope.interface.implements(ILEAPComponent) + + def __init__(self, signaler=None): + """ + Constructor for the EIP component + + :param signaler: Object in charge of handling communication + back to the frontend + :type signaler: Signaler + """ + object.__init__(self) + self.key = "eip" + self._eip_bootstrapper = EIPBootstrapper(signaler) + self._eip_setup_defer = None + self._provider_config = ProviderConfig() + + def setup_eip(self, domain): + """ + Initiates the setup for a provider + + :param domain: URL for the provider + :type domain: unicode + + :returns: the defer for the operation running in a thread. + :rtype: twisted.internet.defer.Deferred + """ + if (not self._provider_config.loaded() or + self._provider_config.get_domain() != domain): + self._provider_config.load(get_provider_path(domain)) + + if self._provider_config.loaded(): + log.msg("") + eb = self._eip_bootstrapper + d = eb.run_eip_setup_checks(self._provider_config, + download_if_needed=True) + self._eip_setup_defer = d + return d + else: + raise Exception("No provider setup loaded") + + def cancel_setup_eip(self): + """ + Cancel the ongoing setup eip defer (if any). + """ + d = self._eip_setup_defer + if d is not None: + d.cancel() + + class Signaler(QtCore.QObject): """ Signaler object, handles converting string commands to Qt signals. @@ -269,6 +324,12 @@ class Signaler(QtCore.QObject): srp_registration_failed = QtCore.Signal(object) srp_registration_taken = QtCore.Signal(object) + # Signals for EIP + eip_download_config = QtCore.Signal(object) + eip_download_client_certificate = QtCore.Signal(object) + + eip_cancelled_setup = QtCore.Signal(object) + #################### # These will exist both in the backend AND the front end. # The frontend might choose to not "interpret" all the signals @@ -289,6 +350,18 @@ class Signaler(QtCore.QObject): SRP_REGISTRATION_FAILED = "srp_registration_failed" SRP_REGISTRATION_TAKEN = "srp_registration_taken" + # TODO change the name of "download_config" signal to + # something less confusing (config_ready maybe) + EIP_DOWNLOAD_CONFIG = "eip_download_config" + EIP_DOWNLOAD_CLIENT_CERTIFICATE = "eip_download_client_certificate" + EIP_CANCELLED_SETUP = "eip_cancelled_setup" + + # TODO change the name of "download_config" signal to + # something less confusing (config_ready maybe) + EIP_DOWNLOAD_CONFIG = "eip_download_config" + EIP_DOWNLOAD_CLIENT_CERTIFICATE = "eip_download_client_certificate" + EIP_CANCELLED_SETUP = "eip_cancelled_setup" + def __init__(self): """ Constructor for the Signaler @@ -311,6 +384,10 @@ class Signaler(QtCore.QObject): self.SRP_REGISTRATION_FINISHED, self.SRP_REGISTRATION_FAILED, self.SRP_REGISTRATION_TAKEN, + + self.EIP_DOWNLOAD_CONFIG, + self.EIP_DOWNLOAD_CLIENT_CERTIFICATE, + self.EIP_CANCELLED_SETUP, ] for sig in signals: @@ -370,6 +447,7 @@ class Backend(object): # Component registration self._register(Provider(self._signaler, bypass_checks)) self._register(Register(self._signaler)) + self._register(EIP(self._signaler)) # We have a looping call on a thread executing all the # commands in queue. Right now this queue is an actual Queue @@ -487,3 +565,9 @@ class Backend(object): def register_user(self, provider, username, password): self._call_queue.put(("register", "register_user", None, provider, username, password)) + + def setup_eip(self, provider): + self._call_queue.put(("eip", "setup_eip", None, provider)) + + def cancel_setup_eip(self): + self._call_queue.put(("eip", "cancel_setup_eip", None)) -- cgit v1.2.3 From c8137a8829668270d4391c7909b39c56b64f604c Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 19 Mar 2014 16:05:16 -0300 Subject: Refactor out the ProviderConfig object retriever. --- src/leap/bitmask/backend.py | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) (limited to 'src/leap/bitmask/backend.py') diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index e4efa09f..3c9991be 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -40,6 +40,26 @@ from PySide import QtCore logger = logging.getLogger(__name__) +def get_provider_config(config, domain): + """ + Return the ProviderConfig object for the given domain. + If it is already loaded in `config`, then don't reload. + + :param config: a ProviderConfig object + :type conig: ProviderConfig + :param domain: the domain which config is required. + :type domain: unicode + + :returns: True if the config was loaded successfully, False otherwise. + :rtype: bool + """ + # TODO: see ProviderConfig.get_provider_config + if (not config.loaded() or config.get_domain() != domain): + config.load(get_provider_path(domain)) + + return config.loaded() + + class ILEAPComponent(zope.interface.Interface): """ Interface that every component for the backend should comply to @@ -129,7 +149,6 @@ class Provider(object): self._provider_bootstrapper = ProviderBootstrapper(signaler, bypass_checks) self._download_provider_defer = None - self._provider_config = ProviderConfig() def setup_provider(self, provider): """ @@ -167,13 +186,8 @@ class Provider(object): """ d = None - # If there's no loaded provider or - # we want to connect to other provider... - if (not self._provider_config.loaded() or - self._provider_config.get_domain() != provider): - self._provider_config.load(get_provider_path(provider)) - - if self._provider_config.loaded(): + config = ProviderConfig() + if get_provider_config(config, provider): d = self._provider_bootstrapper.run_provider_setup_checks( self._provider_config, download_if_needed=True) @@ -206,7 +220,6 @@ class Register(object): object.__init__(self) self.key = "register" self._signaler = signaler - self._provider_config = ProviderConfig() def register_user(self, domain, username, password): """ @@ -222,15 +235,10 @@ class Register(object): :returns: the defer for the operation running in a thread. :rtype: twisted.internet.defer.Deferred """ - # If there's no loaded provider or - # we want to connect to other provider... - if (not self._provider_config.loaded() or - self._provider_config.get_domain() != domain): - self._provider_config.load(get_provider_path(domain)) - - if self._provider_config.loaded(): + config = ProviderConfig() + if get_provider_config(config, domain): srpregister = SRPRegister(signaler=self._signaler, - provider_config=self._provider_config) + provider_config=config) return threads.deferToThread( partial(srpregister.register_user, username, password)) else: -- cgit v1.2.3 From 6444c6c9c758b1f4bd291d5e4e5455b84345ec9b Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 19 Mar 2014 16:06:07 -0300 Subject: Move SRPAuth to the backend. * Move methods from SRPAuth to backend: login, logout, change_password. * Add backend section to hold temporary hack code, needed in the process of splitting frontend and backend. * Replace pyside signals with Signaler signals. * Move all the signaling and thread launching in SRPAuth inside of __impl. * Move defer handling code (callbacks/errbacks) to the backend and left only signal handling in the GUI. [Closes #5347] --- src/leap/bitmask/backend.py | 199 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 198 insertions(+), 1 deletion(-) (limited to 'src/leap/bitmask/backend.py') diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index 3c9991be..d78a9a6a 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -29,6 +29,7 @@ from twisted.python import log import zope.interface from leap.bitmask.config.providerconfig import ProviderConfig +from leap.bitmask.crypto.srpauth import SRPAuth from leap.bitmask.crypto.srpregister import SRPRegister from leap.bitmask.provider import get_provider_path from leap.bitmask.provider.providerbootstrapper import ProviderBootstrapper @@ -149,6 +150,7 @@ class Provider(object): self._provider_bootstrapper = ProviderBootstrapper(signaler, bypass_checks) self._download_provider_defer = None + self._provider_config = ProviderConfig() def setup_provider(self, provider): """ @@ -186,7 +188,7 @@ class Provider(object): """ d = None - config = ProviderConfig() + config = self._provider_config if get_provider_config(config, provider): d = self._provider_bootstrapper.run_provider_setup_checks( self._provider_config, @@ -247,6 +249,113 @@ class Register(object): logger.error("Could not load provider configuration.") +class Authenticate(object): + """ + Interfaces with setup and bootstrapping operations for a provider + """ + + zope.interface.implements(ILEAPComponent) + + def __init__(self, signaler=None): + """ + Constructor for the Authenticate component + + :param signaler: Object in charge of handling communication + back to the frontend + :type signaler: Signaler + """ + object.__init__(self) + self.key = "authenticate" + self._signaler = signaler + self._srp_auth = None + + def login(self, domain, username, password): + """ + Executes the whole authentication process for a user + + :param domain: the domain where we need to authenticate. + :type domain: unicode + :param username: username for this session + :type username: str + :param password: password for this user + :type password: str + + :returns: the defer for the operation running in a thread. + :rtype: twisted.internet.defer.Deferred + """ + config = ProviderConfig() + if get_provider_config(config, domain): + self._srp_auth = SRPAuth(config, self._signaler) + self._login_defer = self._srp_auth.authenticate(username, password) + return self._login_defer + else: + if self._signaler is not None: + self._signaler.signal(self._signaler.srp_auth_error) + logger.error("Could not load provider configuration.") + + def cancel_login(self): + """ + Cancel the ongoing login defer (if any). + """ + d = self._login_defer + if d is not None: + d.cancel() + + def change_password(self, current_password, new_password): + """ + Changes the user's password. + + :param current_password: the current password of the user. + :type current_password: str + :param new_password: the new password for the user. + :type new_password: str + + :returns: a defer to interact with. + :rtype: twisted.internet.defer.Deferred + """ + if not self._is_logged_in(): + if self._signaler is not None: + self._signaler.signal(self._signaler.SRP_NOT_LOGGED_IN_ERROR) + return + + return self._srp_auth.change_password(current_password, new_password) + + def logout(self): + """ + Logs out the current session. + Expects a session_id to exists, might raise AssertionError + """ + if not self._is_logged_in(): + if self._signaler is not None: + self._signaler.signal(self._signaler.SRP_NOT_LOGGED_IN_ERROR) + return + + self._srp_auth.logout() + + def _is_logged_in(self): + """ + Return whether the user is logged in or not. + + :rtype: bool + """ + return self._srp_auth.is_authenticated() + + def get_logged_in_status(self): + """ + Signals if the user is currently logged in or not. + """ + if self._signaler is None: + return + + signal = None + if self._is_logged_in(): + signal = self._signaler.SRP_STATUS_LOGGED_IN + else: + signal = self._signaler.SRP_STATUS_NOT_LOGGED_IN + + self._signaler.signal(signal) + + class EIP(object): """ Interfaces with setup and launch of EIP @@ -338,6 +447,21 @@ class Signaler(QtCore.QObject): eip_cancelled_setup = QtCore.Signal(object) + # Signals for SRPAuth + srp_auth_ok = QtCore.Signal(object) + srp_auth_error = QtCore.Signal(object) + srp_auth_server_error = QtCore.Signal(object) + srp_auth_connection_error = QtCore.Signal(object) + srp_auth_bad_user_or_password = QtCore.Signal(object) + srp_logout_ok = QtCore.Signal(object) + srp_logout_error = QtCore.Signal(object) + srp_password_change_ok = QtCore.Signal(object) + srp_password_change_error = QtCore.Signal(object) + srp_password_change_badpw = QtCore.Signal(object) + srp_not_logged_in_error = QtCore.Signal(object) + srp_status_logged_in = QtCore.Signal(object) + srp_status_not_logged_in = QtCore.Signal(object) + #################### # These will exist both in the backend AND the front end. # The frontend might choose to not "interpret" all the signals @@ -357,6 +481,19 @@ class Signaler(QtCore.QObject): SRP_REGISTRATION_FINISHED = "srp_registration_finished" SRP_REGISTRATION_FAILED = "srp_registration_failed" SRP_REGISTRATION_TAKEN = "srp_registration_taken" + SRP_AUTH_OK = "srp_auth_ok" + SRP_AUTH_ERROR = "srp_auth_error" + SRP_AUTH_SERVER_ERROR = "srp_auth_server_error" + SRP_AUTH_CONNECTION_ERROR = "srp_auth_connection_error" + SRP_AUTH_BAD_USER_OR_PASSWORD = "srp_auth_bad_user_or_password" + SRP_LOGOUT_OK = "srp_logout_ok" + SRP_LOGOUT_ERROR = "srp_logout_error" + SRP_PASSWORD_CHANGE_OK = "srp_password_change_ok" + SRP_PASSWORD_CHANGE_ERROR = "srp_password_change_error" + SRP_PASSWORD_CHANGE_BADPW = "srp_password_change_badpw" + SRP_NOT_LOGGED_IN_ERROR = "srp_not_logged_in_error" + SRP_STATUS_LOGGED_IN = "srp_status_logged_in" + SRP_STATUS_NOT_LOGGED_IN = "srp_status_not_logged_in" # TODO change the name of "download_config" signal to # something less confusing (config_ready maybe) @@ -396,6 +533,20 @@ class Signaler(QtCore.QObject): self.EIP_DOWNLOAD_CONFIG, self.EIP_DOWNLOAD_CLIENT_CERTIFICATE, self.EIP_CANCELLED_SETUP, + + self.SRP_AUTH_OK, + self.SRP_AUTH_ERROR, + self.SRP_AUTH_SERVER_ERROR, + self.SRP_AUTH_CONNECTION_ERROR, + self.SRP_AUTH_BAD_USER_OR_PASSWORD, + self.SRP_LOGOUT_OK, + self.SRP_LOGOUT_ERROR, + self.SRP_PASSWORD_CHANGE_OK, + self.SRP_PASSWORD_CHANGE_ERROR, + self.SRP_PASSWORD_CHANGE_BADPW, + self.SRP_NOT_LOGGED_IN_ERROR, + self.SRP_STATUS_LOGGED_IN, + self.SRP_STATUS_NOT_LOGGED_IN, ] for sig in signals: @@ -455,6 +606,7 @@ class Backend(object): # Component registration self._register(Provider(self._signaler, bypass_checks)) self._register(Register(self._signaler)) + self._register(Authenticate(self._signaler)) self._register(EIP(self._signaler)) # We have a looping call on a thread executing all the @@ -579,3 +731,48 @@ class Backend(object): def cancel_setup_eip(self): self._call_queue.put(("eip", "cancel_setup_eip", None)) + + def login(self, provider, username, password): + self._call_queue.put(("authenticate", "login", None, provider, + username, password)) + + def logout(self): + self._call_queue.put(("authenticate", "logout", None)) + + def cancel_login(self): + self._call_queue.put(("authenticate", "cancel_login", None)) + + def change_password(self, current_password, new_password): + self._call_queue.put(("authenticate", "change_password", None, + current_password, new_password)) + + def get_logged_in_status(self): + self._call_queue.put(("authenticate", "get_logged_in_status", None)) + + ########################################################################### + # XXX HACK: this section is meant to be a place to hold methods and + # variables needed in the meantime while we migrate all to the backend. + + def srpauth_get_username(self): + srp_auth = self._components["authenticate"]._srp_auth + if srp_auth is not None: + return srp_auth.get_username() + + def srpauth_get_session_id(self): + srp_auth = self._components["authenticate"]._srp_auth + if srp_auth is not None: + return srp_auth.get_session_id() + + def srpauth_get_uuid(self): + srp_auth = self._components["authenticate"]._srp_auth + if srp_auth is not None: + return srp_auth.get_uuid() + + def srpauth_get_token(self): + srp_auth = self._components["authenticate"]._srp_auth + if srp_auth is not None: + return srp_auth.get_token() + + def get_provider_config(self): + provider_config = self._components["provider"]._provider_config + return provider_config -- cgit v1.2.3 From c9ce042921d4da8825db4580e27cac4bf74280c3 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 26 Mar 2014 14:52:14 -0300 Subject: Use helper to get the ProviderConfig. --- src/leap/bitmask/backend.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'src/leap/bitmask/backend.py') diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index d78a9a6a..2d86bf09 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -387,11 +387,8 @@ class EIP(object): :returns: the defer for the operation running in a thread. :rtype: twisted.internet.defer.Deferred """ - if (not self._provider_config.loaded() or - self._provider_config.get_domain() != domain): - self._provider_config.load(get_provider_path(domain)) - - if self._provider_config.loaded(): + config = self._provider_config + if get_provider_config(config, domain): log.msg("") eb = self._eip_bootstrapper d = eb.run_eip_setup_checks(self._provider_config, -- cgit v1.2.3 From 03c58451eaf8904346148835b0c3460deae28c3e Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 26 Mar 2014 14:54:30 -0300 Subject: Do not redefine signaler signal key. --- src/leap/bitmask/backend.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/leap/bitmask/backend.py') diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index 2d86bf09..6b168d5d 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -131,8 +131,6 @@ class Provider(object): zope.interface.implements(ILEAPComponent) - PROBLEM_SIGNAL = "prov_problem_with_provider" - def __init__(self, signaler=None, bypass_checks=False): """ Constructor for the Provider component @@ -195,7 +193,8 @@ class Provider(object): download_if_needed=True) else: if self._signaler is not None: - self._signaler.signal(self.PROBLEM_SIGNAL) + self._signaler.signal( + self._signaler.PROV_PROBLEM_WITH_PROVIDER_KEY) logger.error("Could not load provider configuration.") self._login_widget.set_enabled(True) -- cgit v1.2.3 From 540a37766e9bdb1f4d533529734308a91c42f0d2 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 27 Mar 2014 17:15:57 -0300 Subject: Fix: use signal's keys instead of qt signals. --- src/leap/bitmask/backend.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/leap/bitmask/backend.py') diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index 6b168d5d..e179b7d5 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -244,7 +244,7 @@ class Register(object): partial(srpregister.register_user, username, password)) else: if self._signaler is not None: - self._signaler.signal(self._signaler.srp_registration_failed) + self._signaler.signal(self._signaler.SRP_REGISTRATION_FAILED) logger.error("Could not load provider configuration.") @@ -289,7 +289,7 @@ class Authenticate(object): return self._login_defer else: if self._signaler is not None: - self._signaler.signal(self._signaler.srp_auth_error) + self._signaler.signal(self._signaler.SRP_AUTH_ERROR) logger.error("Could not load provider configuration.") def cancel_login(self): -- cgit v1.2.3 From 8e492fe37168e2e6874684e422376f2a43b4a4a4 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Fri, 28 Mar 2014 14:43:43 -0300 Subject: Remove unused 'hack' helpers. --- src/leap/bitmask/backend.py | 20 -------------------- 1 file changed, 20 deletions(-) (limited to 'src/leap/bitmask/backend.py') diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index e179b7d5..00a399ee 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -749,26 +749,6 @@ class Backend(object): # XXX HACK: this section is meant to be a place to hold methods and # variables needed in the meantime while we migrate all to the backend. - def srpauth_get_username(self): - srp_auth = self._components["authenticate"]._srp_auth - if srp_auth is not None: - return srp_auth.get_username() - - def srpauth_get_session_id(self): - srp_auth = self._components["authenticate"]._srp_auth - if srp_auth is not None: - return srp_auth.get_session_id() - - def srpauth_get_uuid(self): - srp_auth = self._components["authenticate"]._srp_auth - if srp_auth is not None: - return srp_auth.get_uuid() - - def srpauth_get_token(self): - srp_auth = self._components["authenticate"]._srp_auth - if srp_auth is not None: - return srp_auth.get_token() - def get_provider_config(self): provider_config = self._components["provider"]._provider_config return provider_config -- cgit v1.2.3 From a73c432400eb6a614706fc615a505ed78d4031e3 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 27 Mar 2014 17:16:04 -0300 Subject: Move EIP to the backend. - Add backend eip management - Connect gui with new eip signals - remove old unused code - remove Qt dependency from backend services. - use Signaler to emit status/state changes from openvpn --- src/leap/bitmask/backend.py | 278 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 221 insertions(+), 57 deletions(-) (limited to 'src/leap/bitmask/backend.py') diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index 00a399ee..591b5da5 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -33,8 +33,13 @@ from leap.bitmask.crypto.srpauth import SRPAuth from leap.bitmask.crypto.srpregister import SRPRegister from leap.bitmask.provider import get_provider_path from leap.bitmask.provider.providerbootstrapper import ProviderBootstrapper +from leap.bitmask.services.eip import eipconfig +from leap.bitmask.services.eip import get_openvpn_management from leap.bitmask.services.eip.eipbootstrapper import EIPBootstrapper +from leap.bitmask.services.eip import vpnlauncher, vpnprocess +from leap.bitmask.services.eip import linuxvpnlauncher, darwinvpnlauncher + # Frontend side from PySide import QtCore @@ -248,6 +253,140 @@ class Register(object): logger.error("Could not load provider configuration.") +class EIP(object): + """ + Interfaces with setup and launch of EIP + """ + + zope.interface.implements(ILEAPService) + + def __init__(self, signaler=None): + """ + Constructor for the EIP component + + :param signaler: Object in charge of handling communication + back to the frontend + :type signaler: Signaler + """ + object.__init__(self) + self.key = "eip" + self._signaler = signaler + self._eip_bootstrapper = EIPBootstrapper(signaler) + self._eip_setup_defer = None + self._provider_config = ProviderConfig() + + self._vpn = vpnprocess.VPN(signaler=signaler) + + def setup_eip(self, domain): + """ + Initiates the setup for a provider + + :param domain: URL for the provider + :type domain: unicode + + :returns: the defer for the operation running in a thread. + :rtype: twisted.internet.defer.Deferred + """ + config = self._provider_config + if get_provider_config(config, domain): + eb = self._eip_bootstrapper + d = eb.run_eip_setup_checks(self._provider_config, + download_if_needed=True) + self._eip_setup_defer = d + return d + else: + raise Exception("No provider setup loaded") + + def cancel_setup_eip(self): + """ + Cancel the ongoing setup eip defer (if any). + """ + d = self._eip_setup_defer + if d is not None: + d.cancel() + + def _start_eip(self): + """ + Starts EIP + """ + provider_config = self._provider_config + eip_config = eipconfig.EIPConfig() + domain = provider_config.get_domain() + + loaded = eipconfig.load_eipconfig_if_needed( + provider_config, eip_config, domain) + + if not loaded: + if self._signaler is not None: + self._signaler.signal(self._signaler.EIP_CONNECTION_ABORTED) + logger.error("Tried to start EIP but cannot find any " + "available provider!") + return + + host, port = get_openvpn_management() + self._vpn.start(eipconfig=eip_config, + providerconfig=provider_config, + socket_host=host, socket_port=port) + + def start(self): + """ + Starts the service. + """ + signaler = self._signaler + + if not self._provider_config.loaded(): + # This means that the user didn't call setup_eip first. + self._signaler.signal(signaler.BACKEND_BAD_CALL) + return + + try: + self._start_eip() + except vpnprocess.OpenVPNAlreadyRunning: + signaler.signal(signaler.EIP_OPEN_VPN_ALREADY_RUNNING) + except vpnprocess.AlienOpenVPNAlreadyRunning: + signaler.signal(signaler.EIP_ALIEN_OPEN_VPN_ALREADY_RUNNING) + except vpnlauncher.OpenVPNNotFoundException: + signaler.signal(signaler.EIP_OPEN_VPN_NOT_FOUND_ERROR) + except vpnlauncher.VPNLauncherException: + # TODO: this seems to be used for 'gateway not found' only. + # see vpnlauncher.py + signaler.signal(signaler.EIP_VPN_LAUNCHER_EXCEPTION) + except linuxvpnlauncher.EIPNoPolkitAuthAgentAvailable: + signaler.signal(signaler.EIP_NO_POLKIT_AGENT_ERROR) + except linuxvpnlauncher.EIPNoPkexecAvailable: + signaler.signal(signaler.EIP_NO_PKEXEC_ERROR) + except darwinvpnlauncher.EIPNoTunKextLoaded: + signaler.signal(signaler.EIP_NO_TUN_KEXT_ERROR) + except Exception as e: + logger.error("Unexpected problem: {0!r}".format(e)) + else: + # TODO: are we connected here? + signaler.signal(signaler.EIP_CONNECTED) + + def stop(self, shutdown=False): + """ + Stops the service. + """ + self._vpn.terminate(shutdown) + + def terminate(self): + """ + Terminates the service, not necessarily in a nice way. + """ + self._vpn.killit() + + def status(self): + """ + Returns a json object with the current status for the service. + + :rtype: object (list, str, dict) + """ + # XXX: Use a namedtuple or a specific object instead of a json + # object, since parsing it will be problematic otherwise. + # It has to be something easily serializable though. + pass + + class Authenticate(object): """ Interfaces with setup and bootstrapping operations for a provider @@ -355,57 +494,6 @@ class Authenticate(object): self._signaler.signal(signal) -class EIP(object): - """ - Interfaces with setup and launch of EIP - """ - - zope.interface.implements(ILEAPComponent) - - def __init__(self, signaler=None): - """ - Constructor for the EIP component - - :param signaler: Object in charge of handling communication - back to the frontend - :type signaler: Signaler - """ - object.__init__(self) - self.key = "eip" - self._eip_bootstrapper = EIPBootstrapper(signaler) - self._eip_setup_defer = None - self._provider_config = ProviderConfig() - - def setup_eip(self, domain): - """ - Initiates the setup for a provider - - :param domain: URL for the provider - :type domain: unicode - - :returns: the defer for the operation running in a thread. - :rtype: twisted.internet.defer.Deferred - """ - config = self._provider_config - if get_provider_config(config, domain): - log.msg("") - eb = self._eip_bootstrapper - d = eb.run_eip_setup_checks(self._provider_config, - download_if_needed=True) - self._eip_setup_defer = d - return d - else: - raise Exception("No provider setup loaded") - - def cancel_setup_eip(self): - """ - Cancel the ongoing setup eip defer (if any). - """ - d = self._eip_setup_defer - if d is not None: - d.cancel() - - class Signaler(QtCore.QObject): """ Signaler object, handles converting string commands to Qt signals. @@ -437,7 +525,7 @@ class Signaler(QtCore.QObject): srp_registration_failed = QtCore.Signal(object) srp_registration_taken = QtCore.Signal(object) - # Signals for EIP + # Signals for EIP bootstrapping eip_download_config = QtCore.Signal(object) eip_download_client_certificate = QtCore.Signal(object) @@ -458,6 +546,35 @@ class Signaler(QtCore.QObject): srp_status_logged_in = QtCore.Signal(object) srp_status_not_logged_in = QtCore.Signal(object) + # Signals for EIP + eip_connected = QtCore.Signal(object) + eip_disconnected = QtCore.Signal(object) + eip_connection_died = QtCore.Signal(object) + eip_connection_aborted = QtCore.Signal(object) + + # EIP problems + eip_no_polkit_agent_error = QtCore.Signal(object) + eip_no_tun_kext_error = QtCore.Signal(object) + eip_no_pkexec_error = QtCore.Signal(object) + eip_openvpn_not_found_error = QtCore.Signal(object) + eip_openvpn_already_running = QtCore.Signal(object) + eip_alien_openvpn_already_running = QtCore.Signal(object) + eip_vpn_launcher_exception = QtCore.Signal(object) + + # signals from parsing openvpn output + eip_network_unreachable = QtCore.Signal(object) + eip_process_restart_tls = QtCore.Signal(object) + eip_process_restart_ping = QtCore.Signal(object) + + # signals from vpnprocess.py + eip_state_changed = QtCore.Signal(dict) + eip_status_changed = QtCore.Signal(dict) + eip_process_finished = QtCore.Signal(int) + + # This signal is used to warn the backend user that is doing something + # wrong + backend_bad_call = QtCore.Signal(object) + #################### # These will exist both in the backend AND the front end. # The frontend might choose to not "interpret" all the signals @@ -497,11 +614,27 @@ class Signaler(QtCore.QObject): EIP_DOWNLOAD_CLIENT_CERTIFICATE = "eip_download_client_certificate" EIP_CANCELLED_SETUP = "eip_cancelled_setup" - # TODO change the name of "download_config" signal to - # something less confusing (config_ready maybe) - EIP_DOWNLOAD_CONFIG = "eip_download_config" - EIP_DOWNLOAD_CLIENT_CERTIFICATE = "eip_download_client_certificate" - EIP_CANCELLED_SETUP = "eip_cancelled_setup" + EIP_CONNECTED = "eip_connected" + EIP_DISCONNECTED = "eip_disconnected" + EIP_CONNECTION_DIED = "eip_connection_died" + EIP_CONNECTION_ABORTED = "eip_connection_aborted" + EIP_NO_POLKIT_AGENT_ERROR = "eip_no_polkit_agent_error" + EIP_NO_TUN_KEXT_ERROR = "eip_no_tun_kext_error" + EIP_NO_PKEXEC_ERROR = "eip_no_pkexec_error" + EIP_OPENVPN_NOT_FOUND_ERROR = "eip_openvpn_not_found_error" + EIP_OPENVPN_ALREADY_RUNNING = "eip_openvpn_already_running" + EIP_ALIEN_OPENVPN_ALREADY_RUNNING = "eip_alien_openvpn_already_running" + EIP_VPN_LAUNCHER_EXCEPTION = "eip_vpn_launcher_exception" + + EIP_NETWORK_UNREACHABLE = "eip_network_unreachable" + EIP_PROCESS_RESTART_TLS = "eip_process_restart_tls" + EIP_PROCESS_RESTART_PING = "eip_process_restart_ping" + + EIP_STATE_CHANGED = "eip_state_changed" + EIP_STATUS_CHANGED = "eip_status_changed" + EIP_PROCESS_FINISHED = "eip_process_finished" + + BACKEND_BAD_CALL = "backend_bad_call" def __init__(self): """ @@ -530,6 +663,26 @@ class Signaler(QtCore.QObject): self.EIP_DOWNLOAD_CLIENT_CERTIFICATE, self.EIP_CANCELLED_SETUP, + self.EIP_CONNECTED, + self.EIP_DISCONNECTED, + self.EIP_CONNECTION_DIED, + self.EIP_CONNECTION_ABORTED, + self.EIP_NO_POLKIT_AGENT_ERROR, + self.EIP_NO_TUN_KEXT_ERROR, + self.EIP_NO_PKEXEC_ERROR, + self.EIP_OPENVPN_NOT_FOUND_ERROR, + self.EIP_OPENVPN_ALREADY_RUNNING, + self.EIP_ALIEN_OPENVPN_ALREADY_RUNNING, + self.EIP_VPN_LAUNCHER_EXCEPTION, + + self.EIP_NETWORK_UNREACHABLE, + self.EIP_PROCESS_RESTART_TLS, + self.EIP_PROCESS_RESTART_PING, + + self.EIP_STATE_CHANGED, + self.EIP_STATUS_CHANGED, + self.EIP_PROCESS_FINISHED, + self.SRP_AUTH_OK, self.SRP_AUTH_ERROR, self.SRP_AUTH_SERVER_ERROR, @@ -543,6 +696,8 @@ class Signaler(QtCore.QObject): self.SRP_NOT_LOGGED_IN_ERROR, self.SRP_STATUS_LOGGED_IN, self.SRP_STATUS_NOT_LOGGED_IN, + + self.BACKEND_BAD_CALL, ] for sig in signals: @@ -728,6 +883,15 @@ class Backend(object): def cancel_setup_eip(self): self._call_queue.put(("eip", "cancel_setup_eip", None)) + def start_eip(self): + self._call_queue.put(("eip", "start", None)) + + def stop_eip(self, shutdown=False): + self._call_queue.put(("eip", "stop", None, shutdown)) + + def terminate_eip(self): + self._call_queue.put(("eip", "terminate", None)) + def login(self, provider, username, password): self._call_queue.put(("authenticate", "login", None, provider, username, password)) -- cgit v1.2.3 From a4772ef52bb7f258a079aaa88cc41a4f8e086073 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Tue, 8 Apr 2014 13:16:56 -0300 Subject: Move gateway selection helpers to backend. --- src/leap/bitmask/backend.py | 92 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) (limited to 'src/leap/bitmask/backend.py') diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index 591b5da5..febe56a5 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -18,6 +18,7 @@ Backend for everything """ import logging +import os from functools import partial from Queue import Queue, Empty @@ -386,6 +387,75 @@ class EIP(object): # It has to be something easily serializable though. pass + def _provider_is_initialized(self, domain): + """ + Returns if the given domain is initialized or not. + + :param domain: the domain to check + :type domain: str + + :returns: True if is initialized, False otherwise. + :rtype: bool + """ + eipconfig_path = eipconfig.get_eipconfig_path(domain, relative=False) + if os.path.isfile(eipconfig_path): + return True + else: + return False + + def get_initialized_providers(self, domains): + """ + Signals a list of the given domains and if they are initialized or not. + + :param domains: the list of domains to check. + :type domain: list of str + + :signal type: list of tuples (str, bool) + """ + filtered_domains = [] + for domain in domains: + is_initialized = self._provider_is_initialized(domain) + filtered_domains.append((domain, is_initialized)) + + if self._signaler is not None: + self._signaler.signal(self._signaler.EIP_GET_INITIALIZED_PROVIDERS, + filtered_domains) + + def get_gateways_list(self, domain): + """ + Signals a list of gateways for the given provider. + + :param domain: the domain to get the gateways. + :type domain: str + + :signal type: list of str + """ + if not self._provider_is_initialized(domain): + if self._signaler is not None: + self._signaler.signal( + self._signaler.EIP_UNINITIALIZED_PROVIDER) + return + + eip_config = eipconfig.EIPConfig() + provider_config = ProviderConfig.get_provider_config(domain) + + api_version = provider_config.get_api_version() + eip_config.set_api_version(api_version) + eip_loaded = eip_config.load(eipconfig.get_eipconfig_path(domain)) + + # check for other problems + if not eip_loaded or provider_config is None: + if self._signaler is not None: + self._signaler.signal( + self._signaler.EIP_GET_GATEWAYS_LIST_ERROR) + return + + gateways = eipconfig.VPNGatewaySelector(eip_config).get_gateways_list() + + if self._signaler is not None: + self._signaler.signal( + self._signaler.EIP_GET_GATEWAYS_LIST, gateways) + class Authenticate(object): """ @@ -561,6 +631,11 @@ class Signaler(QtCore.QObject): eip_alien_openvpn_already_running = QtCore.Signal(object) eip_vpn_launcher_exception = QtCore.Signal(object) + eip_get_gateways_list = QtCore.Signal(object) + eip_get_gateways_list_error = QtCore.Signal(object) + eip_uninitialized_provider = QtCore.Signal(object) + eip_get_initialized_providers = QtCore.Signal(object) + # signals from parsing openvpn output eip_network_unreachable = QtCore.Signal(object) eip_process_restart_tls = QtCore.Signal(object) @@ -626,6 +701,11 @@ class Signaler(QtCore.QObject): EIP_ALIEN_OPENVPN_ALREADY_RUNNING = "eip_alien_openvpn_already_running" EIP_VPN_LAUNCHER_EXCEPTION = "eip_vpn_launcher_exception" + EIP_GET_GATEWAYS_LIST = "eip_get_gateways_list" + EIP_GET_GATEWAYS_LIST_ERROR = "eip_get_gateways_list_error" + EIP_UNINITIALIZED_PROVIDER = "eip_uninitialized_provider" + EIP_GET_INITIALIZED_PROVIDERS = "eip_get_initialized_providers" + EIP_NETWORK_UNREACHABLE = "eip_network_unreachable" EIP_PROCESS_RESTART_TLS = "eip_process_restart_tls" EIP_PROCESS_RESTART_PING = "eip_process_restart_ping" @@ -675,6 +755,11 @@ class Signaler(QtCore.QObject): self.EIP_ALIEN_OPENVPN_ALREADY_RUNNING, self.EIP_VPN_LAUNCHER_EXCEPTION, + self.EIP_GET_GATEWAYS_LIST, + self.EIP_GET_GATEWAYS_LIST_ERROR, + self.EIP_UNINITIALIZED_PROVIDER, + self.EIP_GET_INITIALIZED_PROVIDERS, + self.EIP_NETWORK_UNREACHABLE, self.EIP_PROCESS_RESTART_TLS, self.EIP_PROCESS_RESTART_PING, @@ -892,6 +977,13 @@ class Backend(object): def terminate_eip(self): self._call_queue.put(("eip", "terminate", None)) + def eip_get_gateways_list(self, domain): + self._call_queue.put(("eip", "get_gateways_list", None, domain)) + + def eip_get_initialized_providers(self, domains): + self._call_queue.put(("eip", "get_initialized_providers", + None, domains)) + def login(self, provider, username, password): self._call_queue.put(("authenticate", "login", None, provider, username, password)) -- cgit v1.2.3 From 62a7526c38e4c5cb234fe0b2a5d376eecb0dfcec Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 14 Apr 2014 12:16:39 -0300 Subject: Remove signaling logs, use err for unknown signal. --- src/leap/bitmask/backend.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/leap/bitmask/backend.py') diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index febe56a5..3d238626 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -804,7 +804,6 @@ class Signaler(QtCore.QObject): # Right now it emits Qt signals. The backend version of this # will do zmq.send_multipart, and the frontend version will be # similar to this - log.msg("Signaling %s :: %s" % (key, data)) # for some reason emitting 'None' gives a segmentation fault. if data is None: @@ -813,7 +812,7 @@ class Signaler(QtCore.QObject): try: self._signals[key].emit(data) except KeyError: - log.msg("Unknown key for signal %s!" % (key,)) + log.err("Unknown key for signal %s!" % (key,)) class Backend(object): -- cgit v1.2.3 From 37577fdf037f2987ae3eb9493457dd8d4447aaf7 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 14 Apr 2014 15:35:16 -0300 Subject: Use less confusing signal names. Renames: eip_download_config -> eip_config_ready eip_download_client_certificate -> eip_client_certificate_ready --- src/leap/bitmask/backend.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'src/leap/bitmask/backend.py') diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index 3d238626..c71553a3 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -596,8 +596,8 @@ class Signaler(QtCore.QObject): srp_registration_taken = QtCore.Signal(object) # Signals for EIP bootstrapping - eip_download_config = QtCore.Signal(object) - eip_download_client_certificate = QtCore.Signal(object) + eip_config_ready = QtCore.Signal(object) + eip_client_certificate_ready = QtCore.Signal(object) eip_cancelled_setup = QtCore.Signal(object) @@ -683,10 +683,8 @@ class Signaler(QtCore.QObject): SRP_STATUS_LOGGED_IN = "srp_status_logged_in" SRP_STATUS_NOT_LOGGED_IN = "srp_status_not_logged_in" - # TODO change the name of "download_config" signal to - # something less confusing (config_ready maybe) - EIP_DOWNLOAD_CONFIG = "eip_download_config" - EIP_DOWNLOAD_CLIENT_CERTIFICATE = "eip_download_client_certificate" + EIP_CONFIG_READY = "eip_config_ready" + EIP_CLIENT_CERTIFICATE_READY = "eip_client_certificate_ready" EIP_CANCELLED_SETUP = "eip_cancelled_setup" EIP_CONNECTED = "eip_connected" @@ -739,8 +737,8 @@ class Signaler(QtCore.QObject): self.SRP_REGISTRATION_FAILED, self.SRP_REGISTRATION_TAKEN, - self.EIP_DOWNLOAD_CONFIG, - self.EIP_DOWNLOAD_CLIENT_CERTIFICATE, + self.EIP_CONFIG_READY, + self.EIP_CLIENT_CERTIFICATE_READY, self.EIP_CANCELLED_SETUP, self.EIP_CONNECTED, -- cgit v1.2.3 From fd917ed78713725c26c46c22c924d913e8b734b7 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 14 Apr 2014 16:10:09 -0300 Subject: Improve backend docstrings. * Update wording to match pep-0257 * Add docstrings for signals emitted by the Backend. --- src/leap/bitmask/backend.py | 205 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 184 insertions(+), 21 deletions(-) (limited to 'src/leap/bitmask/backend.py') diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index c71553a3..c7fc3dc4 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -82,7 +82,7 @@ class ILEAPService(ILEAPComponent): def start(self): """ - Starts the service. + Start the service. """ pass @@ -94,13 +94,13 @@ class ILEAPService(ILEAPComponent): def terminate(self): """ - Terminates the service, not necessarily in a nice way. + Terminate the service, not necessarily in a nice way. """ pass def status(self): """ - Returns a json object with the current status for the service. + Return a json object with the current status for the service. :rtype: object (list, str, dict) """ @@ -111,7 +111,7 @@ class ILEAPService(ILEAPComponent): def set_configs(self, keyval): """ - Sets the config parameters for this Service. + Set the config parameters for this Service. :param keyval: values to configure :type keyval: dict, {str: str} @@ -120,7 +120,7 @@ class ILEAPService(ILEAPComponent): def get_configs(self, keys): """ - Returns the configuration values for the list of keys. + Return the configuration values for the list of keys. :param keys: keys to retrieve :type keys: list of str @@ -158,7 +158,7 @@ class Provider(object): def setup_provider(self, provider): """ - Initiates the setup for a provider + Initiate the setup for a provider :param provider: URL for the provider :type provider: unicode @@ -280,7 +280,7 @@ class EIP(object): def setup_eip(self, domain): """ - Initiates the setup for a provider + Initiate the setup for a provider :param domain: URL for the provider :type domain: unicode @@ -308,7 +308,7 @@ class EIP(object): def _start_eip(self): """ - Starts EIP + Start EIP """ provider_config = self._provider_config eip_config = eipconfig.EIPConfig() @@ -331,7 +331,7 @@ class EIP(object): def start(self): """ - Starts the service. + Start the service. """ signaler = self._signaler @@ -366,19 +366,19 @@ class EIP(object): def stop(self, shutdown=False): """ - Stops the service. + Stop the service. """ self._vpn.terminate(shutdown) def terminate(self): """ - Terminates the service, not necessarily in a nice way. + Terminate the service, not necessarily in a nice way. """ self._vpn.killit() def status(self): """ - Returns a json object with the current status for the service. + Return a json object with the current status for the service. :rtype: object (list, str, dict) """ @@ -389,7 +389,7 @@ class EIP(object): def _provider_is_initialized(self, domain): """ - Returns if the given domain is initialized or not. + Return whether the given domain is initialized or not. :param domain: the domain to check :type domain: str @@ -405,12 +405,13 @@ class EIP(object): def get_initialized_providers(self, domains): """ - Signals a list of the given domains and if they are initialized or not. + Signal a list of the given domains and if they are initialized or not. :param domains: the list of domains to check. :type domain: list of str - :signal type: list of tuples (str, bool) + Signals: + eip_get_initialized_providers -> list of tuple(unicode, bool) """ filtered_domains = [] for domain in domains: @@ -423,12 +424,15 @@ class EIP(object): def get_gateways_list(self, domain): """ - Signals a list of gateways for the given provider. + Signal a list of gateways for the given provider. :param domain: the domain to get the gateways. :type domain: str - :signal type: list of str + Signals: + eip_get_gateways_list -> list of unicode + eip_get_gateways_list_error + eip_uninitialized_provider """ if not self._provider_is_initialized(domain): if self._signaler is not None: @@ -479,7 +483,7 @@ class Authenticate(object): def login(self, domain, username, password): """ - Executes the whole authentication process for a user + Execute the whole authentication process for a user :param domain: the domain where we need to authenticate. :type domain: unicode @@ -511,7 +515,7 @@ class Authenticate(object): def change_password(self, current_password, new_password): """ - Changes the user's password. + Change the user's password. :param current_password: the current password of the user. :type current_password: str @@ -530,7 +534,7 @@ class Authenticate(object): def logout(self): """ - Logs out the current session. + Log out the current session. Expects a session_id to exists, might raise AssertionError """ if not self._is_logged_in(): @@ -550,7 +554,7 @@ class Authenticate(object): def get_logged_in_status(self): """ - Signals if the user is currently logged in or not. + Signal if the user is currently logged in or not. """ if self._signaler is None: return @@ -947,55 +951,214 @@ class Backend(object): # send_multipart and this backend class will be really simple. def setup_provider(self, provider): + """ + Initiate the setup for a provider. + + :param provider: URL for the provider + :type provider: unicode + + Signals: + prov_unsupported_client + prov_unsupported_api + prov_name_resolution -> { PASSED_KEY: bool, ERROR_KEY: str } + prov_https_connection -> { PASSED_KEY: bool, ERROR_KEY: str } + prov_download_provider_info -> { PASSED_KEY: bool, ERROR_KEY: str } + """ self._call_queue.put(("provider", "setup_provider", None, provider)) def cancel_setup_provider(self): + """ + Cancel the ongoing setup provider (if any). + """ self._call_queue.put(("provider", "cancel_setup_provider", None)) def provider_bootstrap(self, provider): + """ + Second stage of bootstrapping for a provider. + + :param provider: URL for the provider + :type provider: unicode + + Signals: + prov_problem_with_provider + prov_download_ca_cert -> {PASSED_KEY: bool, ERROR_KEY: str} + prov_check_ca_fingerprint -> {PASSED_KEY: bool, ERROR_KEY: str} + prov_check_api_certificate -> {PASSED_KEY: bool, ERROR_KEY: str} + """ self._call_queue.put(("provider", "bootstrap", None, provider)) def register_user(self, provider, username, password): + """ + Register a user using the domain and password given as parameters. + + :param domain: the domain we need to register the user. + :type domain: unicode + :param username: the user name + :type username: unicode + :param password: the password for the username + :type password: unicode + + Signals: + srp_registration_finished + srp_registration_taken + srp_registration_failed + """ self._call_queue.put(("register", "register_user", None, provider, username, password)) def setup_eip(self, provider): + """ + Initiate the setup for a provider + + :param domain: URL for the provider + :type domain: unicode + + Signals: + eip_config_ready -> {PASSED_KEY: bool, ERROR_KEY: str} + eip_client_certificate_ready -> {PASSED_KEY: bool, ERROR_KEY: str} + eip_cancelled_setup + """ self._call_queue.put(("eip", "setup_eip", None, provider)) def cancel_setup_eip(self): + """ + Cancel the ongoing setup EIP (if any). + """ self._call_queue.put(("eip", "cancel_setup_eip", None)) def start_eip(self): + """ + Start the EIP service. + + Signals: + backend_bad_call + eip_alien_open_vpn_already_running + eip_connected + eip_connection_aborted + eip_network_unreachable + eip_no_pkexec_error + eip_no_polkit_agent_error + eip_no_tun_kext_error + eip_open_vpn_already_running + eip_open_vpn_not_found_error + eip_process_finished + eip_process_restart_ping + eip_process_restart_tls + eip_state_changed -> str + eip_status_changed -> str + eip_vpn_launcher_exception + """ self._call_queue.put(("eip", "start", None)) def stop_eip(self, shutdown=False): + """ + Stop the EIP service. + """ self._call_queue.put(("eip", "stop", None, shutdown)) def terminate_eip(self): + """ + Terminate the EIP service, not necessarily in a nice way. + """ self._call_queue.put(("eip", "terminate", None)) def eip_get_gateways_list(self, domain): + """ + Signal a list of gateways for the given provider. + + :param domain: the domain to get the gateways. + :type domain: str + + # TODO discuss how to document the expected result object received of + # the signal + :signal type: list of str + + Signals: + eip_get_gateways_list -> list of unicode + eip_get_gateways_list_error + eip_uninitialized_provider + """ self._call_queue.put(("eip", "get_gateways_list", None, domain)) def eip_get_initialized_providers(self, domains): + """ + Signal a list of the given domains and if they are initialized or not. + + :param domains: the list of domains to check. + :type domain: list of str + + Signals: + eip_get_initialized_providers -> list of tuple(unicode, bool) + + """ self._call_queue.put(("eip", "get_initialized_providers", None, domains)) def login(self, provider, username, password): + """ + Execute the whole authentication process for a user + + :param domain: the domain where we need to authenticate. + :type domain: unicode + :param username: username for this session + :type username: str + :param password: password for this user + :type password: str + + Signals: + srp_auth_error + srp_auth_ok + srp_auth_bad_user_or_password + srp_auth_server_error + srp_auth_connection_error + srp_auth_error + """ self._call_queue.put(("authenticate", "login", None, provider, username, password)) def logout(self): + """ + Log out the current session. + + Signals: + srp_logout_ok + srp_logout_error + srp_not_logged_in_error + """ self._call_queue.put(("authenticate", "logout", None)) def cancel_login(self): + """ + Cancel the ongoing login (if any). + """ self._call_queue.put(("authenticate", "cancel_login", None)) def change_password(self, current_password, new_password): + """ + Change the user's password. + + :param current_password: the current password of the user. + :type current_password: str + :param new_password: the new password for the user. + :type new_password: str + + Signals: + srp_not_logged_in_error + srp_password_change_ok + srp_password_change_badpw + srp_password_change_error + """ self._call_queue.put(("authenticate", "change_password", None, current_password, new_password)) def get_logged_in_status(self): + """ + Signal if the user is currently logged in or not. + + Signals: + srp_status_logged_in + srp_status_not_logged_in + """ self._call_queue.put(("authenticate", "get_logged_in_status", None)) ########################################################################### -- cgit v1.2.3 From 074acd22df82b732c099444cdb59df203ef996a5 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Tue, 15 Apr 2014 12:50:35 -0300 Subject: Remove unneeded parent's constructor call. --- src/leap/bitmask/backend.py | 6 ------ 1 file changed, 6 deletions(-) (limited to 'src/leap/bitmask/backend.py') diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index c7fc3dc4..ff49908f 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -149,7 +149,6 @@ class Provider(object): certificates at bootstrap :type bypass_checks: bool """ - object.__init__(self) self.key = "provider" self._provider_bootstrapper = ProviderBootstrapper(signaler, bypass_checks) @@ -224,7 +223,6 @@ class Register(object): back to the frontend :type signaler: Signaler """ - object.__init__(self) self.key = "register" self._signaler = signaler @@ -269,7 +267,6 @@ class EIP(object): back to the frontend :type signaler: Signaler """ - object.__init__(self) self.key = "eip" self._signaler = signaler self._eip_bootstrapper = EIPBootstrapper(signaler) @@ -476,7 +473,6 @@ class Authenticate(object): back to the frontend :type signaler: Signaler """ - object.__init__(self) self.key = "authenticate" self._signaler = signaler self._srp_auth = None @@ -829,8 +825,6 @@ class Backend(object): """ Constructor for the backend. """ - object.__init__(self) - # Components map for the commands received self._components = {} -- cgit v1.2.3 From eece52ff0118af412b0e2bf7a4200ebf0bca2f16 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 16 Apr 2014 12:18:31 -0300 Subject: Use authenticated() properly. --- src/leap/bitmask/backend.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/leap/bitmask/backend.py') diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index ff49908f..d208a6cd 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -546,7 +546,8 @@ class Authenticate(object): :rtype: bool """ - return self._srp_auth.is_authenticated() + return (self._srp_auth is not None and + self._srp_auth.is_authenticated()) def get_logged_in_status(self): """ -- cgit v1.2.3 From 0b5566dd599946dc73a0d8f46999ae19b2d0a9d2 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 16 Apr 2014 12:51:57 -0300 Subject: Fix typos on signal names. --- src/leap/bitmask/backend.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/leap/bitmask/backend.py') diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index d208a6cd..d5a8a4e9 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -340,11 +340,11 @@ class EIP(object): try: self._start_eip() except vpnprocess.OpenVPNAlreadyRunning: - signaler.signal(signaler.EIP_OPEN_VPN_ALREADY_RUNNING) + signaler.signal(signaler.EIP_OPENVPN_ALREADY_RUNNING) except vpnprocess.AlienOpenVPNAlreadyRunning: - signaler.signal(signaler.EIP_ALIEN_OPEN_VPN_ALREADY_RUNNING) + signaler.signal(signaler.EIP_ALIEN_OPENVPN_ALREADY_RUNNING) except vpnlauncher.OpenVPNNotFoundException: - signaler.signal(signaler.EIP_OPEN_VPN_NOT_FOUND_ERROR) + signaler.signal(signaler.EIP_OPENVPN_NOT_FOUND_ERROR) except vpnlauncher.VPNLauncherException: # TODO: this seems to be used for 'gateway not found' only. # see vpnlauncher.py @@ -1027,15 +1027,15 @@ class Backend(object): Signals: backend_bad_call - eip_alien_open_vpn_already_running + eip_alien_openvpn_already_running eip_connected eip_connection_aborted eip_network_unreachable eip_no_pkexec_error eip_no_polkit_agent_error eip_no_tun_kext_error - eip_open_vpn_already_running - eip_open_vpn_not_found_error + eip_openvpn_already_running + eip_openvpn_not_found_error eip_process_finished eip_process_restart_ping eip_process_restart_tls -- cgit v1.2.3 From 58a1381764b16ebe01639020c73d4c96632cadfa Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 23 Apr 2014 12:54:29 -0300 Subject: Swap upload/download data strings. Closes #5563. --- src/leap/bitmask/backend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/leap/bitmask/backend.py') diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index d5a8a4e9..054aec85 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -1040,7 +1040,7 @@ class Backend(object): eip_process_restart_ping eip_process_restart_tls eip_state_changed -> str - eip_status_changed -> str + eip_status_changed -> tuple of str (download, upload) eip_vpn_launcher_exception """ self._call_queue.put(("eip", "start", None)) -- cgit v1.2.3 From 9d4aa1a81af7653ed7ba5f89565f12cfea4feaea Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Fri, 25 Apr 2014 16:25:23 -0300 Subject: Initialize SRPAuth asap, so signaler gets in. Closes #5581. --- src/leap/bitmask/backend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/leap/bitmask/backend.py') diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index 054aec85..2bfcbfa0 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -475,7 +475,7 @@ class Authenticate(object): """ self.key = "authenticate" self._signaler = signaler - self._srp_auth = None + self._srp_auth = SRPAuth(ProviderConfig(), self._signaler) def login(self, domain, username, password): """ -- cgit v1.2.3 From 2f47053b631df231e4fcceafef227cf905b660cc Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Wed, 7 May 2014 09:18:23 -0500 Subject: only switch the fw down if user asked for eip down --- src/leap/bitmask/backend.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/leap/bitmask/backend.py') diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index 2bfcbfa0..bd26bb1c 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -1048,6 +1048,9 @@ class Backend(object): def stop_eip(self, shutdown=False): """ Stop the EIP service. + + :param shutdown: + :type shutdown: bool """ self._call_queue.put(("eip", "stop", None, shutdown)) -- cgit v1.2.3 From 66c94c7533a81cf9512b41090ccab4ee8360e611 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Thu, 8 May 2014 17:19:01 -0500 Subject: wait on shutdown until firewall is down --- src/leap/bitmask/backend.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'src/leap/bitmask/backend.py') diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index bd26bb1c..41fdc06e 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -17,8 +17,10 @@ """ Backend for everything """ +import commands import logging import os +import time from functools import partial from Queue import Queue, Empty @@ -32,6 +34,7 @@ import zope.interface from leap.bitmask.config.providerconfig import ProviderConfig from leap.bitmask.crypto.srpauth import SRPAuth from leap.bitmask.crypto.srpregister import SRPRegister +from leap.bitmask.platform_init import IS_LINUX from leap.bitmask.provider import get_provider_path from leap.bitmask.provider.providerbootstrapper import ProviderBootstrapper from leap.bitmask.services.eip import eipconfig @@ -366,6 +369,34 @@ class EIP(object): Stop the service. """ self._vpn.terminate(shutdown) + if IS_LINUX: + self._wait_for_firewall_down() + + def _wait_for_firewall_down(self): + """ + Wait for the firewall to come down. + """ + # Due to how we delay the resolvconf action in linux. + # XXX this *has* to wait for a reasonable lapse, since we have some + # delay in vpn.terminate. + # For a better solution it should be signaled from backend that + # everything is clear to proceed, or a timeout happened. + MAX_FW_WAIT_RETRIES = 25 + FW_WAIT_STEP = 0.5 + + retry = 0 + + fw_up_cmd = "pkexec /usr/sbin/bitmask-root firewall isup" + fw_is_down = lambda: commands.getstatusoutput(fw_up_cmd)[0] == 256 + + while retry < MAX_FW_WAIT_RETRIES: + if fw_is_down(): + return + else: + time.sleep(FW_WAIT_STEP) + retry += 1 + logger.warning("After waiting, firewall is not down... " + "You might experience lack of connectivity") def terminate(self): """ -- cgit v1.2.3 From 02b7b4a35d45671542f1e665767e9227c81207af Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Tue, 13 May 2014 01:55:28 -0500 Subject: give some time for eip to shudown on bundle. Closes: #5663 --- src/leap/bitmask/backend.py | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/leap/bitmask/backend.py') diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index 41fdc06e..a351a477 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -25,6 +25,7 @@ import time from functools import partial from Queue import Queue, Empty +from twisted.internet import reactor from twisted.internet import threads, defer from twisted.internet.task import LoopingCall from twisted.python import log @@ -899,9 +900,17 @@ class Backend(object): """ Stops the looping call and tries to cancel all the defers. """ + reactor.callLater(2, self._stop) + + def _stop(self): + """ + Delayed stopping of worker. Called from `stop`. + """ log.msg("Stopping worker...") if self._lc.running: self._lc.stop() + else: + logger.warning("Looping call is not running, cannot stop") while len(self._ongoing_defers) > 0: d = self._ongoing_defers.pop() d.cancel() -- cgit v1.2.3 From bc424a8d5c9bdd64d837e27636b4b02d8be7d582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Tue, 13 May 2014 16:15:57 -0300 Subject: Enable EIP whenever possible --- src/leap/bitmask/backend.py | 89 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 83 insertions(+), 6 deletions(-) (limited to 'src/leap/bitmask/backend.py') diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index 2bfcbfa0..8dd9f799 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -41,6 +41,8 @@ from leap.bitmask.services.eip.eipbootstrapper import EIPBootstrapper from leap.bitmask.services.eip import vpnlauncher, vpnprocess from leap.bitmask.services.eip import linuxvpnlauncher, darwinvpnlauncher +from leap.common import certs as leap_certs + # Frontend side from PySide import QtCore @@ -275,18 +277,23 @@ class EIP(object): self._vpn = vpnprocess.VPN(signaler=signaler) - def setup_eip(self, domain): + def setup_eip(self, domain, skip_network=False): """ Initiate the setup for a provider :param domain: URL for the provider :type domain: unicode + :param skip_network: Whether checks that involve network should be done + or not + :type skip_network: bool :returns: the defer for the operation running in a thread. :rtype: twisted.internet.defer.Deferred """ config = self._provider_config if get_provider_config(config, domain): + if skip_network: + return defer.Deferred() eb = self._eip_bootstrapper d = eb.run_eip_setup_checks(self._provider_config, download_if_needed=True) @@ -334,7 +341,8 @@ class EIP(object): if not self._provider_config.loaded(): # This means that the user didn't call setup_eip first. - self._signaler.signal(signaler.BACKEND_BAD_CALL) + self._signaler.signal(signaler.BACKEND_BAD_CALL, "EIP.start(), " + "no provider loaded") return try: @@ -457,6 +465,47 @@ class EIP(object): self._signaler.signal( self._signaler.EIP_GET_GATEWAYS_LIST, gateways) + def can_start(self, domain): + """ + Signal whether it has everything that is needed to run EIP or not + + :param domain: the domain for the provider to check + :type domain: str + + Signals: + eip_can_start + eip_cannot_start + """ + try: + eip_config = eipconfig.EIPConfig() + provider_config = ProviderConfig.get_provider_config(domain) + + api_version = provider_config.get_api_version() + eip_config.set_api_version(api_version) + eip_loaded = eip_config.load(eipconfig.get_eipconfig_path(domain)) + + # check for other problems + if not eip_loaded or provider_config is None: + raise Exception("Cannot load provider and eip config, cannot " + "autostart") + + client_cert_path = eip_config.\ + get_client_cert_path(provider_config, about_to_download=False) + + if leap_certs.should_redownload(client_cert_path): + raise Exception("The client should redownload the certificate," + " cannot autostart") + + if not os.path.isfile(client_cert_path): + raise Exception("Can't find the certificate, cannot autostart") + + if self._signaler is not None: + self._signaler.signal(self._signaler.EIP_CAN_START) + except Exception as e: + logger.exception(e) + if self._signaler is not None: + self._signaler.signal(self._signaler.EIP_CANNOT_START) + class Authenticate(object): """ @@ -647,6 +696,10 @@ class Signaler(QtCore.QObject): eip_status_changed = QtCore.Signal(dict) eip_process_finished = QtCore.Signal(int) + # signals whether the needed files to start EIP exist or not + eip_can_start = QtCore.Signal(object) + eip_cannot_start = QtCore.Signal(object) + # This signal is used to warn the backend user that is doing something # wrong backend_bad_call = QtCore.Signal(object) @@ -713,6 +766,9 @@ class Signaler(QtCore.QObject): EIP_STATUS_CHANGED = "eip_status_changed" EIP_PROCESS_FINISHED = "eip_process_finished" + EIP_CAN_START = "eip_can_start" + EIP_CANNOT_START = "eip_cannot_start" + BACKEND_BAD_CALL = "backend_bad_call" def __init__(self): @@ -767,6 +823,9 @@ class Signaler(QtCore.QObject): self.EIP_STATUS_CHANGED, self.EIP_PROCESS_FINISHED, + self.EIP_CAN_START, + self.EIP_CANNOT_START, + self.SRP_AUTH_OK, self.SRP_AUTH_ERROR, self.SRP_AUTH_SERVER_ERROR, @@ -1001,19 +1060,23 @@ class Backend(object): self._call_queue.put(("register", "register_user", None, provider, username, password)) - def setup_eip(self, provider): + def setup_eip(self, provider, skip_network=False): """ Initiate the setup for a provider - :param domain: URL for the provider - :type domain: unicode + :param provider: URL for the provider + :type provider: unicode + :param skip_network: Whether checks that involve network should be done + or not + :type skip_network: bool Signals: eip_config_ready -> {PASSED_KEY: bool, ERROR_KEY: str} eip_client_certificate_ready -> {PASSED_KEY: bool, ERROR_KEY: str} eip_cancelled_setup """ - self._call_queue.put(("eip", "setup_eip", None, provider)) + self._call_queue.put(("eip", "setup_eip", None, provider, + skip_network)) def cancel_setup_eip(self): """ @@ -1089,6 +1152,20 @@ class Backend(object): self._call_queue.put(("eip", "get_initialized_providers", None, domains)) + def eip_can_start(self, domain): + """ + Signal whether it has everything that is needed to run EIP or not + + :param domain: the domain for the provider to check + :type domain: str + + Signals: + eip_can_start + eip_cannot_start + """ + self._call_queue.put(("eip", "can_start", + None, domain)) + def login(self, provider, username, password): """ Execute the whole authentication process for a user -- cgit v1.2.3