summaryrefslogtreecommitdiff
path: root/src/leap
diff options
context:
space:
mode:
Diffstat (limited to 'src/leap')
-rw-r--r--src/leap/bitmask/backend.py199
-rw-r--r--src/leap/bitmask/crypto/srpauth.py139
-rw-r--r--src/leap/bitmask/crypto/srpregister.py2
-rw-r--r--src/leap/bitmask/gui/mainwindow.py121
-rw-r--r--src/leap/bitmask/gui/preferenceswindow.py150
5 files changed, 466 insertions, 145 deletions
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
diff --git a/src/leap/bitmask/crypto/srpauth.py b/src/leap/bitmask/crypto/srpauth.py
index 7cf7e55a..26a2d09a 100644
--- a/src/leap/bitmask/crypto/srpauth.py
+++ b/src/leap/bitmask/crypto/srpauth.py
@@ -30,6 +30,7 @@ from requests.adapters import HTTPAdapter
from PySide import QtCore
from twisted.internet import threads
+from twisted.internet.defer import CancelledError
from leap.bitmask.config.leapsettings import LeapSettings
from leap.bitmask.util import request_helpers as reqhelper
@@ -135,12 +136,15 @@ class SRPAuth(QtCore.QObject):
USER_SALT_KEY = 'user[password_salt]'
AUTHORIZATION_KEY = "Authorization"
- def __init__(self, provider_config):
+ def __init__(self, provider_config, signaler=None):
"""
Constructor for SRPAuth implementation
- :param server: Server to which we will authenticate
- :type server: str
+ :param provider_config: ProviderConfig needed to authenticate.
+ :type provider_config: ProviderConfig
+ :param signaler: Signaler object used to receive notifications
+ from the backend
+ :type signaler: Signaler
"""
QtCore.QObject.__init__(self)
@@ -148,6 +152,7 @@ class SRPAuth(QtCore.QObject):
"We need a provider config to authenticate")
self._provider_config = provider_config
+ self._signaler = signaler
self._settings = LeapSettings()
# **************************************************** #
@@ -448,7 +453,7 @@ class SRPAuth(QtCore.QObject):
def _threader(self, cb, res, *args, **kwargs):
return threads.deferToThread(cb, res, *args, **kwargs)
- def change_password(self, current_password, new_password):
+ def _change_password(self, current_password, new_password):
"""
Changes the password for the currently logged user if the current
password match.
@@ -499,6 +504,43 @@ class SRPAuth(QtCore.QObject):
self._password = new_password
+ def change_password(self, current_password, new_password):
+ """
+ Changes the password for the currently logged user if the current
+ password match.
+ It requires to be authenticated.
+
+ :param current_password: the current password for the logged user.
+ :type current_password: str
+ :param new_password: the new password for the user
+ :type new_password: str
+ """
+ d = threads.deferToThread(
+ self._change_password, current_password, new_password)
+ d.addCallback(self._change_password_ok)
+ d.addErrback(self._change_password_error)
+
+ def _change_password_ok(self, _):
+ """
+ Password change callback.
+ """
+ if self._signaler is not None:
+ self._signaler.signal(self._signaler.SRP_PASSWORD_CHANGE_OK)
+
+ def _change_password_error(self, failure):
+ """
+ Password change errback.
+ """
+ logger.debug(
+ "Error changing password. Failure: {0}".format(failure))
+ if self._signaler is None:
+ return
+
+ if failure.check(SRPAuthBadUserOrPassword):
+ self._signaler.signal(self._signaler.SRP_PASSWORD_CHANGE_BADPW)
+ else:
+ self._signaler.signal(self._signaler.SRP_PASSWORD_CHANGE_ERROR)
+
def authenticate(self, username, password):
"""
Executes the whole authentication process for a user
@@ -539,8 +581,49 @@ class SRPAuth(QtCore.QObject):
d.addCallback(partial(self._threader,
self._verify_session))
+ d.addCallback(self._authenticate_ok)
+ d.addErrback(self._authenticate_error)
return d
+ def _authenticate_ok(self, _):
+ """
+ Callback that notifies that the authentication was successful.
+
+ :param _: IGNORED, output from the previous callback (None)
+ :type _: IGNORED
+ """
+ logger.debug("Successful login!")
+ self._signaler.signal(self._signaler.SRP_AUTH_OK)
+
+ def _authenticate_error(self, failure):
+ """
+ Error handler for the srpauth.authenticate method.
+
+ :param failure: failure object that Twisted generates
+ :type failure: twisted.python.failure.Failure
+ """
+ logger.error("Error logging in, {0!r}".format(failure))
+
+ signal = None
+ if failure.check(CancelledError):
+ logger.debug("Defer cancelled.")
+ failure.trap(Exception)
+ return
+
+ if self._signaler is None:
+ return
+
+ if failure.check(SRPAuthBadUserOrPassword):
+ signal = self._signaler.SRP_AUTH_BAD_USER_OR_PASSWORD
+ elif failure.check(SRPAuthConnectionError):
+ signal = self._signaler.SRP_AUTH_CONNECTION_ERROR
+ elif failure.check(SRPAuthenticationError):
+ signal = self._signaler.SRP_AUTH_SERVER_ERROR
+ else:
+ signal = self._signaler.SRP_AUTH_ERROR
+
+ self._signaler.signal(signal)
+
def logout(self):
"""
Logs out the current session.
@@ -565,6 +648,8 @@ class SRPAuth(QtCore.QObject):
except Exception as e:
logger.warning("Something went wrong with the logout: %r" %
(e,))
+ if self._signaler is not None:
+ self._signaler.signal(self._signaler.SRP_LOGOUT_ERROR)
raise
else:
self.set_session_id(None)
@@ -573,6 +658,8 @@ class SRPAuth(QtCore.QObject):
# Also reset the session
self._session = self._fetcher.session()
logger.debug("Successfully logged out.")
+ if self._signaler is not None:
+ self._signaler.signal(self._signaler.SRP_LOGOUT_OK)
def set_session_id(self, session_id):
QtCore.QMutexLocker(self._session_id_lock)
@@ -604,20 +691,22 @@ class SRPAuth(QtCore.QObject):
__instance = None
- authentication_finished = QtCore.Signal()
- logout_ok = QtCore.Signal()
- logout_error = QtCore.Signal()
-
- def __init__(self, provider_config):
+ def __init__(self, provider_config, signaler=None):
"""
- Creates a singleton instance if needed
+ Create a singleton instance if needed
+
+ :param provider_config: ProviderConfig needed to authenticate.
+ :type provider_config: ProviderConfig
+ :param signaler: Signaler object used to send notifications
+ from the backend
+ :type signaler: Signaler
"""
QtCore.QObject.__init__(self)
# Check whether we already have an instance
if SRPAuth.__instance is None:
# Create and remember instance
- SRPAuth.__instance = SRPAuth.__impl(provider_config)
+ SRPAuth.__instance = SRPAuth.__impl(provider_config, signaler)
# Store instance reference as the only member in the handle
self.__dict__['_SRPAuth__instance'] = SRPAuth.__instance
@@ -642,9 +731,20 @@ class SRPAuth(QtCore.QObject):
"""
username = username.lower()
d = self.__instance.authenticate(username, password)
- d.addCallback(self._gui_notify)
return d
+ def is_authenticated(self):
+ """
+ Return whether the user is authenticated or not.
+
+ :rtype: bool
+ """
+ user = self.__instance._srp_user
+ if user is not None:
+ return self.__instance.authenticated()
+
+ return False
+
def change_password(self, current_password, new_password):
"""
Changes the user's password.
@@ -657,8 +757,7 @@ class SRPAuth(QtCore.QObject):
:returns: a defer to interact with.
:rtype: twisted.internet.defer.Deferred
"""
- d = threads.deferToThread(
- self.__instance.change_password, current_password, new_password)
+ d = self.__instance.change_password(current_password, new_password)
return d
def get_username(self):
@@ -672,16 +771,6 @@ class SRPAuth(QtCore.QObject):
return None
return self.__instance._username
- def _gui_notify(self, _):
- """
- Callback that notifies the UI with the proper signal.
-
- :param _: IGNORED, output from the previous callback (None)
- :type _: IGNORED
- """
- logger.debug("Successful login!")
- self.authentication_finished.emit()
-
def get_session_id(self):
return self.__instance.get_session_id()
@@ -699,9 +788,7 @@ class SRPAuth(QtCore.QObject):
try:
self.__instance.logout()
logger.debug("Logout success")
- self.logout_ok.emit()
return True
except Exception as e:
logger.debug("Logout error: {0!r}".format(e))
- self.logout_error.emit()
return False
diff --git a/src/leap/bitmask/crypto/srpregister.py b/src/leap/bitmask/crypto/srpregister.py
index 4c52db42..f03dc469 100644
--- a/src/leap/bitmask/crypto/srpregister.py
+++ b/src/leap/bitmask/crypto/srpregister.py
@@ -46,8 +46,6 @@ class SRPRegister(QtCore.QObject):
STATUS_TAKEN = 422
STATUS_ERROR = -999 # Custom error status
- registration_finished = QtCore.Signal(bool, object)
-
def __init__(self, signaler=None,
provider_config=None, register_path="users"):
"""
diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py
index 61aff5f9..492ea125 100644
--- a/src/leap/bitmask/gui/mainwindow.py
+++ b/src/leap/bitmask/gui/mainwindow.py
@@ -20,13 +20,13 @@ Main window for Bitmask.
import logging
import socket
+from functools import partial
from threading import Condition
from datetime import datetime
from PySide import QtCore, QtGui
from zope.proxy import ProxyBase, setProxiedObject
from twisted.internet import reactor, threads
-from twisted.internet.defer import CancelledError
from leap.bitmask import __version__ as VERSION
from leap.bitmask import __version_hash__ as VERSION_HASH
@@ -34,9 +34,6 @@ from leap.bitmask.config import flags
from leap.bitmask.config.leapsettings import LeapSettings
from leap.bitmask.config.providerconfig import ProviderConfig
-from leap.bitmask.crypto import srpauth
-from leap.bitmask.crypto.srpauth import SRPAuth
-
from leap.bitmask.gui.loggerwindow import LoggerWindow
from leap.bitmask.gui.advanced_key_management import AdvancedKeyManagement
from leap.bitmask.gui.login import LoginWidget
@@ -213,8 +210,8 @@ class MainWindow(QtGui.QMainWindow):
# than once
# XXX HACK!! But we need it as long as we are using
# provider_config in here
- self._provider_config = (
- self._backend._components["provider"]._provider_config)
+ self._provider_config = self._backend.get_provider_config()
+
# Used for automatic start of EIP
self._provisional_provider_config = ProviderConfig()
self._eip_config = eipconfig.EIPConfig()
@@ -342,7 +339,6 @@ class MainWindow(QtGui.QMainWindow):
self._soledad = ProxyBase(None)
self._keymanager = ProxyBase(None)
- self._login_defer = None
self._soledad_defer = None
self._mail_conductor = mail_conductor.MailConductor(
@@ -377,6 +373,18 @@ class MainWindow(QtGui.QMainWindow):
# so this has to be done after eip_machine is started
self._finish_init()
+ def _not_logged_in_error(self):
+ """
+ Handle the 'not logged in' backend error if we try to do an operation
+ that requires to be logged in.
+ """
+ logger.critical("You are trying to do an operation that requires "
+ "log in first.")
+ QtGui.QMessageBox.critical(
+ self, self.tr("Application error"),
+ self.tr("You are trying to do an operation "
+ "that requires logging in first."))
+
def _backend_connect(self):
"""
Helper to connect to backend signals
@@ -401,6 +409,34 @@ class MainWindow(QtGui.QMainWindow):
sig.eip_download_config.connect(self._eip_intermediate_stage)
sig.eip_download_client_certificate.connect(self._finish_eip_bootstrap)
+ # Authentication related signals
+ sig.srp_auth_ok.connect(self._authentication_finished)
+
+ auth_error = partial(
+ self._authentication_error,
+ self.tr("Unknown error."))
+ sig.srp_auth_error.connect(auth_error)
+
+ auth_server_error = partial(
+ self._authentication_error,
+ self.tr("There was a server problem with authentication."))
+ sig.srp_auth_server_error.connect(auth_server_error)
+
+ auth_connection_error = partial(
+ self._authentication_error,
+ self.tr("Could not establish a connection."))
+ sig.srp_auth_connection_error.connect(auth_connection_error)
+
+ auth_bad_user_or_password = partial(
+ self._authentication_error,
+ self.tr("Invalid username or password."))
+ sig.srp_auth_bad_user_or_password.connect(auth_bad_user_or_password)
+
+ sig.srp_logout_ok.connect(self._logout_ok)
+ sig.srp_logout_error.connect(self._logout_error)
+
+ sig.srp_not_logged_in_error.connect(self._not_logged_in_error)
+
def _backend_disconnect(self):
"""
Helper to disconnect from backend signals.
@@ -538,7 +574,7 @@ class MainWindow(QtGui.QMainWindow):
Displays the preferences window.
"""
preferences = PreferencesWindow(
- self, self._srp_auth, self._provider_config, self._soledad,
+ self, self._backend, self._provider_config, self._soledad,
self._login_widget.get_selected_provider())
self.soledad_ready.connect(preferences.set_soledad_ready)
@@ -1050,39 +1086,20 @@ class MainWindow(QtGui.QMainWindow):
if self._login_widget.start_login():
self._download_provider_config()
- def _login_errback(self, failure):
- """
- Error handler for the srpauth.authenticate method.
-
- :param failure: failure object that Twisted generates
- :type failure: twisted.python.failure.Failure
+ def _authentication_error(self, msg):
"""
- # NOTE: this behavior needs to be managed through the signaler,
- # as we are doing with the prov_cancelled_setup signal.
- # After we move srpauth to the backend, we need to update this.
- logger.error("Error logging in, {0!r}".format(failure))
+ SLOT
+ TRIGGERS:
+ Signaler.srp_auth_error
+ Signaler.srp_auth_server_error
+ Signaler.srp_auth_connection_error
+ Signaler.srp_auth_bad_user_or_password
- if failure.check(CancelledError):
- logger.debug("Defer cancelled.")
- failure.trap(Exception)
- self._set_login_cancelled()
- return
- elif failure.check(srpauth.SRPAuthBadUserOrPassword):
- msg = self.tr("Invalid username or password.")
- elif failure.check(srpauth.SRPAuthBadStatusCode,
- srpauth.SRPAuthenticationError,
- srpauth.SRPAuthVerificationFailed,
- srpauth.SRPAuthNoSessionId,
- srpauth.SRPAuthNoSalt, srpauth.SRPAuthNoB,
- srpauth.SRPAuthBadDataFromServer,
- srpauth.SRPAuthJSONDecodeError):
- msg = self.tr("There was a server problem with authentication.")
- elif failure.check(srpauth.SRPAuthConnectionError):
- msg = self.tr("Could not establish a connection.")
- else:
- # this shouldn't happen, but just in case.
- msg = self.tr("Unknown error: {0!r}".format(failure.value))
+ Handle the authentication errors.
+ :param msg: the message to show to the user.
+ :type msg: unicode
+ """
self._login_widget.set_status(msg)
self._login_widget.set_enabled(True)
@@ -1101,12 +1118,9 @@ class MainWindow(QtGui.QMainWindow):
"""
Cancel the running defers to avoid app blocking.
"""
+ # XXX: Should we stop all the backend defers?
self._backend.cancel_setup_provider()
-
- if self._login_defer is not None:
- logger.debug("Cancelling login defer.")
- self._login_defer.cancel()
- self._login_defer = None
+ self._backend.cancel_login()
if self._soledad_defer is not None:
logger.debug("Cancelling soledad defer.")
@@ -1142,15 +1156,8 @@ class MainWindow(QtGui.QMainWindow):
self._hide_unsupported_services()
- if self._srp_auth is None:
- self._srp_auth = SRPAuth(self._provider_config)
- self._srp_auth.authentication_finished.connect(
- self._authentication_finished)
- self._srp_auth.logout_ok.connect(self._logout_ok)
- self._srp_auth.logout_error.connect(self._logout_error)
-
- self._login_defer = self._srp_auth.authenticate(username, password)
- self._login_defer.addErrback(self._login_errback)
+ domain = self._provider_config.get_domain()
+ self._backend.login(domain, username, password)
else:
self._login_widget.set_status(
"Unable to login: Problem with provider")
@@ -1172,7 +1179,6 @@ class MainWindow(QtGui.QMainWindow):
domain = self._provider_config.get_domain()
full_user_id = make_address(user, domain)
self._mail_conductor.userid = full_user_id
- self._login_defer = None
self._start_eip_bootstrap()
# if soledad/mail is enabled:
@@ -1916,7 +1922,7 @@ class MainWindow(QtGui.QMainWindow):
# XXX: If other defers are doing authenticated stuff, this
# might conflict with those. CHECK!
- threads.deferToThread(self._srp_auth.logout)
+ self._backend.logout()
self.logout.emit()
def _logout_error(self):
@@ -2017,11 +2023,8 @@ class MainWindow(QtGui.QMainWindow):
self._stop_imap_service()
- if self._srp_auth is not None:
- if self._srp_auth.get_session_id() is not None or \
- self._srp_auth.get_token() is not None:
- # XXX this can timeout after loong time: See #3368
- self._srp_auth.logout()
+ if self._logged_user is not None:
+ self._backend.logout()
if self._soledad_bootstrapper.soledad is not None:
logger.debug("Closing soledad...")
diff --git a/src/leap/bitmask/gui/preferenceswindow.py b/src/leap/bitmask/gui/preferenceswindow.py
index b2cc2236..f6bd1ed3 100644
--- a/src/leap/bitmask/gui/preferenceswindow.py
+++ b/src/leap/bitmask/gui/preferenceswindow.py
@@ -29,7 +29,6 @@ from leap.bitmask.provider import get_provider_path
from leap.bitmask.config.leapsettings import LeapSettings
from leap.bitmask.gui.ui_preferences import Ui_Preferences
from leap.soledad.client import NoStorageSecret
-from leap.bitmask.crypto.srpauth import SRPAuthBadUserOrPassword
from leap.bitmask.util.password import basic_password_checks
from leap.bitmask.services import get_supported
from leap.bitmask.config.providerconfig import ProviderConfig
@@ -44,12 +43,12 @@ class PreferencesWindow(QtGui.QDialog):
"""
preferences_saved = QtCore.Signal()
- def __init__(self, parent, srp_auth, provider_config, soledad, domain):
+ def __init__(self, parent, backend, provider_config, soledad, domain):
"""
:param parent: parent object of the PreferencesWindow.
:parent type: QWidget
- :param srp_auth: SRPAuth object configured in the main app.
- :type srp_auth: SRPAuth
+ :param backend: Backend being used
+ :type backend: Backend
:param provider_config: ProviderConfig object.
:type provider_config: ProviderConfig
:param soledad: Soledad instance
@@ -60,9 +59,13 @@ class PreferencesWindow(QtGui.QDialog):
QtGui.QDialog.__init__(self, parent)
self.AUTOMATIC_GATEWAY_LABEL = self.tr("Automatic")
- self._srp_auth = srp_auth
+ self._backend = backend
self._settings = LeapSettings()
self._soledad = soledad
+ self._provider_config = provider_config
+ self._domain = domain
+
+ self._backend_connect()
# Load UI
self.ui = Ui_Preferences()
@@ -82,40 +85,57 @@ class PreferencesWindow(QtGui.QDialog):
else:
self._add_configured_providers()
- pw_enabled = False
-
- # check if the user is logged in
- if srp_auth is not None and srp_auth.get_token() is not None:
- # check if provider has 'mx' ...
- if provider_config.provides_mx():
- enabled_services = self._settings.get_enabled_services(domain)
- mx_name = get_service_display_name(MX_SERVICE)
-
- # ... and if the user have it enabled
- if MX_SERVICE not in enabled_services:
- msg = self.tr("You need to enable {0} in order to change "
- "the password.".format(mx_name))
- self._set_password_change_status(msg, error=True)
- else:
- if sameProxiedObjects(self._soledad, None):
- msg = self.tr(
- "You need to wait until {0} is ready in "
- "order to change the password.".format(mx_name))
- self._set_password_change_status(msg)
- else:
- # Soledad is bootstrapped
- pw_enabled = True
- else:
- pw_enabled = True
- else:
- msg = self.tr(
- "In order to change your password you need to be logged in.")
- self._set_password_change_status(msg)
+ self._backend.get_logged_in_status()
self._select_provider_by_name(domain)
+ def _is_logged_in(self):
+ """
+ SLOT
+ TRIGGERS:
+ Signaler.srp_status_logged_in
+
+ Actions to perform is the user is logged in.
+ """
+ settings = self._settings
+ pw_enabled = True
+
+ # check if provider has 'mx' ...
+ # TODO: we should move this to the backend.
+ if self._provider_config.provides_mx():
+ enabled_services = settings.get_enabled_services(self._domain)
+ mx_name = get_service_display_name(MX_SERVICE)
+
+ # ... and if the user have it enabled
+ if MX_SERVICE not in enabled_services:
+ msg = self.tr("You need to enable {0} in order to change "
+ "the password.".format(mx_name))
+ self._set_password_change_status(msg, error=True)
+ pw_enabled = False
+ else:
+ # check if Soledad is bootstrapped
+ if sameProxiedObjects(self._soledad, None):
+ msg = self.tr(
+ "You need to wait until {0} is ready in "
+ "order to change the password.".format(mx_name))
+ self._set_password_change_status(msg)
+ pw_enabled = False
+
self.ui.gbPasswordChange.setEnabled(pw_enabled)
+ def _not_logged_in(self):
+ """
+ SLOT
+ TRIGGERS:
+ Signaler.srp_status_not_logged_in
+
+ Actions to perform if the user is not logged in.
+ """
+ msg = self.tr(
+ "In order to change your password you need to be logged in.")
+ self._set_password_change_status(msg)
+ self.ui.gbPasswordChange.setEnabled(False)
+
def set_soledad_ready(self):
"""
SLOT
@@ -185,19 +205,17 @@ class PreferencesWindow(QtGui.QDialog):
return
self._set_changing_password(True)
- d = self._srp_auth.change_password(current_password, new_password)
- d.addCallback(partial(self._change_password_success, new_password))
- d.addErrback(self._change_password_problem)
+ self._backend.change_password(current_password, new_password)
- def _change_password_success(self, new_password, _):
+ def _change_password_ok(self):
"""
- Callback used to display a successfully performed action.
+ SLOT
+ TRIGGERS:
+ self._backend.signaler.srp_password_change_ok
- :param new_password: the new password for the user.
- :type new_password: str.
- :param _: the returned data from self._srp_auth.change_password
- Ignored
+ Callback used to display a successfully changed password.
"""
+ new_password = self.ui.leNewPassword.text()
logger.debug("SRP password changed successfully.")
try:
self._soledad.change_passphrase(new_password)
@@ -211,24 +229,21 @@ class PreferencesWindow(QtGui.QDialog):
self._clear_password_inputs()
self._set_changing_password(False)
- def _change_password_problem(self, failure):
- """
- Errback called if there was a problem with the deferred.
- Also is used to display an error message.
-
- :param failure: the cause of the method failed.
- :type failure: twisted.python.Failure
+ def _change_password_problem(self, msg):
"""
- logger.error("Error changing password: %s", (failure, ))
- problem = self.tr("There was a problem changing the password.")
-
- if failure.check(SRPAuthBadUserOrPassword):
- problem = self.tr("You did not enter a correct current password.")
+ SLOT
+ TRIGGERS:
+ self._backend.signaler.srp_password_change_error
+ self._backend.signaler.srp_password_change_badpw
- self._set_password_change_status(problem, error=True)
+ Callback used to display an error on changing password.
+ :param msg: the message to show to the user.
+ :type msg: unicode
+ """
+ logger.error("Error changing password")
+ self._set_password_change_status(msg, error=True)
self._set_changing_password(False)
- failure.trap(Exception)
def _clear_password_inputs(self):
"""
@@ -387,3 +402,24 @@ class PreferencesWindow(QtGui.QDialog):
provider_config = None
return provider_config
+
+ def _backend_connect(self):
+ """
+ Helper to connect to backend signals
+ """
+ sig = self._backend.signaler
+
+ sig.srp_status_logged_in.connect(self._is_logged_in)
+ sig.srp_status_not_logged_in.connect(self._not_logged_in)
+
+ sig.srp_password_change_ok.connect(self._change_password_ok)
+
+ pwd_change_error = partial(
+ self._change_password_problem,
+ self.tr("There was a problem changing the password."))
+ sig.srp_password_change_error.connect(pwd_change_error)
+
+ pwd_change_badpw = partial(
+ self._change_password_problem,
+ self.tr("You did not enter a correct current password."))
+ sig.srp_password_change_badpw.connect(pwd_change_badpw)