diff options
author | Tomás Touceda <chiiph@leap.se> | 2014-04-04 16:58:18 -0300 |
---|---|---|
committer | Tomás Touceda <chiiph@leap.se> | 2014-04-04 16:58:18 -0300 |
commit | 81715dc47d77934c4f67d2527a56c28f58f0345d (patch) | |
tree | 6e66940af735e089803c5ce05ad1ce1df16c9d1e /src/leap/bitmask/crypto | |
parent | 496036f15cf257d16b6594770812da64a249280c (diff) | |
parent | eb4cdab9c6b8ff66bb4667cc6195d2c366122540 (diff) |
Merge branch 'release-0.5.0'
Diffstat (limited to 'src/leap/bitmask/crypto')
-rw-r--r-- | src/leap/bitmask/crypto/srpauth.py | 128 | ||||
-rw-r--r-- | src/leap/bitmask/crypto/srpregister.py | 63 | ||||
-rwxr-xr-x | src/leap/bitmask/crypto/tests/fake_provider.py | 1 | ||||
-rw-r--r-- | src/leap/bitmask/crypto/tests/test_srpauth.py | 8 |
4 files changed, 109 insertions, 91 deletions
diff --git a/src/leap/bitmask/crypto/srpauth.py b/src/leap/bitmask/crypto/srpauth.py index 85b9b003..7cf7e55a 100644 --- a/src/leap/bitmask/crypto/srpauth.py +++ b/src/leap/bitmask/crypto/srpauth.py @@ -31,6 +31,7 @@ from requests.adapters import HTTPAdapter from PySide import QtCore from twisted.internet import threads +from leap.bitmask.config.leapsettings import LeapSettings from leap.bitmask.util import request_helpers as reqhelper from leap.bitmask.util.compat import requests_has_max_retries from leap.bitmask.util.constants import REQUEST_TIMEOUT @@ -147,6 +148,7 @@ class SRPAuth(QtCore.QObject): "We need a provider config to authenticate") self._provider_config = provider_config + self._settings = LeapSettings() # **************************************************** # # Dependency injection helpers, override this for more @@ -161,17 +163,14 @@ class SRPAuth(QtCore.QObject): self._session_id = None self._session_id_lock = QtCore.QMutex() - self._uid = None - self._uid_lock = QtCore.QMutex() + self._uuid = None + self._uuid_lock = QtCore.QMutex() self._token = None self._token_lock = QtCore.QMutex() self._srp_user = None self._srp_a = None - # Error msg displayed if the username or the password is invalid - self._WRONG_USER_PASS = self.tr("Invalid username or password.") - # User credentials stored for password changing checks self._username = None self._password = None @@ -265,14 +264,11 @@ class SRPAuth(QtCore.QObject): # Clean up A value, we don't need it anymore self._srp_a = None except requests.exceptions.ConnectionError as e: - logger.error("No connection made (salt): %r" % - (e,)) - raise SRPAuthConnectionError("Could not establish a " - "connection") + logger.error("No connection made (salt): {0!r}".format(e)) + raise SRPAuthConnectionError() except Exception as e: logger.error("Unknown error: %r" % (e,)) - raise SRPAuthenticationError("Unknown error: %r" % - (e,)) + raise SRPAuthenticationError() content, mtime = reqhelper.get_content(init_session) @@ -281,23 +277,22 @@ class SRPAuth(QtCore.QObject): "Status code = %r. Content: %r" % (init_session.status_code, content)) if init_session.status_code == 422: - raise SRPAuthBadUserOrPassword(self._WRONG_USER_PASS) + logger.error("Invalid username or password.") + raise SRPAuthBadUserOrPassword() - raise SRPAuthBadStatusCode(self.tr("There was a problem with" - " authentication")) + logger.error("There was a problem with authentication.") + raise SRPAuthBadStatusCode() json_content = json.loads(content) salt = json_content.get("salt", None) B = json_content.get("B", None) if salt is None: - logger.error("No salt parameter sent") - raise SRPAuthNoSalt(self.tr("The server did not send " - "the salt parameter")) + logger.error("The server didn't send the salt parameter.") + raise SRPAuthNoSalt() if B is None: - logger.error("No B parameter sent") - raise SRPAuthNoB(self.tr("The server did not send " - "the B parameter")) + logger.error("The server didn't send the B parameter.") + raise SRPAuthNoB() return salt, B @@ -328,8 +323,7 @@ class SRPAuth(QtCore.QObject): unhex_B = self._safe_unhexlify(B) except (TypeError, ValueError) as e: logger.error("Bad data from server: %r" % (e,)) - raise SRPAuthBadDataFromServer( - self.tr("The data sent from the server had errors")) + raise SRPAuthBadDataFromServer() M = self._srp_user.process_challenge(unhex_salt, unhex_B) auth_url = "%s/%s/%s/%s" % (self._provider_config.get_api_uri(), @@ -350,13 +344,13 @@ class SRPAuth(QtCore.QObject): timeout=REQUEST_TIMEOUT) except requests.exceptions.ConnectionError as e: logger.error("No connection made (HAMK): %r" % (e,)) - raise SRPAuthConnectionError(self.tr("Could not connect to " - "the server")) + raise SRPAuthConnectionError() try: content, mtime = reqhelper.get_content(auth_result) except JSONDecodeError: - raise SRPAuthJSONDecodeError("Bad JSON content in auth result") + logger.error("Bad JSON content in auth result.") + raise SRPAuthJSONDecodeError() if auth_result.status_code == 422: error = "" @@ -370,14 +364,13 @@ class SRPAuth(QtCore.QObject): "received: %s", (content,)) logger.error("[%s] Wrong password (HAMK): [%s]" % (auth_result.status_code, error)) - raise SRPAuthBadUserOrPassword(self._WRONG_USER_PASS) + raise SRPAuthBadUserOrPassword() if auth_result.status_code not in (200,): logger.error("No valid response (HAMK): " "Status code = %s. Content = %r" % (auth_result.status_code, content)) - raise SRPAuthBadStatusCode(self.tr("Unknown error (%s)") % - (auth_result.status_code,)) + raise SRPAuthBadStatusCode() return json.loads(content) @@ -394,24 +387,22 @@ class SRPAuth(QtCore.QObject): """ try: M2 = json_content.get("M2", None) - uid = json_content.get("id", None) + uuid = json_content.get("id", None) token = json_content.get("token", None) except Exception as e: logger.error(e) - raise SRPAuthBadDataFromServer("Something went wrong with the " - "login") + raise SRPAuthBadDataFromServer() - self.set_uid(uid) + self.set_uuid(uuid) self.set_token(token) - if M2 is None or self.get_uid() is None: + if M2 is None or self.get_uuid() is None: logger.error("Something went wrong. Content = %r" % (json_content,)) - raise SRPAuthBadDataFromServer(self.tr("Problem getting data " - "from server")) + raise SRPAuthBadDataFromServer() events_signal( - proto.CLIENT_UID, content=uid, + proto.CLIENT_UID, content=uuid, reqcbk=lambda req, res: None) # make the rpc call async return M2 @@ -434,22 +425,19 @@ class SRPAuth(QtCore.QObject): unhex_M2 = self._safe_unhexlify(M2) except TypeError: logger.error("Bad data from server (HAWK)") - raise SRPAuthBadDataFromServer(self.tr("Bad data from server")) + raise SRPAuthBadDataFromServer() self._srp_user.verify_session(unhex_M2) if not self._srp_user.authenticated(): - logger.error("Auth verification failed") - raise SRPAuthVerificationFailed(self.tr("Auth verification " - "failed")) + logger.error("Auth verification failed.") + raise SRPAuthVerificationFailed() logger.debug("Session verified.") session_id = self._session.cookies.get(self.SESSION_ID_KEY, None) if not session_id: logger.error("Bad cookie from server (missing _session_id)") - raise SRPAuthNoSessionId(self.tr("Session cookie " - "verification " - "failed")) + raise SRPAuthNoSessionId() events_signal( proto.CLIENT_SESSION_ID, content=session_id, @@ -475,7 +463,7 @@ class SRPAuth(QtCore.QObject): :param new_password: the new password for the user :type new_password: str """ - leap_assert(self.get_uid() is not None) + leap_assert(self.get_uuid() is not None) if current_password != self._password: raise SRPAuthBadUserOrPassword @@ -483,7 +471,7 @@ class SRPAuth(QtCore.QObject): url = "%s/%s/users/%s.json" % ( self._provider_config.get_api_uri(), self._provider_config.get_api_version(), - self.get_uid()) + self.get_uuid()) salt, verifier = self._srp.create_salted_verification_key( self._username.encode('utf-8'), new_password.encode('utf-8'), @@ -580,7 +568,7 @@ class SRPAuth(QtCore.QObject): raise else: self.set_session_id(None) - self.set_uid(None) + self.set_uuid(None) self.set_token(None) # Also reset the session self._session = self._fetcher.session() @@ -594,13 +582,17 @@ class SRPAuth(QtCore.QObject): QtCore.QMutexLocker(self._session_id_lock) return self._session_id - def set_uid(self, uid): - QtCore.QMutexLocker(self._uid_lock) - self._uid = uid + 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 - def get_uid(self): - QtCore.QMutexLocker(self._uid_lock) - return self._uid + def get_uuid(self): + QtCore.QMutexLocker(self._uuid_lock) + return self._uuid def set_token(self, token): QtCore.QMutexLocker(self._token_lock) @@ -612,8 +604,9 @@ class SRPAuth(QtCore.QObject): __instance = None - authentication_finished = QtCore.Signal(bool, str) - logout_finished = QtCore.Signal(bool, str) + authentication_finished = QtCore.Signal() + logout_ok = QtCore.Signal() + logout_error = QtCore.Signal() def __init__(self, provider_config): """ @@ -650,7 +643,6 @@ class SRPAuth(QtCore.QObject): username = username.lower() d = self.__instance.authenticate(username, password) d.addCallback(self._gui_notify) - d.addErrback(self._errback) return d def change_password(self, current_password, new_password): @@ -676,7 +668,7 @@ class SRPAuth(QtCore.QObject): :rtype: str or None """ - if self.get_uid() is None: + if self.get_uuid() is None: return None return self.__instance._username @@ -688,25 +680,13 @@ class SRPAuth(QtCore.QObject): :type _: IGNORED """ logger.debug("Successful login!") - self.authentication_finished.emit(True, self.tr("Succeeded")) - - def _errback(self, failure): - """ - General errback for the whole login process. Will notify the - UI with the proper signal. - - :param failure: Failure object captured from a callback. - :type failure: twisted.python.failure.Failure - """ - logger.error("Error logging in %s" % (failure,)) - self.authentication_finished.emit(False, "%s" % (failure.value,)) - failure.trap(Exception) + self.authentication_finished.emit() def get_session_id(self): return self.__instance.get_session_id() - def get_uid(self): - return self.__instance.get_uid() + def get_uuid(self): + return self.__instance.get_uuid() def get_token(self): return self.__instance.get_token() @@ -718,8 +698,10 @@ class SRPAuth(QtCore.QObject): """ try: self.__instance.logout() - self.logout_finished.emit(True, self.tr("Succeeded")) + logger.debug("Logout success") + self.logout_ok.emit() return True except Exception as e: - self.logout_finished.emit(False, "%s" % (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 02a1ea63..4c52db42 100644 --- a/src/leap/bitmask/crypto/srpregister.py +++ b/src/leap/bitmask/crypto/srpregister.py @@ -16,6 +16,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. import binascii +import json import logging import requests @@ -26,6 +27,7 @@ from urlparse import urlparse from leap.bitmask.config.providerconfig import ProviderConfig from leap.bitmask.util.constants import SIGNUP_TIMEOUT +from leap.bitmask.util.request_helpers import get_content from leap.common.check import leap_assert, leap_assert_type logger = logging.getLogger(__name__) @@ -40,16 +42,22 @@ class SRPRegister(QtCore.QObject): USER_VERIFIER_KEY = 'user[password_verifier]' USER_SALT_KEY = 'user[password_salt]' + STATUS_OK = (200, 201) + STATUS_TAKEN = 422 + STATUS_ERROR = -999 # Custom error status + registration_finished = QtCore.Signal(bool, object) - def __init__(self, - provider_config=None, - register_path="users"): + def __init__(self, signaler=None, + provider_config=None, register_path="users"): """ Constructor + :param signaler: Signaler object used to receive notifications + from the backend + :type signaler: Signaler :param provider_config: provider configuration instance, - properly loaded + properly loaded :type privider_config: ProviderConfig :param register_path: webapp path for registering users :type register_path; str @@ -59,6 +67,7 @@ class SRPRegister(QtCore.QObject): leap_assert_type(provider_config, ProviderConfig) self._provider_config = provider_config + self._signaler = signaler # **************************************************** # # Dependency injection helpers, override this for more @@ -104,8 +113,8 @@ class SRPRegister(QtCore.QObject): :param password: password for this username :type password: str - :rtype: tuple - :rparam: (ok, request) + :returns: if the registration went ok or not. + :rtype: bool """ username = username.lower().encode('utf-8') @@ -129,11 +138,7 @@ class SRPRegister(QtCore.QObject): logger.debug("Will try to register user = %s" % (username,)) ok = False - # This should be None, but we don't like when PySide segfaults, - # so it something else. - # To reproduce it, just do: - # self.registration_finished.emit(False, None) - req = [] + req = None try: req = self._session.post(uri, data=user_data, @@ -143,13 +148,45 @@ class SRPRegister(QtCore.QObject): except requests.exceptions.RequestException as exc: logger.error(exc.message) - ok = False else: ok = req.ok - self.registration_finished.emit(ok, req) + status_code = self.STATUS_ERROR + if req is not None: + status_code = req.status_code + self._emit_result(status_code) + + if not ok: + try: + content, _ = get_content(req) + json_content = json.loads(content) + error_msg = json_content.get("errors").get("login")[0] + if not error_msg.istitle(): + error_msg = "%s %s" % (username, error_msg) + logger.error(error_msg) + except Exception as e: + logger.error("Unknown error: %r" % (e, )) + return ok + def _emit_result(self, status_code): + """ + Emit the corresponding signal depending on the status code. + + :param status_code: the status code received. + :type status_code: int or str + """ + logger.debug("Status code is: {0}".format(status_code)) + if self._signaler is None: + return + + if status_code in self.STATUS_OK: + self._signaler.signal(self._signaler.SRP_REGISTRATION_FINISHED) + elif status_code == self.STATUS_TAKEN: + self._signaler.signal(self._signaler.SRP_REGISTRATION_TAKEN) + else: + self._signaler.signal(self._signaler.SRP_REGISTRATION_FAILED) + if __name__ == "__main__": logger = logging.getLogger(name='leap') diff --git a/src/leap/bitmask/crypto/tests/fake_provider.py b/src/leap/bitmask/crypto/tests/fake_provider.py index 54af485d..b8cdbb12 100755 --- a/src/leap/bitmask/crypto/tests/fake_provider.py +++ b/src/leap/bitmask/crypto/tests/fake_provider.py @@ -280,7 +280,6 @@ class FakeSession(Resource): if HAMK is None: print '[server] verification failed!!!' raise Exception("Authentication failed!") - #import ipdb;ipdb.set_trace() assert svr.authenticated() print "***" diff --git a/src/leap/bitmask/crypto/tests/test_srpauth.py b/src/leap/bitmask/crypto/tests/test_srpauth.py index e63c1385..511a12ed 100644 --- a/src/leap/bitmask/crypto/tests/test_srpauth.py +++ b/src/leap/bitmask/crypto/tests/test_srpauth.py @@ -520,9 +520,9 @@ class SRPAuthTestCase(unittest.TestCase): m2 = self.auth_backend._extract_data(test_data) self.assertEqual(m2, test_m2) - self.assertEqual(self.auth_backend.get_uid(), test_uid) - self.assertEqual(self.auth_backend.get_uid(), - self.auth.get_uid()) + self.assertEqual(self.auth_backend.get_uuid(), test_uid) + self.assertEqual(self.auth_backend.get_uuid(), + self.auth.get_uuid()) self.assertEqual(self.auth_backend.get_token(), test_token) self.assertEqual(self.auth_backend.get_token(), self.auth.get_token()) @@ -691,7 +691,7 @@ class SRPAuthTestCase(unittest.TestCase): old_session = self.auth_backend._session self.auth_backend.logout() self.assertIsNone(self.auth_backend.get_session_id()) - self.assertIsNone(self.auth_backend.get_uid()) + self.assertIsNone(self.auth_backend.get_uuid()) self.assertNotEqual(old_session, self.auth_backend._session) d = threads.deferToThread(wrapper) |