Beispiel #1
0
 def start(self, properties):
     self.authzid = properties.get("authzid")
     # TODO: This isn't very XEP-0178'ish.
     # XEP-0178 says "=" should be sent when only one id-on-xmppAddr is
     # in the cert, but we don't know that. Still, this conforms to the
     # standard and works.
     if self.authzid:
         return Response(self.authzid)
     else:
         return Response(b"")
Beispiel #2
0
    def _make_response(self, nonce, salt, iteration_count):
        """Make a response for the first challenge from the server.

        :return: the response or a failure indicator.
        :returntype: `sasl.Response` or `sasl.Failure`
        """
        self._salted_password = self.Hi(self.Normalize(self.password), salt,
                                        iteration_count)
        self.password = None  # not needed any more
        if self.channel_binding:
            channel_binding = b"c=" + standard_b64encode(self._gs2_header +
                                                         self._cb_data)
        else:
            channel_binding = b"c=" + standard_b64encode(self._gs2_header)

        client_final_message_without_proof = (channel_binding + b",r=" + nonce)

        client_key = self.HMAC(self._salted_password, b"Client Key")
        stored_key = self.H(client_key)
        auth_message = (self._client_first_message_bare + b"," +
                        self._server_first_message + b"," +
                        client_final_message_without_proof)
        self._auth_message = auth_message
        client_signature = self.HMAC(stored_key, auth_message)
        client_proof = self.XOR(client_key, client_signature)
        proof = b"p=" + standard_b64encode(client_proof)
        client_final_message = (client_final_message_without_proof + b"," +
                                proof)
        return Response(client_final_message)
Beispiel #3
0
 def challenge(self, challenge):
     if self.step == 0:
         ret = kerberos.authGSSClientStep(self._gss,
                                          base64.b64encode(challenge))
         if ret != kerberos.AUTH_GSS_CONTINUE:
             self.step = 1
     elif self.step == 1:
         ret = kerberos.authGSSClientUnwrap(self._gss,
                                            base64.b64encode(challenge))
         response = kerberos.authGSSClientResponse(self._gss)
         ret = kerberos.authGSSClientWrap(self._gss, response,
                                          self.username)
     response = kerberos.authGSSClientResponse(self._gss)
     if response is None:
         return Response(b"")
     else:
         return Response(base64.b64decode(response))
Beispiel #4
0
 def start(self, properties):
     self.username = properties["username"]
     self.authzid = properties.get("authzid", "")
     self.in_properties = properties
     self.nonce_count = 0
     self.response_auth = None
     self.rspauth_checked = False
     self.realm = None
     return Response(None)
Beispiel #5
0
 def challenge(self, challenge):
     in_params = dict([part.split('=') for part in challenge.split('&')])
     out_params = {}
     out_params['nonce'] = in_params['nonce']
     out_params['method'] = in_params['method']
     out_params['access_token'] = self.access_token
     out_params['api_key'] = self.api_key
     out_params['call_id'] = float(round(time.time() * 1000))
     out_params['v'] = '1.0'
     data = urllib.urlencode(out_params)
     return Response(data)
Beispiel #6
0
    def start(self, properties):
        self.username = properties["username"]
        self.password = properties["password"]
        self.authzid = properties.get("authzid", u"")
        c_nonce = properties.get("nonce_factory", default_nonce_factory)()
        if not VALUE_CHARS_RE.match(c_nonce):
            c_nonce = standard_b64encode(c_nonce)
        self._c_nonce = c_nonce

        if self.channel_binding:
            cb_data = properties.get("channel-binding")
            if not cb_data:
                raise ValueError("No channel binding data provided")
            if "tls-unique" in cb_data:
                cb_type = "tls-unique"
            elif "tls-server-end-point" in cb_data:
                cb_type = "tls-server-end-point"
            elif cb_data:
                cb_type = cb_data.keys()[0]
            self._cb_data = cb_data[cb_type]
            cb_flag = b"p=" + cb_type.encode("utf-8")
        else:
            plus_name = self.name + "-PLUS"
            if plus_name in properties.get("enabled_mechanisms", []):
                # -PLUS is enabled (supported) on our side,
                # but was not selected - that means it was not included
                # in the server features
                cb_flag = b"y"
            else:
                cb_flag = b"n"

        if self.authzid:
            authzid = b"a=" + self.escape(self.authzid.encode("utf-8"))
        else:
            authzid = b""
        gs2_header = cb_flag + b"," + authzid + b","
        self._gs2_header = gs2_header
        nonce = b"r=" + c_nonce
        client_first_message_bare = (
            b"n=" + self.escape(self.username.encode("utf-8")) + b"," + nonce)
        self._client_first_message_bare = client_first_message_bare
        client_first_message = gs2_header + client_first_message_bare
        return Response(client_first_message)
Beispiel #7
0
    def _final_challenge(self, challenge):
        """Process the second challenge from the server and return the
        response.

        :Parameters:
            - `challenge`: the challenge from server.
        :Types:
            - `challenge`: `bytes`

        :return: the response or a failure indicator.
        :returntype: `sasl.Response` or `sasl.Failure`
        """
        if self._finished:
            return Failure("extra-challenge")

        match = SERVER_FINAL_MESSAGE_RE.match(challenge)
        if not match:
            logger.debug("Bad final message syntax: {0!r}".format(challenge))
            return Failure("bad-challenge")

        error = match.group("error")
        if error:
            logger.debug("Server returned SCRAM error: {0!r}".format(error))
            return Failure(u"scram-" + error.decode("utf-8"))

        verifier = match.group("verifier")
        if not verifier:
            logger.debug("No verifier value in the final message")
            return Failure("bad-succes")

        server_key = self.HMAC(self._salted_password, b"Server Key")
        server_signature = self.HMAC(server_key, self._auth_message)
        if server_signature != a2b_base64(verifier):
            logger.debug("Server verifier does not match")
            return Failure("bad-succes")

        self._finished = True
        return Response(None)
Beispiel #8
0
    def _final_challenge(self, challenge):
        """Process the second challenge from the server and return the response.

        :Parameters:
            - `challenge`: the challenge from server.
        :Types:
            - `challenge`: `bytes`

        :return: the response or a failure indicator.
        :returntype: `sasl.Response` or `sasl.Failure`
        """
        if self.rspauth_checked:
            return Failure("extra-challenge")
        challenge = challenge.split(b'\x00')[0]
        rspauth = None
        while challenge:
            match = PARAM_RE.match(challenge)
            if not match:
                logger.debug("Challenge syntax error: {0!r}".format(challenge))
                return Failure("bad-challenge")
            challenge = match.group("rest")
            var = match.group("var")
            val = match.group("val")
            logger.debug("{0!r}: {1!r}".format(var, val))
            if var == b"rspauth":
                rspauth = val
        if not rspauth:
            logger.debug("Final challenge without rspauth")
            return Failure("bad-success")
        if rspauth == self.response_auth:
            self.rspauth_checked = True
            return Response(None)
        else:
            logger.debug("Wrong rspauth value - peer is cheating?")
            logger.debug("my rspauth: {0!r}".format(self.response_auth))
            return Failure("bad-success")
Beispiel #9
0
    def _make_response(self, charset, realms, nonce):
        """Make a response for the first challenge from the server.

        :Parameters:
            - `charset`: charset name from the challenge.
            - `realms`: realms list from the challenge.
            - `nonce`: nonce value from the challenge.
        :Types:
            - `charset`: `bytes`
            - `realms`: `bytes`
            - `nonce`: `bytes`

        :return: the response or a failure indicator.
        :returntype: `sasl.Response` or `sasl.Failure`"""

        params = []
        realm = self._get_realm(realms, charset)
        if isinstance(realm, Failure):
            return realm
        elif realm:
            realm = _quote(realm)
            params.append(b'realm="' + realm + b'"')

        try:
            username = self.username.encode(charset)
        except UnicodeError:
            logger.debug("Couldn't encode username to {0!r}".format(charset))
            return Failure("incompatible-charset")

        username = _quote(username)
        params.append(b'username="******"')

        cnonce = self.in_properties.get("nonce_factory",
                                        default_nonce_factory)()
        cnonce = _quote(cnonce)
        params.append(b'cnonce="' + cnonce + b'"')

        params.append(b'nonce="' + nonce + b'"')

        self.nonce_count += 1

        nonce_count = "{0:08x}".format(self.nonce_count).encode("us-ascii")
        params.append(b'nc=' + nonce_count)

        params.append(b'qop=auth')

        serv_type = self.in_properties["service-type"]
        serv_type = serv_type.encode("us-ascii")
        serv_name = self.in_properties["service-domain"]
        host = self.in_properties.get("service-hostname", serv_name)
        serv_name = serv_name.encode("idna")
        host = host.encode("idna")

        if serv_name and serv_name != host:
            digest_uri = b"/".join((serv_type, host, serv_name))
        else:
            digest_uri = b"/".join((serv_type, host))

        digest_uri = _quote(digest_uri)
        params.append(b'digest-uri="' + digest_uri + b'"')

        if self.authzid:
            try:
                authzid = self.authzid.encode(charset)
            except UnicodeError:
                logger.debug(
                    "Couldn't encode authzid to {0!r}".format(charset))
                return Failure("incompatible-charset")
            authzid = _quote(authzid)
        else:
            authzid = b""

        try:
            epasswd = self.in_properties["password"].encode(charset)
        except UnicodeError:
            logger.debug("Couldn't encode password to {0!r}".format(charset))
            return Failure("incompatible-charset")
        logger.debug("Encoded password: {0!r}".format(epasswd))
        urp_hash = _make_urp_hash(username, realm, epasswd)

        response = _compute_response(urp_hash, nonce, cnonce, nonce_count,
                                     authzid, digest_uri)
        self.response_auth = _compute_response_auth(urp_hash, nonce, cnonce,
                                                    nonce_count, authzid,
                                                    digest_uri)
        params.append(b'response=' + response)
        if authzid:
            params.append(b'authzid="' + authzid + b'"')
        return Response(b",".join(params))
Beispiel #10
0
 def start(self, properties):
     self.access_token = properties['facebook_access_token']
     self.api_key = properties['facebook_api_key']
     return Response(None)