summaryrefslogtreecommitdiff
path: root/src/leap/bitmask/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'src/leap/bitmask/crypto')
-rw-r--r--src/leap/bitmask/crypto/srpauth.py128
-rw-r--r--src/leap/bitmask/crypto/srpregister.py63
-rwxr-xr-xsrc/leap/bitmask/crypto/tests/fake_provider.py1
-rw-r--r--src/leap/bitmask/crypto/tests/test_srpauth.py8
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)