diff options
| -rw-r--r-- | src/leap/crypto/srpauth.py | 152 | 
1 files changed, 120 insertions, 32 deletions
| diff --git a/src/leap/crypto/srpauth.py b/src/leap/crypto/srpauth.py index 0fe3bf5a..8e228e79 100644 --- a/src/leap/crypto/srpauth.py +++ b/src/leap/crypto/srpauth.py @@ -30,8 +30,8 @@ from PySide import QtCore  from twisted.internet import threads  from leap.common.check import leap_assert -from leap.util.request_helpers import get_content  from leap.util.constants import REQUEST_TIMEOUT +from leap.util import request_helpers as reqhelper  from leap.common.events import signal as events_signal  from leap.common.events import events_pb2 as proto @@ -45,6 +45,71 @@ class SRPAuthenticationError(Exception):      pass +class SRPAuthConnectionError(SRPAuthenticationError): +    """ +    Exception raised when there's a connection error +    """ +    pass + +class SRPAuthUnknownUser(SRPAuthenticationError): +    """ +    Exception raised when trying to authenticate an unknown user +    """ +    pass + +class SRPAuthBadStatusCode(SRPAuthenticationError): +    """ +    Exception raised when we received an unknown bad status code +    """ +    pass + +class SRPAuthNoSalt(SRPAuthenticationError): +    """ +    Exception raised when we don't receive the salt param at a +    specific point in the auth process +    """ +    pass + +class SRPAuthNoB(SRPAuthenticationError): +    """ +    Exception raised when we don't receive the B param at a specific +    point in the auth process +    """ +    pass + +class SRPAuthBadDataFromServer(SRPAuthenticationError): +    """ +    Generic exception when we receive bad data from the server. +    """ +    pass + +class SRPAuthJSONDecodeError(SRPAuthenticationError): +    """ +    Exception raised when there's a problem decoding the JSON content +    parsed as received from th e server. +    """ +    pass + +class SRPAuthBadPassword(SRPAuthenticationError): +    """ +    Exception raised when the user provided a bad password to auth. +    """ +    pass + +class SRPAuthVerificationFailed(SRPAuthenticationError): +    """ +    Exception raised when we can't verify the SRP data received from +    the server. +    """ +    pass + +class SRPAuthNoSessionId(SRPAuthenticationError): +    """ +    Exception raised when we don't receive a session id from the +    server. +    """ +    pass +  class SRPAuth(QtCore.QObject):      """      SRPAuth singleton @@ -131,7 +196,13 @@ class SRPAuth(QtCore.QObject):              Sends the first request for authentication to retrieve the              salt and B parameter -            Might raise SRPAuthenticationError +            Might raise all SRPAuthenticationError based: +              SRPAuthenticationError +              SRPAuthConnectionError +              SRPAuthUnknownUser +              SRPAuthBadStatusCode +              SRPAuthNoSalt +              SRPAuthNoB              :param _: IGNORED, output from the previous callback (None)              :type _: IGNORED @@ -161,24 +232,24 @@ class SRPAuth(QtCore.QObject):              except requests.exceptions.ConnectionError as e:                  logger.error("No connection made (salt): %r" %                               (e,)) -                raise SRPAuthenticationError("Could not establish a " +                raise SRPAuthConnectionError("Could not establish a "                                               "connection")              except Exception as e:                  logger.error("Unknown error: %r" % (e,))                  raise SRPAuthenticationError("Unknown error: %r" %                                               (e,)) -            content, mtime = get_content(init_session) +            content, mtime = reqhelper.get_content(init_session)              if init_session.status_code not in (200,):                  logger.error("No valid response (salt): "                               "Status code = %r. Content: %r" %                               (init_session.status_code, content))                  if init_session.status_code == 422: -                    raise SRPAuthenticationError(self.tr("Unknown user")) +                    raise SRPAuthUnknownUser(self.tr("Unknown user")) -                raise SRPAuthenticationError(self.tr("There was a problem with" -                                                     " authentication")) +                raise SRPAuthBadStatusCode(self.tr("There was a problem with" +                                                   " authentication"))              json_content = json.loads(content)              salt = json_content.get("salt", None) @@ -186,12 +257,12 @@ class SRPAuth(QtCore.QObject):              if salt is None:                  logger.error("No salt parameter sent") -                raise SRPAuthenticationError(self.tr("The server did not send " -                                                     "the salt parameter")) +                raise SRPAuthNoSalt(self.tr("The server did not send " +                                            "the salt parameter"))              if B is None:                  logger.error("No B parameter sent") -                raise SRPAuthenticationError(self.tr("The server did not send " -                                                     "the B parameter")) +                raise SRPAuthNoB(self.tr("The server did not send " +                                         "the B parameter"))              return salt, B @@ -200,7 +271,12 @@ class SRPAuth(QtCore.QObject):              Given the salt and B processes the auth challenge and              generates the M2 parameter -            Might throw SRPAuthenticationError +            Might raise SRPAuthenticationError based: +              SRPAuthenticationError +              SRPAuthBadDataFromServer +              SRPAuthConnectionError +              SRPAuthJSONDecodeError +              SRPAuthBadPassword              :param salt_B: salt and B parameters for the username              :type salt_B: tuple @@ -217,8 +293,8 @@ class SRPAuth(QtCore.QObject):                  unhex_B = self._safe_unhexlify(B)              except (TypeError, ValueError) as e:                  logger.error("Bad data from server: %r" % (e,)) -                raise SRPAuthenticationError(self.tr("The data sent from " -                                                     "the server had errors")) +                raise SRPAuthBadDataFromServer( +                    self.tr("The data sent from the server had errors"))              M = self._srp_user.process_challenge(unhex_salt, unhex_B)              auth_url = "%s/%s/%s/%s" % (self._provider_config.get_api_uri(), @@ -239,13 +315,13 @@ class SRPAuth(QtCore.QObject):                                                  timeout=REQUEST_TIMEOUT)              except requests.exceptions.ConnectionError as e:                  logger.error("No connection made (HAMK): %r" % (e,)) -                raise SRPAuthenticationError(self.tr("Could not connect to " +                raise SRPAuthConnectionError(self.tr("Could not connect to "                                                       "the server"))              try: -                content, mtime = get_content(auth_result) +                content, mtime = reqhelper.get_content(auth_result)              except JSONDecodeError: -                raise SRPAuthenticationError("Bad JSON content in auth result") +                raise SRPAuthJSONDecodeError("Bad JSON content in auth result")              if auth_result.status_code == 422:                  error = "" @@ -259,26 +335,36 @@ class SRPAuth(QtCore.QObject):                                   "received: %s", (content,))                  logger.error("[%s] Wrong password (HAMK): [%s]" %                               (auth_result.status_code, error)) -                raise SRPAuthenticationError(self.tr("Wrong password")) +                raise SRPAuthBadPassword(self.tr("Wrong password"))              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 SRPAuthenticationError(self.tr("Unknown error (%s)") % -                                             (auth_result.status_code,)) +                raise SRPAuthBadStatusCode(self.tr("Unknown error (%s)") % +                                           (auth_result.status_code,))              return json.loads(content)          def _extract_data(self, json_content): +            """ +            Extracts the necessary parameters from json_content (M2, +            id, token) + +            Might raise SRPAuthenticationError based: +              SRPBadDataFromServer + +            :param json_content: Data received from the server +            :type json_content: dict +            """              try:                  M2 = json_content.get("M2", None)                  uid = json_content.get("id", None)                  token = json_content.get("token", None)              except Exception as e:                  logger.error(e) -                raise SRPAuthenticationError("Something went wrong with the " -                                             "login") +                raise SRPAuthBadDataFromServer("Something went wrong with the " +                                               "login")              self.set_uid(uid)              self.set_token(token) @@ -286,8 +372,8 @@ class SRPAuth(QtCore.QObject):              if M2 is None or self.get_uid() is None:                  logger.error("Something went wrong. Content = %r" %                               (json_content,)) -                raise SRPAuthenticationError(self.tr("Problem getting data " -                                                     "from server")) +                raise SRPAuthBadDataFromServer(self.tr("Problem getting data " +                                                       "from server"))              events_signal(proto.CLIENT_UID, content=uid) @@ -299,7 +385,9 @@ class SRPAuth(QtCore.QObject):              verification succeeds, it sets the session_id for this              session -            Might throw SRPAuthenticationError +            Might raise SRPAuthenticationError based: +              SRPAuthBadDataFromServer +              SRPAuthVerificationFailed              :param M2: M2 SRP parameter              :type M2: str @@ -309,22 +397,22 @@ class SRPAuth(QtCore.QObject):                  unhex_M2 = self._safe_unhexlify(M2)              except TypeError:                  logger.error("Bad data from server (HAWK)") -                raise SRPAuthenticationError(self.tr("Bad data from server")) +                raise SRPAuthBadDataFromServer(self.tr("Bad data from server"))              self._srp_user.verify_session(unhex_M2)              if not self._srp_user.authenticated():                  logger.error("Auth verification failed") -                raise SRPAuthenticationError(self.tr("Auth verification " -                                                     "failed")) +                raise SRPAuthVerificationFailed(self.tr("Auth verification " +                                                        "failed"))              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 SRPAuthenticationError(self.tr("Session cookie " -                                                     "verification " -                                                     "failed")) +                raise SRPAuthNoSessionId(self.tr("Session cookie " +                                                 "verification " +                                                 "failed"))              events_signal(proto.CLIENT_SESSION_ID, content=session_id) @@ -447,7 +535,7 @@ class SRPAuth(QtCore.QObject):          """          Executes the whole authentication process for a user -        Might raise SRPAuthenticationError +        Might raise SRPAuthenticationError based          :param username: username for this session          :type username: str | 
