class ResultValidatorTest(TestCase):
    SAMPLE_RESPONSES = {"405": {"description": "Invalid input"}}

    def setUp(self):
        self.validator = ResultValidator()
        self.response = MagicMock()
        self.response.status_code = 405
        self.response.documented_reason = 'doc reason'
        self.response.text = 'Error text from server'

    def test_evaluate_returns_none_when_resp_status_code_in_expected_responses(
            self):
        result = self.validator.evaluate(self.response, self.SAMPLE_RESPONSES,
                                         True)
        self.assertEqual(
            result, {
                'body': 'Error text from server',
                'status_code': 405,
                'documented_reason': 'Invalid input'
            })

    def test_evaluate_returns_result_log_when_resp_status_code_not_expected_responses_and_logging_not_forced(
            self):
        self.response.status_code = 500
        self.response.text = 'Internal Error'
        result = self.validator.evaluate(self.response, self.SAMPLE_RESPONSES,
                                         True)
        self.assertEqual(
            result, {
                "status_code": 500,
                "body": 'Internal Error',
                "documented_reason": None
            })

    def test_evaluate_returns_log_when_resp_status_code_in_expected_responses_and_forced_for_all_codes(
            self):
        result = self.validator.evaluate(self.response, self.SAMPLE_RESPONSES,
                                         False)
        self.assertEqual(
            result, {
                "status_code": 405,
                "body": 'Error text from server',
                "documented_reason": 'Invalid input'
            })

    def test_evaluate_returns_log_when_resp_status_code_not_in_expected_responses_and_forced_for_all_codes(
            self):
        self.response.status_code = 500
        self.response.text = 'Internal Error'
        result = self.validator.evaluate(self.response, self.SAMPLE_RESPONSES,
                                         False)
        self.assertEqual(
            result, {
                "status_code": 500,
                "body": 'Internal Error',
                "documented_reason": None
            })
示例#2
0
    def start(self):
        print('Fetching open API from: ' + self.url)

        # Try to find the protocol, host and basePath from the Swagger spec.
        # host and schemes can be omitted, and the "standard" says you should use the spec's URL to derive them.
        # https://swagger.io/docs/specification/2-0/api-host-and-base-path/
        schemes = []
        host = None
        basePath = None

        try:
            spec = self.get_swagger_spec(self.url)
            specURL = urlparse(self.url)
        except json.JSONDecodeError:
            error_cant_connect()

        if 'openapi' not in spec:
            if 'swagger' not in spec:
                self.log_operation(
                    None, self.url, {
                        "status_code":
                        "000",
                        "documented_reason":
                        "Specification: no version string found",
                        "body":
                        "Specification: no version string found in Swagger spec"
                    }, '')
                raise SchemaException

            if not spec['swagger'].startswith('2'):
                self.log_operation(
                    None, self.url, {
                        "status_code":
                        "000",
                        "documented_reason":
                        "Specification: wrong specification version",
                        "body":
                        "Specification: version in swagger spec not supported"
                    }, '')
                raise SchemaException
        elif not spec['openapi'].startswith('3'):
            self.log_operation(
                None, self.url, {
                    "status_code": "000",
                    "documented_reason":
                    "Specification: wrong specification version",
                    "body":
                    "Specification: version in openapi spec not supported"
                }, '')
            raise SchemaException
        baseUris = []
        if 'servers' in spec and len(spec['servers']) > 0:
            for server in spec['servers']:
                baseUris.append(server['url'])
        elif 'schemes' in spec:
            schemes = spec['schemes']
        else:
            # fake the array we'd find in the spec
            schemes.append(specURL.scheme)
            self.log_operation(
                None, self.url, {
                    "status_code": "000",
                    "documented_reason":
                    "Specification: no schemes entry, fallback to spec URL scheme",
                    "body":
                    "Specification: host entry not present in Swagger spec"
                }, '')
        if len(baseUris) == 0:
            if self.host:
                host = self.host
            elif 'host' in spec:
                host = spec['host']
            else:
                host = specURL.netloc
                self.log_operation(
                    None, self.url, {
                        "status_code":
                        "000",
                        "documented_reason":
                        "Specification: no host entry, fallback to spec URL host",
                        "body":
                        "Specification: schemes entry not present in Swagger spec"
                    }, '')

            # There is no nice way to derive the basePath from the spec's URL. They *have* to include it
            if 'basePath' not in spec:
                self.log_operation(
                    None, self.url, {
                        "status_code":
                        "000",
                        "documented_reason":
                        "Specification: basePath entry missing from Swagger spec",
                        "body":
                        "Specification Error: basePath entry missing from Swagger spec"
                    }, '')
                raise SchemaException
            basePath = self.basepath if self.basepath else spec['basePath']
            host_basepath = host + basePath
            for protocol in schemes:
                baseUris.append(protocol + '://' + host_basepath)

        paths = spec['paths']
        if 'definitions' in spec:
            type_definitions = spec['definitions']
        elif 'components' in spec and 'schemas' in spec['components']:
            type_definitions = spec['components']['schemas']
        else:
            self.log_operation(
                None, self.url, {
                    "status_code":
                    "000",
                    "documented_reason":
                    "Specification: type definitions missing from Swagger spec",
                    "body":
                    "Specification Error: type definitions missing from Swagger spec"
                }, '')
            raise SchemaException
        # the specifcation can list multiple schemes (http, https, ws, wss) - all should be tested.
        # Each scheme is a potentially different end point
        replicator = Replicator(type_definitions, self.use_string_pattern,
                                True, self.max_string_length)
        for baseUri in baseUris:
            for path_key in paths.keys():
                if path_key in self.ignored_paths:
                    continue
                path = paths[path_key]

                for op_code in path.keys():
                    operation = HttpOperation(op_code,
                                              baseUri,
                                              path_key,
                                              replicator=replicator,
                                              op_infos=path[op_code],
                                              use_fuzzing=True,
                                              headers=self.headers,
                                              ignore_tls=self.ignore_tls)

                    for _ in range(self.iterations):
                        response = operation.execute()
                        validator = ResultValidator()
                        log = validator.evaluate(
                            response, path[op_code]['responses'],
                            self.log_unexpected_errors_only)
                        curlcommand = CurlCommand(response.url,
                                                  operation.op_code,
                                                  operation.request_body,
                                                  self.headers,
                                                  self.ignore_tls)

                        # log to screen for now
                        self.log_operation(operation.op_code, response.url,
                                           log, curlcommand)

        return True
示例#3
0
    def start(self):
        print('Fetching open API from: ' + self.url)

        # Try to find the protocol, host and basePath from the Swagger spec.
        # host and schemes can be omitted, and the "standard" says you should use the spec's URL to derive them.
        # https://swagger.io/docs/specification/2-0/api-host-and-base-path/
        schemes = []
        host = None
        basePath = None

        client = SwaggerClient.from_url(self.url)
        spec = client.swagger_spec.spec_dict
        specURL = urlparse(self.url)

        if 'schemes' in spec:
            schemes = spec['schemes']
        else:
            # fake the array we'd find in the spec
            schemes.append(specURL.scheme)
            self.log_operation(
                None, self.url, {
                    "status_code": "000",
                    "documented_reason":
                    "Specification: no schemes entry, fallback to spec URL scheme",
                    "body":
                    "Specification: host entry not present in Swagger spec"
                }, '')

        if 'host' in spec:
            host = spec['host']
        else:
            host = specURL.netloc
            self.log_operation(
                None, self.url, {
                    "status_code":
                    "000",
                    "documented_reason":
                    "Specification: no host entry, fallback to spec URL host",
                    "body":
                    "Specification: schemes entry not present in Swagger spec"
                }, '')

        # There is no nice way to derive the basePath from the spec's URL. They *have* to include it
        if 'basePath' not in spec:
            self.log_operation(
                None, self.url, {
                    "status_code":
                    "000",
                    "body":
                    "Specification Error: basePath entry missing from Swagger spec"
                }, '')
        host_basepath = host + spec['basePath']
        paths = spec['paths']
        type_definitions = spec['definitions']
        # the specifcation can list multiple schemes (http, https, ws, wss) - all should be tested.
        # Each scheme is a potentially different end point
        for protocol in schemes:
            for path_key in paths.keys():
                path = paths[path_key]

                for op_code in path.keys():
                    operation = HttpOperation(op_code,
                                              protocol + '://' + host_basepath,
                                              path_key,
                                              op_infos=path[op_code],
                                              use_fuzzing=True,
                                              headers=self.headers)

                    for x in range(self.iterations):
                        response = operation.execute(type_definitions)
                        validator = ResultValidator()
                        log = validator.evaluate(
                            response, path[op_code]['responses'],
                            self.log_unexpected_errors_only)
                        curlcommand = CurlCommand(response.url,
                                                  operation.op_code,
                                                  operation.request_body,
                                                  self.headers)

                        # log to screen for now
                        self.log_operation(operation.op_code, response.url,
                                           log, curlcommand)
 def setUp(self):
     self.validator = ResultValidator()
     self.response = MagicMock()
     self.response.status_code = 405
     self.response.documented_reason = 'doc reason'
     self.response.text = 'Error text from server'