Exemple #1
0
    def _init_connection(self, response):
        """
        Prepare initial connection message. We send the version as well as the initial
        JSON as an optimization.

        :param response: Response from the database
        :raises: ReqlDriverError
        :return: Initial message which will be sent to the DB
        """

        if response is not None:
            raise ReqlDriverError('Unexpected response')

        self._random_nonce = base64.standard_b64encode(
            bytes(bytearray(SystemRandom().getrandbits(8) for i in range(18))))

        self._first_client_message = chain_to_bytes('n=', self._username,
                                                    ',r=', self._random_nonce)

        initial_message = chain_to_bytes(
            struct.pack('<L', self.VERSION),
            self._json_encoder.encode({
                'protocol_version':
                self._protocol_version,
                'authentication_method':
                'SCRAM-SHA-256',
                'authentication':
                chain_to_bytes('n,,',
                               self._first_client_message).decode('ascii')
            }).encode('utf-8'), b'\0')

        self._next_state()
        return initial_message
Exemple #2
0
    def test_init_connection(self, mock_base64):
        self.handshake._next_state = Mock()
        encoded_string = "test"
        mock_base64.standard_b64encode.return_value = encoded_string
        first_client_message = chain_to_bytes(
            "n=", self.handshake._username, ",r=", encoded_string
        )

        expected_result = chain_to_bytes(
            struct.pack("<L", self.handshake.VERSION),
            self.handshake._json_encoder.encode(
                {
                    "protocol_version": self.handshake._protocol_version,
                    "authentication_method": "SCRAM-SHA-256",
                    "authentication": chain_to_bytes(
                        "n,,", first_client_message
                    ).decode("ascii"),
                }
            ).encode("utf-8"),
            b"\0",
        )

        result = self.handshake._init_connection(response=None)

        assert result == expected_result
        assert self.handshake._next_state.called is True
Exemple #3
0
    def _prepare_auth_request(self, response):
        """
        Put tohether the authentication request based on the response of the database.

        :param response: Response from the database
        :raises: ReqlDriverError | ReqlAuthError
        :return: An empty string
        """

        json_response = self._decode_json_response(response, with_utf8=True)
        first_client_message, authentication = self._get_authentication_and_first_client_message(
            json_response)

        random_nonce = authentication[b'r']
        if not random_nonce.startswith(self._random_nonce):
            raise ReqlAuthError('Invalid nonce from server', self._host,
                                self._port)

        salted_password = self._pbkdf2_hmac(
            'sha256', self._password,
            base64.standard_b64decode(authentication[b's']),
            int(authentication[b'i']))

        message_without_proof = chain_to_bytes('c=biws,r=', random_nonce)
        auth_message = b','.join((self._first_client_message,
                                  first_client_message, message_without_proof))

        self._server_signature = hmac.new(
            hmac.new(salted_password, b'Server Key', hashlib.sha256).digest(),
            auth_message, hashlib.sha256).digest()

        client_key = hmac.new(salted_password, b'Client Key',
                              hashlib.sha256).digest()
        client_signature = hmac.new(
            hashlib.sha256(client_key).digest(), auth_message,
            hashlib.sha256).digest()
        client_proof = struct.pack(
            '32B',
            *(l ^ random_nonce for l, random_nonce in zip(
                struct.unpack('32B', client_key),
                struct.unpack('32B', client_signature))))

        authentication_request = chain_to_bytes(
            self._json_encoder.encode({
                'authentication':
                chain_to_bytes(
                    message_without_proof, ',p=',
                    base64.standard_b64encode(client_proof)).decode('ascii')
            }), b'\0')

        self._next_state()
        return authentication_request
    def test_init_connection(self, mock_base64):
        self.handshake._next_state = Mock()
        encoded_string = 'test'
        mock_base64.standard_b64encode.return_value = encoded_string
        first_client_message = chain_to_bytes('n=', self.handshake._username,
                                              ',r=', encoded_string)

        expected_result = chain_to_bytes(
            struct.pack('<L', self.handshake.VERSION),
            self.handshake._json_encoder.encode({
                'protocol_version':
                self.handshake._protocol_version,
                'authentication_method':
                'SCRAM-SHA-256',
                'authentication':
                chain_to_bytes('n,,', first_client_message).decode('ascii')
            }).encode('utf-8'), b'\0')

        result = self.handshake._init_connection(response=None)

        assert result == expected_result
        assert self.handshake._next_state.called is True
    def _init_connection(self, response):
        """
        Prepare initial connection message. We send the version as well as the initial
        JSON as an optimization.

        :param response: Response from the database
        :raises: ReqlDriverError
        :return: Initial message which will be sent to the DB
        """

        if response is not None:
            raise ReqlDriverError("Unexpected response")

        self._random_nonce = base64.standard_b64encode(
            bytes(bytearray(SystemRandom().getrandbits(8) for i in range(18)))
        )

        self._first_client_message = chain_to_bytes(
            "n=", self._username, ",r=", self._random_nonce
        )

        initial_message = chain_to_bytes(
            struct.pack("<L", self.VERSION),
            self._json_encoder.encode(
                {
                    "protocol_version": self._protocol_version,
                    "authentication_method": "SCRAM-SHA-256",
                    "authentication": chain_to_bytes(
                        "n,,", self._first_client_message
                    ).decode("ascii"),
                }
            ).encode("utf-8"),
            b"\0",
        )

        self._next_state()
        return initial_message
    def test_prepare_auth_request(self):
        self.handshake._next_state = Mock()
        self.handshake._random_nonce = base64.encodebytes(
            b'random_nonce') if six.PY3 else base64.b64encode(b'random_nonce')
        self.handshake._first_client_message = chain_to_bytes(
            'n=', self.handshake._username, ',r=',
            self.handshake._random_nonce)
        response = {
            'success': True,
            'authentication': 's=cmFuZG9tX25vbmNl\n,i=2,r=cmFuZG9tX25vbmNl\n'
        }
        if six.PY3:
            expected_result = b'{"authentication": "c=biws,r=cmFuZG9tX25vbmNl\\n,p=2Tpd60LM4Tkhe7VATTPj/lh4yunl07Sm4A+m3ukC774="}\x00'
        else:
            expected_result = b'{"authentication": "c=biws,r=cmFuZG9tX25vbmNl\\n,p=JqVP98bzu3yye/3SLopNJvCRimBx34uKI/EY8UI41gM="}\x00'

        result = self.handshake._prepare_auth_request(json.dumps(response))

        assert isinstance(result, six.binary_type)
        assert result == expected_result
        assert self.handshake._next_state.called is True
    def test_mixed_chaining(self):
        expected_string = b"iron man"

        result = chain_to_bytes("iron", " ", b"man")

        assert result == expected_string
    def test_mixed_chaining(self):
        expected_string = b'iron man'

        result = chain_to_bytes('iron', ' ', b'man')

        assert result == expected_string
    def _prepare_auth_request(self, response):
        """
        Put tohether the authentication request based on the response of the database.

        :param response: Response from the database
        :raises: ReqlDriverError | ReqlAuthError
        :return: An empty string
        """

        json_response = self._decode_json_response(response, with_utf8=True)
        (
            first_client_message,
            authentication,
        ) = self._get_authentication_and_first_client_message(json_response)

        random_nonce = authentication[b"r"]
        if not random_nonce.startswith(self._random_nonce):
            raise ReqlAuthError("Invalid nonce from server", self._host, self._port)

        salted_password = self._pbkdf2_hmac(
            "sha256",
            self._password,
            base64.standard_b64decode(authentication[b"s"]),
            int(authentication[b"i"]),
        )

        message_without_proof = chain_to_bytes("c=biws,r=", random_nonce)
        auth_message = b",".join(
            (self._first_client_message, first_client_message, message_without_proof)
        )

        self._server_signature = hmac.new(
            hmac.new(salted_password, b"Server Key", hashlib.sha256).digest(),
            auth_message,
            hashlib.sha256,
        ).digest()

        client_key = hmac.new(salted_password, b"Client Key", hashlib.sha256).digest()
        client_signature = hmac.new(
            hashlib.sha256(client_key).digest(), auth_message, hashlib.sha256
        ).digest()
        client_proof = struct.pack(
            "32B",
            *(
                l ^ random_nonce
                for l, random_nonce in zip(
                    struct.unpack("32B", client_key),
                    struct.unpack("32B", client_signature),
                )
            )
        )

        authentication_request = chain_to_bytes(
            self._json_encoder.encode(
                {
                    "authentication": chain_to_bytes(
                        message_without_proof,
                        ",p=",
                        base64.standard_b64encode(client_proof),
                    ).decode("ascii")
                }
            ),
            b"\0",
        )

        self._next_state()
        return authentication_request