Example #1
0
    def test_verify_callback(self):
        json_from_post = "{\"result-data\":{\"gw\":{\"gateway-transaction-id\":\"8d77f986-de7f-4d47-97ef-9de7f8561684\",\"status-code\":7,\"status-text\":\"SUCCESS\"}," \
                         "\"error\":{},\"acquirer-details\":{\"eci-sli\":\"503\",\"terminal-mid\":\"3201210\",\"transaction-id\":\"7146311464333929\"," \
                         "\"result-code\":\"000\",\"status-text\":\"Approved\",\"status-description\":\"Approved\"},\"warnings\":" \
                         "[\"Soon counters will be exceeded for the merchant\",\"Soon counters will be exceeded for the account\"," \
                         "\"Soon counters will be exceeded for the terminal group\",\"Soon counters will be exceeded for the terminal\"]}}"

        sign_from_post = "Digest username=bc501eda-e2a1-4e63-9a1e-7a7f6ff4813b, uri=\"/v3.0/sms\", algorithm=SHA-256, " \
                         "cnonce=\"MTU5MTg2OTQ3OTpbmPfGQxVAh5z7MdWnRjF1cavfwKyxiLVrX4p7IHNwWA==\", " \
                         "snonce=\"MTU5MTg2OTQ4MTqfPxash/0hfNpI/gHuaoSiV+6PwVKYEawxchE0nxHTkA==\", qop=auth-int, " \
                         "response=\"87bd753875e28da54dfcb5e61614e10a7120aba9a3f8bed0e6eaa9acb85aa9f9\""

        response_digest = ResponseDigest(sign_from_post)
        response_digest.set_original_uri("/v3.0/sms")
        response_digest.set_original_cnonce(
            base64.b64decode(
                "MTU5MTg2OTQ3OTpbmPfGQxVAh5z7MdWnRjF1cavfwKyxiLVrX4p7IHNwWA==")
        )
        response_digest.set_body(json_from_post)
        response_digest.verify("bc501eda-e2a1-4e63-9a1e-7a7f6ff4813b",
                               "tPMOogw7YBumh6RpXxi2nvGW0C9lJq3L")

        parsed_result = CallbackResult(json.loads(json_from_post))
        self.assertEqual("8d77f986-de7f-4d47-97ef-9de7f8561684",
                         parsed_result.gw.gateway_transaction_id)
Example #2
0
    def test_verify_success_full_checks(self):
        body = "{\"acquirer-details\":{},\"error\":{},\"gw\":{\"gateway-transaction-id\":\"37b88436-b69c-45f3-ad26-b945153ad9a8\"," \
               "\"redirect-url\":\"http://api.local/4f1f647d10e8296a2ed4d21e3639f1ee\",\"status-code\":30,\"status-text\":" \
               "\"INSIDE FORM URL SENT\"},\"warnings\":[\"Soon counters will be exceeded for the merchant\",\"Soon counters will be exceeded " \
               "for the account\"]}"

        header = "Digest username=bc501eda-e2a1-4e63-9a1e-7a7f6ff4813b, uri=\"/v3.0/sms\", algorithm=SHA-256, " \
                 "cnonce=\"MTU5MTg2NjU3Mzo38zMeHvu4qcbhR8X158atP/BB4dDb5DbOMRT656yS7Q==\", " \
                 "snonce=\"MTU5MTg2NjU3MzpvnttqUse7hfrkUHtPS8tWE1jl0D0G/DgMmEFwbk5/jw==\", qop=auth-int, " \
                 "response=\"dda7026eebbeeee19fda191fd951d470b2064e3e1bc416365835abc775352552\""

        response_digest = ResponseDigest(header)
        response_digest.set_original_uri("/v3.0/sms")
        response_digest.set_original_cnonce(
            base64.b64decode(
                "MTU5MTg2NjU3Mzo38zMeHvu4qcbhR8X158atP/BB4dDb5DbOMRT656yS7Q==")
        )
        response_digest.set_body(body)
        response_digest.verify("bc501eda-e2a1-4e63-9a1e-7a7f6ff4813b",
                               "tPMOogw7YBumh6RpXxi2nvGW0C9lJq3L")
Example #3
0
    def test_parse_errors(self):
        nonce = str(base64.b64encode(bytes("1:q", "utf-8")), "utf-8")
        no_ts_nonce = str(base64.b64encode(bytes("qqq", "utf-8")), "utf-8")
        wrong_ts_nonce = str(base64.b64encode(bytes("qqq:www", "utf-8")),
                             "utf-8")

        cases = [
            ('', DigestMissingError, 'Digest is missing'),
            ("Digest uri=b, algorithm=SHA-256, cnonce=%s, snonce=%s, qop=auth-int, response=e"
             % (nonce, nonce), DigestMismatchError,
             'Digest mismatch: empty value for username'),
            ("Digest username=a, algorithm=SHA-256, cnonce=%s, snonce=%s, qop=auth-int, response=e"
             % (nonce, nonce), DigestMismatchError,
             "Digest mismatch: empty value for uri"),
            ("Digest username=a, uri=b, cnonce=%s, snonce=%s, qop=auth-int, response=e"
             % (nonce, nonce), DigestMismatchError,
             "Digest mismatch: empty value for algorithm"),
            ("Digest username=a, uri=b, algorithm=SHA-256, snonce=%s, qop=auth-int, response=e"
             % nonce, DigestMismatchError,
             "Digest mismatch: empty value for cnonce"),
            ("Digest username=a, uri=b, algorithm=SHA-256, cnonce=%s, qop=auth-int, response=e"
             % nonce, DigestMismatchError,
             "Digest mismatch: empty value for snonce"),
            ("Digest username=a, uri=b, algorithm=SHA-256, cnonce=%s, snonce=%s, response=e"
             % (nonce, nonce), DigestMismatchError,
             "Digest mismatch: empty value for qop"),
            ("Digest username=a, uri=b, algorithm=SHA-256, cnonce=%s, snonce=%s, qop=auth"
             % (nonce, nonce), DigestMismatchError,
             "Digest mismatch: empty value for response"),
            ("Digest username=a, uri=b, algorithm=SHA-256, cnonce=%s, snonce=%s, qop=aaa, response=x"
             % (nonce, nonce), DigestMismatchError,
             "Digest mismatch: format error: unknown QOP value"),
            ("Digest username=a, uri=b, algorithm=aaa, cnonce=%s, snonce=%s, qop=auth, response=x"
             % (nonce, nonce), DigestMismatchError,
             "Digest mismatch: format error: unknown algorithm"),
            ("Digest username=a, uri=b, algorithm=SHA-256, cnonce=%s, snonce=%s, qop=auth, response=x"
             % (nonce, no_ts_nonce), DigestMismatchError,
             "Digest mismatch: corrupted value for snonce (missing timestamp)"
             ),
            ("Digest username=a, uri=b, algorithm=SHA-256, cnonce=%s, snonce=%s, qop=auth, response=x"
             % (nonce, wrong_ts_nonce), DigestMismatchError,
             "Digest mismatch: corrupted value for snonce (unexpected timestamp value)"
             ),
        ]

        for i, test_case in enumerate(cases):
            [header, expected_error, expected_message] = test_case

            with self.subTest("#%d" % i):
                with self.assertRaises(expected_error) as cm:
                    ResponseDigest(header)
                self.assertEqual(expected_message, str(cm.exception))
Example #4
0
    def test_verify_errors(self):
        valid_cnonce = base64.b64decode(
            "MTU5MTg2NjU3Mzo38zMeHvu4qcbhR8X158atP/BB4dDb5DbOMRT656yS7Q==")
        invalid_cnonce = base64.b64decode(
            "MTU5MTg2NjU3MzpvnttqUse7hfrkUHtPS8tWE1jl0D0G/DgMmEFwbk5/jw==")

        cases = [
            ("wrong-guid", "/v3.0/sms", valid_cnonce,
             "Digest mismatch: username mismatch"),
            ("bc501eda-e2a1-4e63-9a1e-7a7f6ff4813b", "http://another.local",
             valid_cnonce, "Digest mismatch: uri mismatch"),
            ("bc501eda-e2a1-4e63-9a1e-7a7f6ff4813b", "/v3.0/sms",
             invalid_cnonce, "Digest mismatch: cnonce mismatch"),
            ("bc501eda-e2a1-4e63-9a1e-7a7f6ff4813b", "/v3.0/sms", valid_cnonce,
             "Digest mismatch")
        ]

        body = "{\"acquirer-details\":{},\"error\":{},\"gw\":{\"gateway-transaction-id\":\"37b88436-b69c-45f3-ad26-b945153ad9a8\"," \
               "\"redirect-url\":\"http://api.local/4f1f647d10e8296a2ed4d21e3639f1ee\",\"status-code\":30,\"status-text\":" \
               "\"INSIDE FORM URL SENT\"},\"warnings\":[\"Soon counters will be exceeded for the merchant\",\"Soon counters will be exceeded " \
               "for the account\"]}"

        header = "Digest username=bc501eda-e2a1-4e63-9a1e-7a7f6ff4813b, uri=\"/v3.0/sms\", algorithm=SHA-256, " \
                 "cnonce=\"MTU5MTg2NjU3Mzo38zMeHvu4qcbhR8X158atP/BB4dDb5DbOMRT656yS7Q==\", " \
                 "snonce=\"MTU5MTg2NjU3MzpvnttqUse7hfrkUHtPS8tWE1jl0D0G/DgMmEFwbk5/jw==\", qop=auth-int, " \
                 "response=\"624478f45d33bbadc7cf0ae9b34462efd7b9736111f295e6330fe0bc3b20acda\""

        for i, test_case in enumerate(cases):
            with self.subTest("#%d" % i):
                response_digest = ResponseDigest(header)
                response_digest.set_original_uri(test_case[1])
                response_digest.set_original_cnonce(test_case[2])
                response_digest.set_body(body)

                with self.assertRaises(DigestMismatchError) as cm:
                    response_digest.verify(test_case[0], "something wrong")
                self.assertEqual(test_case[3], str(cm.exception))
Example #5
0
    def test_parse_successful(self):
        header = "Digest username=bc501eda-e2a1-4e63-9a1e-7a7f6ff4813b, uri=\"/v3.0/sms\", algorithm=SHA-256, " \
                 "cnonce=\"MTU5MTYyNTA2MzqydV+lpoF4ZtfSAifxoUretZdAzGaZa97iRogrQ8K/yg==\", " \
                 "snonce=\"MTU5MTYyNDgwNzoUte6YsXIJmUo1EsA4yrYDCVbPrvCrEtqGq6CHTMhImg==\", qop=auth-int, " \
                 "response=\"a21df219fd9bb2efb71554eb9ebb47f6a7a61769a289f9ab4fcbe41d7544e28d\""
        digest = ResponseDigest(header)

        self.assertEqual("bc501eda-e2a1-4e63-9a1e-7a7f6ff4813b",
                         digest.get_username())
        self.assertEqual("/v3.0/sms", digest.get_uri())
        self.assertEqual(Algorithm.SHA256, digest.get_algorithm())
        self.assertEqual(QOP.AUTH_INT, digest.get_qop())
        self.assertEqual(
            "a21df219fd9bb2efb71554eb9ebb47f6a7a61769a289f9ab4fcbe41d7544e28d",
            digest.get_response())
        self.assertEqual(1591624807, digest.get_timestamp())
        self.assertEqual(
            base64.b64decode(
                "MTU5MTYyNTA2MzqydV+lpoF4ZtfSAifxoUretZdAzGaZa97iRogrQ8K/yg=="
            ), digest.get_cnonce())
        self.assertEqual(
            base64.b64decode(
                "MTU5MTYyNDgwNzoUte6YsXIJmUo1EsA4yrYDCVbPrvCrEtqGq6CHTMhImg=="
            ), digest.get_snonce())
Example #6
0
    def make_request(self, request_data=None) -> GatewayResponse:
        """
        Make HTTP request via Transact Pro HttpTransport

        Args:
            request_data (dict): Transact Pro request structure

        Response tuple (HTTP Content, HTTP Status code, HTTP Headers)

        Returns:
            GatewayResponse
        """
        if self.__client_operations['current'] == '/report':
            req_url = gateway.API_BASE_URL.rstrip(
                '/') + self.__client_operations['current']
        elif str(self.__client_operations['current']).startswith('http'):
            req_url = self.__client_operations['current']
        else:
            req_url = gateway.API_BASE_URL + gateway.API_VERSION + self.__client_operations[
                'current']

        if req_url is None:
            raise RuntimeError('Transact PRO API URL Empty!')

        if self.__client_operations['method'] != HTTP_GET:
            if request_data is None or len(request_data) < 1:
                raise RuntimeError("Request data invalid, is empty")

            if type(request_data) is not dict:
                raise RuntimeError('Request data invalid, must be dict')

        guid = AuthorizationBuilder.get_object_guid(
            self.__dict_of_auth_data_set)
        secret = self.__dict_of_auth_data_set[
            RequestParameters.AUTH_DATA_SECRET_KEY]
        digest = RequestDigest(username=guid, secret=secret, full_url=req_url)
        digest.set_body(json.dumps(request_data))

        # Setup config for HTTP transport
        # And make request via HTTP implemented Client
        [content, status_code, headers] = new_http_client(
            cli_name=gateway.HTTP_TRANSPORT_IMPLEMENTATION,
            verify_ssl=gateway.HTTP_VERIFY_SSL_CERTS,
            proxy=gateway.HTTP_PROXY,
            timeout=gateway.HTTP_TIME_OUT).request(
                http_method=self.__client_operations['method'],
                http_url=req_url,
                authorization_header=digest.create_header(),
                request_data=request_data)

        gw_response = GatewayResponse(status_code, content, headers)
        if gw_response.is_successful():
            response_digest = ResponseDigest(
                gw_response.headers.get('authorization'))
            gw_response.digest = response_digest

            response_digest.set_original_uri(digest.get_uri())
            response_digest.set_original_cnonce(digest.get_cnonce())
            response_digest.set_body(gw_response.payload)
            response_digest.verify(guid, secret)

        return gw_response