diff options
Diffstat (limited to 'src/leap/bitmask/crypto/srpauth.py')
-rw-r--r-- | src/leap/bitmask/crypto/srpauth.py | 195 |
1 files changed, 143 insertions, 52 deletions
diff --git a/src/leap/bitmask/crypto/srpauth.py b/src/leap/bitmask/crypto/srpauth.py index 7cf7e55a..192a9d5c 100644 --- a/src/leap/bitmask/crypto/srpauth.py +++ b/src/leap/bitmask/crypto/srpauth.py @@ -17,6 +17,7 @@ import binascii import logging +import threading import sys import requests @@ -28,8 +29,8 @@ from simplejson.decoder import JSONDecodeError from functools import partial 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 @@ -117,12 +118,12 @@ class SRPAuthNoSessionId(SRPAuthenticationError): pass -class SRPAuth(QtCore.QObject): +class SRPAuth(object): """ SRPAuth singleton """ - class __impl(QtCore.QObject): + class __impl(object): """ Implementation of the SRPAuth interface """ @@ -135,19 +136,21 @@ 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) - leap_assert(provider_config, "We need a provider config to authenticate") self._provider_config = provider_config + self._signaler = signaler self._settings = LeapSettings() # **************************************************** # @@ -162,11 +165,11 @@ class SRPAuth(QtCore.QObject): self._reset_session() self._session_id = None - self._session_id_lock = QtCore.QMutex() + self._session_id_lock = threading.Lock() self._uuid = None - self._uuid_lock = QtCore.QMutex() + self._uuid_lock = threading.Lock() self._token = None - self._token_lock = QtCore.QMutex() + self._token_lock = threading.Lock() self._srp_user = None self._srp_a = None @@ -448,7 +451,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 +502,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 +579,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 +646,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,51 +656,65 @@ 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) - self._session_id = session_id + with self._session_id_lock: + self._session_id = session_id def get_session_id(self): - QtCore.QMutexLocker(self._session_id_lock) - return self._session_id + with self._session_id_lock: + return self._session_id def set_uuid(self, uuid): - QtCore.QMutexLocker(self._uuid_lock) - full_uid = "%s@%s" % ( - self._username, self._provider_config.get_domain()) - if uuid is not None: # avoid removing the uuid from settings - self._settings.set_uuid(full_uid, uuid) - self._uuid = uuid + with self._uuid_lock: + full_uid = "%s@%s" % ( + self._username, self._provider_config.get_domain()) + if uuid is not None: # avoid removing the uuid from settings + self._settings.set_uuid(full_uid, uuid) + self._uuid = uuid def get_uuid(self): - QtCore.QMutexLocker(self._uuid_lock) - return self._uuid + with self._uuid_lock: + return self._uuid def set_token(self, token): - QtCore.QMutexLocker(self._token_lock) - self._token = token + with self._token_lock: + self._token = token def get_token(self): - QtCore.QMutexLocker(self._token_lock) - return self._token + with self._token_lock: + return self._token - __instance = None + def is_authenticated(self): + """ + Return whether the user is authenticated or not. - authentication_finished = QtCore.Signal() - logout_ok = QtCore.Signal() - logout_error = QtCore.Signal() + :rtype: bool + """ + user = self._srp_user + if user is not None: + return user.authenticated() - def __init__(self, provider_config): - """ - Creates a singleton instance if needed + return False + + __instance = None + + def __init__(self, provider_config, signaler=None): """ - QtCore.QObject.__init__(self) + 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 + """ # 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 +739,16 @@ 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 + """ + return self.__instance.is_authenticated() + def change_password(self, current_password, new_password): """ Changes the user's password. @@ -657,8 +761,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 +775,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 +792,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 |