def test_model_param_nested_allOf_in_json(self): specification_as_string = NestedModel().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] self.assertEqual(len(data), 1) # The specification says that this query string parameter is # required and there is only one parameter, so there is no second # operation with the optional parameters filled in. self.assertEqual(len(data), 1) data_i = data[0] factory = RequestFactory(*data_i) fuzzable_request = factory.get_fuzzable_request() e_url = 'http://w3af.org/api/pets' e_headers = Headers([('Content-Type', 'application/json')]) e_data = '{"pet": {"tag": "7", "name": "John", "id": 42}}' self.assertEqual(fuzzable_request.get_method(), 'GET') self.assertEqual(fuzzable_request.get_uri().url_string, e_url) self.assertEqual(fuzzable_request.get_headers(), e_headers) self.assertEqual(fuzzable_request.get_data(), e_data)
def test_array_with_model_items_param_in_json(self): specification_as_string = ArrayModelItems().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] # The specification says that this query string parameter is # required and there is only one parameter, so there is no second # operation with the optional parameters filled in. self.assertEqual(len(data), 1) data_i = data[0] factory = RequestFactory(*data_i) fuzzable_request = factory.get_fuzzable_request() e_url = 'http://petstore.swagger.io/api/pets' e_headers = Headers([('Content-Type', 'application/json')]) e_data = '{"pets": [{"tag": "7", "name": "John"}]}' self.assertEqual(fuzzable_request.get_method(), 'POST') self.assertEqual(fuzzable_request.get_uri().url_string, e_url) self.assertEqual(fuzzable_request.get_headers(), e_headers) self.assertEqual(fuzzable_request.get_data(), e_data)
def test_model_param_nested_allOf_in_json(self): specification_as_string = NestedModel().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] self.assertEqual(len(data), 1) # # Assertions on call #1 # (spec, api_resource_name, resource, operation_name, operation, parameters) = data[0] self.assertEqual(api_resource_name, 'pets') self.assertEqual(operation_name, 'findPets') self.assertEqual(operation.consumes, [u'application/json']) self.assertEqual(operation.produces, [u'application/json', u'application/xml', u'text/xml', u'text/html']) self.assertEqual(operation.path_name, '/pets') # Now we check the parameters for the operation self.assertEqual(len(operation.params), 1) param = operation.params.get('pet') self.assertEqual(param.param_spec['required'], True) self.assertEqual(param.param_spec['in'], 'body') self.assertIn('schema', param.param_spec) expected_value = {u'tag': '7', u'name': 'John', u'id': 42} self.assertEqual(param.fill, expected_value)
def test_array_with_model_items_param_in_json(self): specification_as_string = ArrayModelItems().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] # The specification says that this query string parameter is # required and there is only one parameter, so there is no second # operation with the optional parameters filled in. self.assertEqual(len(data), 1) data_i = data[0] factory = RequestFactory(*data_i) fuzzable_request = factory.get_fuzzable_request() e_url = 'http://petstore.swagger.io/api/pets' e_headers = Headers([('Content-Type', 'application/json')]) e_data = '{"pets": [{"tag": "7", "name": "John"}]}' self.assertEqual(fuzzable_request.get_method(), 'POST') self.assertEqual(fuzzable_request.get_uri().url_string, e_url) self.assertEqual(fuzzable_request.get_headers(), e_headers) self.assertEqual(fuzzable_request.get_data(), e_data)
def test_string_param_header(self): specification_as_string = StringParamHeader().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] # The specification says that this query string parameter is # required and there is only one parameter, so there is no second # operation with the optional parameters filled in. self.assertEqual(len(data), 1) (spec, api_resource_name, resource, operation_name, operation, parameters) = data[0] self.assertEqual(api_resource_name, 'pets') self.assertEqual(operation_name, 'findPets') self.assertEqual(operation.consumes, [u'application/json']) self.assertEqual(operation.produces, [u'application/json']) self.assertEqual(operation.path_name, '/pets') # Now we check the parameters for the operation self.assertEqual(len(operation.params), 1) param = operation.params.get('X-Foo-Header') self.assertEqual(param.param_spec['required'], True) self.assertEqual(param.param_spec['in'], 'header') self.assertEqual(param.param_spec['type'], 'string') self.assertEqual(param.fill, '56')
def test_array_int_items_param_in_qs(self): specification_as_string = ArrayIntItemsQueryString().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] # The specification says that this query string parameter is # required and there is only one parameter, so there is no second # operation with the optional parameters filled in. self.assertEqual(len(data), 1) (spec, api_resource_name, resource, operation_name, operation, parameters) = data[0] self.assertEqual(api_resource_name, 'pets') self.assertEqual(operation_name, 'addTags') self.assertEqual(operation.consumes, [u'application/json']) self.assertEqual(operation.produces, [u'application/json']) self.assertEqual(operation.path_name, '/pets') # Now we check the parameters for the operation self.assertEqual(len(operation.params), 1) param = operation.params.get('tags') self.assertEqual(param.param_spec['required'], True) self.assertEqual(param.param_spec['in'], 'query') self.assertEqual(param.param_spec['type'], 'array') self.assertEqual(param.fill, [42])
def test_simple_int_param_in_path(self): specification_as_string = IntParamPath().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] self.assertEqual(len(data), 1) (spec, api_resource_name, resource, operation_name, operation, parameters) = data[0] self.assertEqual(api_resource_name, 'pets') self.assertEqual(operation_name, 'get_pets_pet_id') self.assertEqual(operation.consumes, []) self.assertEqual(operation.produces, []) self.assertEqual(operation.path_name, '/pets/{pet_id}') # And now the real stuff... self.assertEqual(len(operation.params), 1) param = operation.params.get('pet_id') self.assertEqual(param.param_spec['required'], True) self.assertEqual(param.param_spec['in'], 'path') self.assertEqual(param.param_spec['type'], 'integer') self.assertEqual(param.fill, 42)
def test_array_int_items_param_in_qs(self): specification_as_string = ArrayIntItemsQueryString().get_specification( ) http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] # The specification says that this query string parameter is # required and there is only one parameter, so there is no second # operation with the optional parameters filled in. self.assertEqual(len(data), 1) (spec, api_resource_name, resource, operation_name, operation, parameters) = data[0] self.assertEqual(api_resource_name, 'pets') self.assertEqual(operation_name, 'addTags') self.assertEqual(operation.consumes, [u'application/json']) self.assertEqual(operation.produces, [u'application/json']) self.assertEqual(operation.path_name, '/pets') # Now we check the parameters for the operation self.assertEqual(len(operation.params), 1) param = operation.params.get('tags') self.assertEqual(param.param_spec['required'], True) self.assertEqual(param.param_spec['in'], 'query') self.assertEqual(param.param_spec['type'], 'array') self.assertEqual(param.fill, [42])
def test_string_param_header(self): specification_as_string = StringParamHeader().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] # The specification says that this query string parameter is # required and there is only one parameter, so there is no second # operation with the optional parameters filled in. self.assertEqual(len(data), 1) data_i = data[0] factory = RequestFactory(*data_i) fuzzable_request = factory.get_fuzzable_request() e_url = 'http://petstore.swagger.io/api/pets' e_headers = Headers([('X-Foo-Header', '56'), ('Content-Type', 'application/json')]) e_data = '' self.assertEqual(fuzzable_request.get_method(), 'GET') self.assertEqual(fuzzable_request.get_uri().url_string, e_url) self.assertEqual(fuzzable_request.get_headers(), e_headers) self.assertEqual(fuzzable_request.get_data(), e_data)
def test_no_model_json_object_with_int_param_in_body(self): specification_as_string = IntParamNoModelJson().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] # The specification says that this query string parameter is # required and there is only one parameter, so there is no second # operation with the optional parameters filled in. self.assertEqual(len(data), 1) (spec, api_resource_name, resource, operation_name, operation, parameters) = data[0] self.assertEqual(api_resource_name, 'pets') self.assertEqual(operation_name, 'addPet') self.assertEqual(operation.consumes, [u'application/json']) self.assertEqual(operation.produces, [u'application/json']) self.assertEqual(operation.path_name, '/pets') # Now we check the parameters for the operation self.assertEqual(len(operation.params), 1) param = operation.params.get('pet') self.assertEqual(param.param_spec['required'], True) self.assertEqual(param.param_spec['in'], 'body') self.assertIn('schema', param.param_spec) self.assertEqual(param.fill, {u'age': 42})
def test_model_param_nested_allOf_in_json(self): specification_as_string = NestedModel().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] self.assertEqual(len(data), 1) # # Assertions on call #1 # (spec, api_resource_name, resource, operation_name, operation, parameters) = data[0] self.assertEqual(api_resource_name, 'pets') self.assertEqual(operation_name, 'findPets') self.assertEqual(operation.consumes, [u'application/json']) self.assertEqual(operation.produces, [ u'application/json', u'application/xml', u'text/xml', u'text/html' ]) self.assertEqual(operation.path_name, '/pets') # Now we check the parameters for the operation self.assertEqual(len(operation.params), 1) param = operation.params.get('pet') self.assertEqual(param.param_spec['required'], True) self.assertEqual(param.param_spec['in'], 'body') self.assertIn('schema', param.param_spec) expected_value = {u'tag': '7', u'name': 'John', u'id': 42} self.assertEqual(param.fill, expected_value)
def test_simple_int_param_in_path(self): specification_as_string = IntParamPath().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] self.assertEqual(len(data), 1) (spec, api_resource_name, resource, operation_name, operation, parameters) = data[0] self.assertEqual(api_resource_name, 'pets') self.assertEqual(operation_name, 'get_pets_pet_id') self.assertEqual(operation.consumes, []) self.assertEqual(operation.produces, []) self.assertEqual(operation.path_name, '/pets/{pet_id}') # And now the real stuff... self.assertEqual(len(operation.params), 1) param = operation.params.get('pet_id') self.assertEqual(param.param_spec['required'], True) self.assertEqual(param.param_spec['in'], 'path') self.assertEqual(param.param_spec['type'], 'integer') self.assertEqual(param.fill, 42)
def test_no_model_json_object_complex_nested_in_body(self): specification_as_string = ComplexDereferencedNestedModel().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] # The specification says that this query string parameter is # required and there is only one parameter, so there is no second # operation with the optional parameters filled in. self.assertEqual(len(data), 1) data_i = data[0] factory = RequestFactory(*data_i) fuzzable_request = factory.get_fuzzable_request() e_url = 'http://www.w3af.com/swagger.json/pets' e_headers = Headers([('Content-Type', 'application/json')]) e_data = ('{"pet": {"owner": {"name": {"last": "Smith", "first": "56"},' ' "address": {"postalCode": "90210", "street1": "Bonsai Street 123",' ' "street2": "Bonsai Street 123", "state": "AK",' ' "city": "Buenos Aires"}}, "type": "cat", "name": "John",' ' "birthdate": "2017-06-30"}}') self.assertEqual(fuzzable_request.get_method(), 'POST') self.assertEqual(fuzzable_request.get_uri().url_string, e_url) self.assertEqual(fuzzable_request.get_headers(), e_headers) self.assertEqual(fuzzable_request.get_data(), e_data)
def test_no_model_json_object_complex_nested_in_body(self): specification_as_string = ComplexDereferencedNestedModel( ).get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] # The specification says that this query string parameter is # required and there is only one parameter, so there is no second # operation with the optional parameters filled in. self.assertEqual(len(data), 1) data_i = data[0] factory = RequestFactory(*data_i) fuzzable_request = factory.get_fuzzable_request() e_url = 'http://www.w3af.com/swagger.json/pets' e_headers = Headers([('Content-Type', 'application/json')]) e_data = ( '{"pet": {"owner": {"name": {"last": "Smith", "first": "56"},' ' "address": {"postalCode": "90210", "street1": "Bonsai Street 123",' ' "street2": "Bonsai Street 123", "state": "AK",' ' "city": "Buenos Aires"}}, "type": "cat", "name": "John",' ' "birthdate": "2017-06-30"}}') self.assertEqual(fuzzable_request.get_method(), 'POST') self.assertEqual(fuzzable_request.get_uri().url_string, e_url) self.assertEqual(fuzzable_request.get_headers(), e_headers) self.assertEqual(fuzzable_request.get_data(), e_data)
def test_no_model_json_object_with_int_param_in_body(self): specification_as_string = IntParamNoModelJson().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] # The specification says that this query string parameter is # required and there is only one parameter, so there is no second # operation with the optional parameters filled in. self.assertEqual(len(data), 1) (spec, api_resource_name, resource, operation_name, operation, parameters) = data[0] self.assertEqual(api_resource_name, 'pets') self.assertEqual(operation_name, 'addPet') self.assertEqual(operation.consumes, [u'application/json']) self.assertEqual(operation.produces, [u'application/json']) self.assertEqual(operation.path_name, '/pets') # Now we check the parameters for the operation self.assertEqual(len(operation.params), 1) param = operation.params.get('pet') self.assertEqual(param.param_spec['required'], True) self.assertEqual(param.param_spec['in'], 'body') self.assertIn('schema', param.param_spec) self.assertEqual(param.fill, {u'age': 42, u'name': 'John'})
def test_string_param_header(self): specification_as_string = StringParamHeader().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] # The specification says that this query string parameter is # required and there is only one parameter, so there is no second # operation with the optional parameters filled in. self.assertEqual(len(data), 1) (spec, api_resource_name, resource, operation_name, operation, parameters) = data[0] self.assertEqual(api_resource_name, 'pets') self.assertEqual(operation_name, 'findPets') self.assertEqual(operation.consumes, [u'application/json']) self.assertEqual(operation.produces, [u'application/json']) self.assertEqual(operation.path_name, '/pets') # Now we check the parameters for the operation self.assertEqual(len(operation.params), 1) param = operation.params.get('X-Foo-Header') self.assertEqual(param.param_spec['required'], True) self.assertEqual(param.param_spec['in'], 'header') self.assertEqual(param.param_spec['type'], 'string') self.assertEqual(param.fill, '56')
def test_array_with_model_items_param_in_json(self): specification_as_string = ArrayModelItems().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] # The specification says that this query string parameter is # required and there is only one parameter, so there is no second # operation with the optional parameters filled in. self.assertEqual(len(data), 1) (spec, api_resource_name, resource, operation_name, operation, parameters) = data[0] self.assertEqual(api_resource_name, 'pets') self.assertEqual(operation_name, 'addMultiplePets') self.assertEqual(operation.consumes, [u'application/json']) self.assertEqual(operation.produces, [u'application/json']) self.assertEqual(operation.path_name, '/pets') # Now we check the parameters for the operation self.assertEqual(len(operation.params), 1) param = operation.params.get('pets') self.assertEqual(param.param_spec['required'], True) self.assertEqual(param.param_spec['in'], 'body') self.assertIn('schema', param.param_spec) expected_value = [{u'name': 'John', u'tag': '7'}] self.assertEqual(param.fill, expected_value)
def test_string_param_header(self): specification_as_string = StringParamHeader().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] # The specification says that this query string parameter is # required and there is only one parameter, so there is no second # operation with the optional parameters filled in. self.assertEqual(len(data), 1) data_i = data[0] factory = RequestFactory(*data_i) fuzzable_request = factory.get_fuzzable_request() e_url = 'http://petstore.swagger.io/api/pets' e_headers = Headers([('X-Foo-Header', '56'), ('Content-Type', 'application/json')]) e_data = '' self.assertEqual(fuzzable_request.get_method(), 'GET') self.assertEqual(fuzzable_request.get_uri().url_string, e_url) self.assertEqual(fuzzable_request.get_headers(), e_headers) self.assertEqual(fuzzable_request.get_data(), e_data)
def test_model_param_nested_allOf_in_json(self): specification_as_string = NestedModel().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] self.assertEqual(len(data), 1) # The specification says that this query string parameter is # required and there is only one parameter, so there is no second # operation with the optional parameters filled in. self.assertEqual(len(data), 1) data_i = data[0] factory = RequestFactory(*data_i) fuzzable_request = factory.get_fuzzable_request() e_url = 'http://w3af.org/api/pets' e_headers = Headers([('Content-Type', 'application/json')]) e_data = '{"pet": {"tag": "7", "name": "John", "id": 42}}' self.assertEqual(fuzzable_request.get_method(), 'GET') self.assertEqual(fuzzable_request.get_uri().url_string, e_url) self.assertEqual(fuzzable_request.get_headers(), e_headers) self.assertEqual(fuzzable_request.get_data(), e_data)
def test_array_with_model_items_param_in_json(self): specification_as_string = ArrayModelItems().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] # The specification says that this query string parameter is # required and there is only one parameter, so there is no second # operation with the optional parameters filled in. self.assertEqual(len(data), 1) (spec, api_resource_name, resource, operation_name, operation, parameters) = data[0] self.assertEqual(api_resource_name, 'pets') self.assertEqual(operation_name, 'addMultiplePets') self.assertEqual(operation.consumes, [u'application/json']) self.assertEqual(operation.produces, [u'application/json']) self.assertEqual(operation.path_name, '/pets') # Now we check the parameters for the operation self.assertEqual(len(operation.params), 1) param = operation.params.get('pets') self.assertEqual(param.param_spec['required'], True) self.assertEqual(param.param_spec['in'], 'body') self.assertIn('schema', param.param_spec) expected_value = [{u'name': 'John', u'tag': '7'}] self.assertEqual(param.fill, expected_value)
def test_model_param_nested_loop_in_json(self): specification_as_string = NestedLoopModel().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] # `_parse_spec_from_dict` raises max recursion while trying to resolve # references for this (broken) model. self.assertEqual(len(data), 0)
def test_model_param_nested_loop_in_json(self): specification_as_string = NestedLoopModel().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] # `_parse_spec_from_dict` raises max recursion while trying to resolve # references for this (broken) model. self.assertEqual(len(data), 0)
def parse(self): """ Extract all the API endpoints using the bravado Open API parser """ specification_handler = SpecificationHandler(self.get_http_response()) for data in specification_handler.get_api_information(): request_factory = RequestFactory(*data) fuzzable_request = request_factory.get_fuzzable_request() if not self._should_audit(fuzzable_request): continue self.api_calls.append(fuzzable_request)
def parse(self): """ Extract all the API endpoints using the bravado Open API parser """ specification_handler = SpecificationHandler(self.get_http_response()) for data in specification_handler.get_api_information(): request_factory = RequestFactory(*data) fuzzable_request = request_factory.get_fuzzable_request() if not self._should_audit(fuzzable_request): continue self.api_calls.append(fuzzable_request)
def test_no_model_json_object_complex_nested_in_body(self): specification_as_string = ComplexDereferencedNestedModel( ).get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] # The specification says that this query string parameter is # required and there is only one parameter, so there is no second # operation with the optional parameters filled in. self.assertEqual(len(data), 1) (spec, api_resource_name, resource, operation_name, operation, parameters) = data[0] self.assertEqual(api_resource_name, 'pets') self.assertEqual(operation_name, 'post_pets') self.assertEqual(operation.consumes, [u'application/json']) self.assertEqual(operation.produces, [u'application/json']) self.assertEqual(operation.path_name, '/pets') # Now we check the parameters for the operation self.assertEqual(len(operation.params), 1) param = operation.params.get('pet') self.assertEqual(param.param_spec['required'], True) self.assertEqual(param.param_spec['in'], 'body') self.assertIn('schema', param.param_spec) expected_value = { u'birthdate': datetime.date(2017, 6, 30), u'name': 'John', u'owner': { u'address': { u'city': 'Buenos Aires', u'postalCode': '90210', u'state': 'AK', u'street1': 'Bonsai Street 123', u'street2': 'Bonsai Street 123' }, u'name': { u'first': '56', u'last': 'Smith' } }, u'type': u'cat' } self.assertEqual(param.fill, expected_value)
def parse(self): """ Extract all the API endpoints using the bravado Open API parser. The method also looks for all parameters which are passed to endpoints via headers, and stores them in to the fuzzable request """ self._specification_handler = SpecificationHandler( self.get_http_response(), validate_swagger_spec=self.validate_swagger_spec) for data in self._specification_handler.get_api_information(): try: request_factory = RequestFactory(*data) fuzzable_request = request_factory.get_fuzzable_request( self.discover_fuzzable_headers, self.discover_fuzzable_url_parts) except Exception, e: # # This is a strange situation because parsing of the OpenAPI # spec can fail awfully for one of the operations but succeed # for the rest. # # Usually we would simply stop processing the document, but it # is better to a) provide value to the user, and b) warn him # so that they can report the issue and improve w3af # # Just crashing wouldn't provide any value to the user # tb = get_traceback() path, filename, _function, line = get_exception_location(tb) spec_url = self.get_http_response().get_url() msg = ( 'Failed to generate a fuzzable request for one of the' ' OpenAPI operations. The parser will continue with the' ' next operation. The OpenAPI specification is at "%s" and' ' the exception was: "%s" at %s/%s:%s():%s.') args = (spec_url, e, path, filename, _function, line) om.out.error(msg % args) else: if not self._should_audit(fuzzable_request): continue self.api_calls.append(fuzzable_request)
def test_parameter_handler_no_model_json_object_complex_nested_in_body( self): specification_as_string = ComplexDereferencedNestedModel( ).get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) self.check_parameter_setting(handler)
def test_no_params(self): specification_as_string = NoParams().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] self.assertEqual(len(data), 1) (spec, api_resource_name, resource, operation_name, operation, parameters) = data[0] self.assertEqual(api_resource_name, 'random') self.assertEqual(operation_name, 'get_random') self.assertEqual(operation.consumes, []) self.assertEqual(operation.produces, []) self.assertEqual(operation.params, {}) self.assertEqual(operation.path_name, '/random')
def test_no_params(self): specification_as_string = NoParams().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] self.assertEqual(len(data), 1) (spec, api_resource_name, resource, operation_name, operation, parameters) = data[0] self.assertEqual(api_resource_name, 'random') self.assertEqual(operation_name, 'get_random') self.assertEqual(operation.consumes, []) self.assertEqual(operation.produces, []) self.assertEqual(operation.params, {}) self.assertEqual(operation.path_name, '/random')
def parse(self): """ Extract all the API endpoints using the bravado Open API parser. The method also looks for all parameters which are passed to endpoints via headers, and stores them in to the fuzzable request """ specification_handler = SpecificationHandler(self.get_http_response(), self.no_validation) for data in specification_handler.get_api_information(): try: request_factory = RequestFactory(*data) fuzzable_request = request_factory.get_fuzzable_request(self.discover_fuzzable_headers) except Exception, e: # # This is a strange situation because parsing of the OpenAPI # spec can fail awfully for one of the operations but succeed # for the rest. # # Usually we would simply stop processing the document, but it # is better to a) provide value to the user, and b) warn him # so that they can report the issue and improve w3af # # Just crashing wouldn't provide any value to the user # tb = get_traceback() path, filename, _function, line = get_exception_location(tb) spec_url = self.get_http_response().get_url() msg = ('Failed to generate a fuzzable request for one of the' ' OpenAPI operations. The parser will continue with the' ' next operation. The OpenAPI specification is at "%s" and' ' the exception was: "%s" at %s/%s:%s():%s.') args = (spec_url, e, path, filename, _function, line) om.out.error(msg % args) else: if not self._should_audit(fuzzable_request): continue self.api_calls.append(fuzzable_request)
def test_simple_int_param_in_qs(self): specification_as_string = IntParamQueryString().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] # The specification says that this query string parameter is not # required, thus we get two operations, one for the parameter with # a value and another without the parameter self.assertEqual(len(data), 2) # # Assertions on call #1 # data_i = data[0] factory = RequestFactory(*data_i) fuzzable_request = factory.get_fuzzable_request() e_url = 'http://w3af.org/api/pets' e_headers = Headers([('Content-Type', 'application/json')]) self.assertEqual(fuzzable_request.get_method(), 'GET') self.assertEqual(fuzzable_request.get_uri().url_string, e_url) self.assertEqual(fuzzable_request.get_headers(), e_headers) self.assertEqual(fuzzable_request.get_data(), '') # # Assertions on call #2 # data_i = data[1] factory = RequestFactory(*data_i) fuzzable_request = factory.get_fuzzable_request() e_url = 'http://w3af.org/api/pets?limit=42' e_headers = Headers([('Content-Type', 'application/json')]) self.assertEqual(fuzzable_request.get_method(), 'GET') self.assertEqual(fuzzable_request.get_uri().url_string, e_url) self.assertEqual(fuzzable_request.get_headers(), e_headers) self.assertEqual(fuzzable_request.get_data(), '')
def test_simple_int_param_in_qs(self): specification_as_string = IntParamQueryString().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] # The specification says that this query string parameter is not # required, thus we get two operations, one for the parameter with # a value and another without the parameter self.assertEqual(len(data), 2) # # Assertions on call #1 # data_i = data[0] factory = RequestFactory(*data_i) fuzzable_request = factory.get_fuzzable_request() e_url = 'http://w3af.org/api/pets' e_headers = Headers([('Content-Type', 'application/json')]) self.assertEqual(fuzzable_request.get_method(), 'GET') self.assertEqual(fuzzable_request.get_uri().url_string, e_url) self.assertEqual(fuzzable_request.get_headers(), e_headers) self.assertEqual(fuzzable_request.get_data(), '') # # Assertions on call #2 # data_i = data[1] factory = RequestFactory(*data_i) fuzzable_request = factory.get_fuzzable_request() e_url = 'http://w3af.org/api/pets?limit=42' e_headers = Headers([('Content-Type', 'application/json')]) self.assertEqual(fuzzable_request.get_method(), 'GET') self.assertEqual(fuzzable_request.get_uri().url_string, e_url) self.assertEqual(fuzzable_request.get_headers(), e_headers) self.assertEqual(fuzzable_request.get_data(), '')
def test_simple_int_param_in_path(self): specification_as_string = IntParamPath().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] self.assertEqual(len(data), 1) data_i = data[0] factory = RequestFactory(*data_i) fuzzable_request = factory.get_fuzzable_request() e_url = 'http://www.w3af.com/swagger.json/pets/42' e_headers = Headers([('Content-Type', 'application/json')]) self.assertEqual(fuzzable_request.get_method(), 'GET') self.assertEqual(fuzzable_request.get_uri().url_string, e_url) self.assertEqual(fuzzable_request.get_headers(), e_headers) self.assertEqual(fuzzable_request.get_raw_data(), '')
def test_no_params(self): specification_as_string = NoParams().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] self.assertEqual(len(data), 1) data_i = data[0] factory = RequestFactory(*data_i) fuzzable_request = factory.get_fuzzable_request() e_url = 'http://www.w3af.com/swagger.json/random' e_headers = Headers() self.assertEqual(fuzzable_request.get_method(), 'GET') self.assertEqual(fuzzable_request.get_uri().url_string, e_url) self.assertEqual(fuzzable_request.get_headers(), e_headers) self.assertEqual(fuzzable_request.get_raw_data(), '')
def test_no_params(self): specification_as_string = NoParams().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] self.assertEqual(len(data), 1) data_i = data[0] factory = RequestFactory(*data_i) fuzzable_request = factory.get_fuzzable_request() e_url = 'http://www.w3af.com/swagger.json/random' e_headers = Headers() self.assertEqual(fuzzable_request.get_method(), 'GET') self.assertEqual(fuzzable_request.get_uri().url_string, e_url) self.assertEqual(fuzzable_request.get_headers(), e_headers) self.assertEqual(fuzzable_request.get_raw_data(), '')
def test_simple_int_param_in_path(self): specification_as_string = IntParamPath().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] self.assertEqual(len(data), 1) data_i = data[0] factory = RequestFactory(*data_i) fuzzable_request = factory.get_fuzzable_request() e_url = 'http://www.w3af.com/swagger.json/pets/42' e_headers = Headers([('Content-Type', 'application/json')]) self.assertEqual(fuzzable_request.get_method(), 'GET') self.assertEqual(fuzzable_request.get_uri().url_string, e_url) self.assertEqual(fuzzable_request.get_headers(), e_headers) self.assertEqual(fuzzable_request.get_raw_data(), '')
def test_simple_int_param_in_qs(self): specification_as_string = IntParamQueryString().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] # The specification says that this query string parameter is not # required, thus we get two operations, one for the parameter with # a value and another without the parameter self.assertEqual(len(data), 2) (spec, api_resource_name, resource, operation_name, operation, parameters) = data[0] self.assertEqual(api_resource_name, 'pets') self.assertEqual(operation_name, 'findPets') self.assertEqual(operation.consumes, [u'application/json']) self.assertEqual(operation.produces, [u'application/json']) self.assertEqual(operation.path_name, '/pets') # Now we check the parameters for the operation self.assertEqual(len(operation.params), 1) param = operation.params.get('limit') self.assertEqual(param.param_spec['required'], False) self.assertEqual(param.param_spec['in'], 'query') self.assertEqual(param.param_spec['type'], 'integer') self.assertEqual(param.fill, None) # And check the second one too (spec, api_resource_name, resource, operation_name, operation, parameters) = data[1] self.assertEqual(len(operation.params), 1) param = operation.params.get('limit') self.assertEqual(param.param_spec['required'], False) self.assertEqual(param.param_spec['in'], 'query') self.assertEqual(param.param_spec['type'], 'integer') self.assertEqual(param.fill, 42)
def test_simple_int_param_in_qs(self): specification_as_string = IntParamQueryString().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] # The specification says that this query string parameter is not # required, thus we get two operations, one for the parameter with # a value and another without the parameter self.assertEqual(len(data), 2) (spec, api_resource_name, resource, operation_name, operation, parameters) = data[0] self.assertEqual(api_resource_name, 'pets') self.assertEqual(operation_name, 'findPets') self.assertEqual(operation.consumes, [u'application/json']) self.assertEqual(operation.produces, [u'application/json']) self.assertEqual(operation.path_name, '/pets') # Now we check the parameters for the operation self.assertEqual(len(operation.params), 1) param = operation.params.get('limit') self.assertEqual(param.param_spec['required'], False) self.assertEqual(param.param_spec['in'], 'query') self.assertEqual(param.param_spec['type'], 'integer') self.assertEqual(param.fill, None) # And check the second one too (spec, api_resource_name, resource, operation_name, operation, parameters) = data[1] self.assertEqual(len(operation.params), 1) param = operation.params.get('limit') self.assertEqual(param.param_spec['required'], False) self.assertEqual(param.param_spec['in'], 'query') self.assertEqual(param.param_spec['type'], 'integer') self.assertEqual(param.fill, 42)
def test_no_model_json_object_complex_nested_in_body(self): specification_as_string = ComplexDereferencedNestedModel().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] # The specification says that this query string parameter is # required and there is only one parameter, so there is no second # operation with the optional parameters filled in. self.assertEqual(len(data), 1) (spec, api_resource_name, resource, operation_name, operation, parameters) = data[0] self.assertEqual(api_resource_name, 'pets') self.assertEqual(operation_name, 'post_pets') self.assertEqual(operation.consumes, [u'application/json']) self.assertEqual(operation.produces, [u'application/json']) self.assertEqual(operation.path_name, '/pets') # Now we check the parameters for the operation self.assertEqual(len(operation.params), 1) param = operation.params.get('pet') self.assertEqual(param.param_spec['required'], True) self.assertEqual(param.param_spec['in'], 'body') self.assertIn('schema', param.param_spec) expected_value = {u'birthdate': datetime.date(2017, 6, 30), u'name': 'John', u'owner': {u'address': {u'city': 'Buenos Aires', u'postalCode': '90210', u'state': 'AK', u'street1': 'Bonsai Street 123', u'street2': 'Bonsai Street 123'}, u'name': {u'first': '56', u'last': 'Smith'}}, u'type': u'cat'} self.assertEqual(param.fill, expected_value)
def test_model_param_nested_loop_in_json(self): specification_as_string = NestedLoopModel().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] self.assertEqual(len(data), 1, data) # # Assertions on call #1 # spec, api_resource_name, resource, operation_name, operation, parameters = data[ 0] self.assertEqual(api_resource_name, 'pets') self.assertEqual(operation_name, 'findPets') self.assertEqual(operation.consumes, [u'application/json']) self.assertEqual(operation.produces, [ u'application/json', u'application/xml', u'text/xml', u'text/html' ]) self.assertEqual(operation.path_name, '/pets')
def test_model_with_int_param_json_example_value(self): specification_as_string = IntParamWithExampleJson().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] # The specification says that this query string parameter is # required and there is only one parameter, so there is no second # operation with the optional parameters filled in. self.assertEqual(len(data), 1) data_i = data[0] factory = RequestFactory(*data_i) fuzzable_request = factory.get_fuzzable_request() e_url = 'http://petstore.swagger.io/api/pets' e_headers = Headers([('Content-Type', 'application/json')]) self.assertEqual(fuzzable_request.get_method(), 'POST') self.assertEqual(fuzzable_request.get_uri().url_string, e_url) self.assertEqual(fuzzable_request.get_headers(), e_headers) self.assertEqual(fuzzable_request.get_data(), '{"pet": {"count": 666999}}')
def test_parameter_handler_multiple_paths_and_headers(self): specification_as_string = MultiplePathsAndHeaders().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) self.check_parameter_setting(handler)
def test_parameter_handler_model_param_nested_allOf_in_json(self): specification_as_string = NestedModel().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) self.check_parameter_setting(handler)
def test_dereferenced_pet_store(self): # See: dereferenced_pet_store.json , which was generated using # http://bigstickcarpet.com/swagger-parser/www/index.html# specification_as_string = DereferencedPetStore().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] self.assertEqual(len(data), 3) # # Assertions on call #1 # data_i = data[0] factory = RequestFactory(*data_i) fuzzable_request = factory.get_fuzzable_request() e_url = 'http://www.w3af.com/swagger.json/pets/John' e_headers = Headers([('Content-Type', 'application/json')]) e_data = '' self.assertEqual(fuzzable_request.get_method(), 'GET') self.assertEqual(fuzzable_request.get_uri().url_string, e_url) self.assertEqual(fuzzable_request.get_headers(), e_headers) self.assertEqual(fuzzable_request.get_data(), e_data) # # Assertions on call #2 # data_i = data[1] factory = RequestFactory(*data_i) fuzzable_request = factory.get_fuzzable_request() e_url = 'http://www.w3af.com/swagger.json/pets' e_headers = Headers([('Content-Type', 'application/json')]) e_data = '' self.assertEqual(fuzzable_request.get_method(), 'GET') self.assertEqual(fuzzable_request.get_uri().url_string, e_url) self.assertEqual(fuzzable_request.get_headers(), e_headers) self.assertEqual(fuzzable_request.get_data(), e_data) # # Assertions on call #3 # data_i = data[2] factory = RequestFactory(*data_i) fuzzable_request = factory.get_fuzzable_request() e_url = 'http://www.w3af.com/swagger.json/pets' e_headers = Headers([('Content-Type', 'application/json')]) e_data = ('{"pet": {"owner": {"name": {"last": "Smith", "first": "56"},' ' "address": {"postalCode": "90210", "street1": "Bonsai Street 123",' ' "street2": "Bonsai Street 123", "state": "AK",' ' "city": "Buenos Aires"}}, "type": "cat", "name": "John",' ' "birthdate": "2017-06-30"}}') self.assertEqual(fuzzable_request.get_method(), 'POST') self.assertEqual(fuzzable_request.get_uri().url_string, e_url) self.assertEqual(fuzzable_request.get_headers(), e_headers) self.assertEqual(fuzzable_request.get_data(), e_data)
def test_parameter_handler_array_string_items_param_in_qs(self): specification_as_string = ArrayStringItemsQueryString( ).get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) self.check_parameter_setting(handler)
def test_parameter_handler_simple_int_param_in_qs(self): specification_as_string = IntParamQueryString().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) self.check_parameter_setting(handler)
def test_parameter_handler_no_params(self): specification_as_string = NoParams().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) self.check_parameter_setting(handler)
def test_dereferenced_pet_store(self): # See: dereferenced_pet_store.json , which was generated using # http://bigstickcarpet.com/swagger-parser/www/index.html# specification_as_string = DereferencedPetStore().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] self.assertEqual(len(data), 3) # # Assertions on call #1 # (spec, api_resource_name, resource, operation_name, operation, parameters) = data[0] self.assertEqual(api_resource_name, 'pets') self.assertEqual(operation_name, 'get_pets_name') self.assertEqual(operation.consumes, [u'application/json']) self.assertEqual(operation.produces, [u'application/json']) self.assertEqual(operation.path_name, '/pets/{name}') # Now we check the parameters for the operation self.assertEqual(len(operation.params), 1) param = operation.params.get('name') self.assertEqual(param.param_spec['required'], True) self.assertEqual(param.param_spec['in'], 'path') self.assertEqual(param.param_spec['type'], 'string') expected_value = 'John' self.assertEqual(param.fill, expected_value) # # Assertions on call #2 # (spec, api_resource_name, resource, operation_name, operation, parameters) = data[1] self.assertEqual(api_resource_name, 'pets') self.assertEqual(operation_name, 'get_pets') self.assertEqual(operation.consumes, [u'application/json']) self.assertEqual(operation.produces, [u'application/json']) self.assertEqual(operation.path_name, '/pets') # Now we check the parameters for the operation self.assertEqual(len(operation.params), 0) # # Assertions on call #3 # (spec, api_resource_name, resource, operation_name, operation, parameters) = data[2] self.assertEqual(api_resource_name, 'pets') self.assertEqual(operation_name, 'post_pets') self.assertEqual(operation.consumes, [u'application/json']) self.assertEqual(operation.produces, [u'application/json']) self.assertEqual(operation.path_name, '/pets') # Now we check the parameters for the operation self.assertEqual(len(operation.params), 1) param = operation.params.get('pet') self.assertEqual(param.param_spec['required'], True) self.assertEqual(param.param_spec['in'], 'body') self.assertIn('schema', param.param_spec) expected_value = { u'owner': { u'name': { u'last': 'Smith', u'first': '56' }, u'address': { u'postalCode': '90210', u'street1': 'Bonsai Street 123', u'street2': 'Bonsai Street 123', u'state': 'AK', u'city': 'Buenos Aires' } }, u'type': 'cat', u'name': 'John', u'birthdate': datetime.date(2017, 6, 30) } self.assertEqual(param.fill, expected_value)
def test_dereferenced_pet_store(self): # See: dereferenced_pet_store.json , which was generated using # http://bigstickcarpet.com/swagger-parser/www/index.html# specification_as_string = DereferencedPetStore().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] self.assertEqual(len(data), 3) # # Assertions on call #1 # (spec, api_resource_name, resource, operation_name, operation, parameters) = data[0] self.assertEqual(api_resource_name, 'pets') self.assertEqual(operation_name, 'get_pets_name') self.assertEqual(operation.consumes, [u'application/json']) self.assertEqual(operation.produces, [u'application/json']) self.assertEqual(operation.path_name, '/pets/{name}') # Now we check the parameters for the operation self.assertEqual(len(operation.params), 1) param = operation.params.get('name') self.assertEqual(param.param_spec['required'], True) self.assertEqual(param.param_spec['in'], 'path') self.assertEqual(param.param_spec['type'], 'string') expected_value = 'John' self.assertEqual(param.fill, expected_value) # # Assertions on call #2 # (spec, api_resource_name, resource, operation_name, operation, parameters) = data[1] self.assertEqual(api_resource_name, 'pets') self.assertEqual(operation_name, 'get_pets') self.assertEqual(operation.consumes, [u'application/json']) self.assertEqual(operation.produces, [u'application/json']) self.assertEqual(operation.path_name, '/pets') # Now we check the parameters for the operation self.assertEqual(len(operation.params), 0) # # Assertions on call #3 # (spec, api_resource_name, resource, operation_name, operation, parameters) = data[2] self.assertEqual(api_resource_name, 'pets') self.assertEqual(operation_name, 'post_pets') self.assertEqual(operation.consumes, [u'application/json']) self.assertEqual(operation.produces, [u'application/json']) self.assertEqual(operation.path_name, '/pets') # Now we check the parameters for the operation self.assertEqual(len(operation.params), 1) param = operation.params.get('pet') self.assertEqual(param.param_spec['required'], True) self.assertEqual(param.param_spec['in'], 'body') self.assertIn('schema', param.param_spec) expected_value = {u'owner': {u'name': {u'last': 'Smith', u'first': '56'}, u'address': {u'postalCode': '90210', u'street1': 'Bonsai Street 123', u'street2': 'Bonsai Street 123', u'state': 'AK', u'city': 'Buenos Aires'}}, u'type': 'cat', u'name': 'John', u'birthdate': datetime.date(2017, 6, 30)} self.assertEqual(param.fill, expected_value)
class OpenAPI(BaseParser): """ This class parses REST API definitions written in OpenAPI [0] format using bravado-core [1]. The parser only returns interesting results for get_forms(), where all FuzzableRequests associated with REST API calls are returned. [0] https://www.openapis.org/ [1] https://github.com/Yelp/bravado-core :author: Andres Riancho ([email protected]) """ CONTENT_TYPES = ('application/json', 'text/yaml', 'text/x-yaml', 'application/yaml', 'application/x-yaml', 'application/octet-stream', 'application/vnd.oai.openapi', 'application/vnd.oai.openapi+json', 'application/vnd.oai.openapi;version=2.0') KEYWORDS = ('consumes', 'produces', 'swagger', 'openapi', 'paths') def __init__(self, http_response, validate_swagger_spec=False, discover_fuzzable_headers=True, discover_fuzzable_url_parts=True): super(OpenAPI, self).__init__(http_response) # Result self.api_calls = [] # Internal self._specification_handler = None # Configuration self.validate_swagger_spec = validate_swagger_spec self.discover_fuzzable_headers = discover_fuzzable_headers self.discover_fuzzable_url_parts = discover_fuzzable_url_parts @staticmethod def content_type_match(http_resp): """ :param http_resp: The HTTP response we want to parse :return: True if we know how to parse this content type """ for _type in OpenAPI.CONTENT_TYPES: if _type in http_resp.content_type: return True return False @staticmethod def matches_any_keyword(http_resp): """ :param http_resp: The HTTP response we want to parse :return: True if it seems that this page is an open api doc """ for keyword in OpenAPI.KEYWORDS: if keyword in http_resp.body: return True return False @staticmethod def is_valid_json_or_yaml(http_resp): """ :param http_resp: The HTTP response we want to parse :return: True if it seems that this page is an open api doc """ try: json.loads(http_resp.body) except ValueError: pass else: return True try: load(http_resp.body, Loader=Loader) except: return False else: return True @staticmethod def looks_like_json_or_yaml(http_resp): """ :param http_resp: The HTTP response we want to parse :return: True if it seems that this response body holds JSON or YAML """ return ':' in '\n'.join(http_resp.body.split('\n')[:20]) @staticmethod def can_parse(http_resp): """ :param http_resp: A http response object that contains a document of type JSON or YAML. :return: True if it seems that the HTTP response contains an Open API spec """ # # In the past we had this check: # # if not OpenAPI.content_type_match(http_resp): # return False # # But real-life testing showed that it was too restrictive. Some web # servers and frameworks did not return the "expected" content-types # which triggered bugs in can_parse() # # Had to replace it with two other checks, which is worse in performance, # more permissive, but should fix the bug # if http_resp.is_image(): return False if not OpenAPI.looks_like_json_or_yaml(http_resp): return False # Only parse documents that look like Open API docs if not OpenAPI.matches_any_keyword(http_resp): return False # Only parse if they are valid json or yaml docs if not OpenAPI.is_valid_json_or_yaml(http_resp): return False # It seems that this is an openapi doc, but we can't never be 100% # sure until we really parse it in OpenAPI.parse() return True def parse(self): """ Extract all the API endpoints using the bravado Open API parser. The method also looks for all parameters which are passed to endpoints via headers, and stores them in to the fuzzable request """ self._specification_handler = SpecificationHandler(self.get_http_response(), validate_swagger_spec=self.validate_swagger_spec) for data in self._specification_handler.get_api_information(): try: request_factory = RequestFactory(*data) fuzzable_request = request_factory.get_fuzzable_request(self.discover_fuzzable_headers, self.discover_fuzzable_url_parts) except Exception, e: # # This is a strange situation because parsing of the OpenAPI # spec can fail awfully for one of the operations but succeed # for the rest. # # Usually we would simply stop processing the document, but it # is better to a) provide value to the user, and b) warn him # so that they can report the issue and improve w3af # # Just crashing wouldn't provide any value to the user # tb = get_traceback() path, filename, _function, line = get_exception_location(tb) spec_url = self.get_http_response().get_url() msg = ('Failed to generate a fuzzable request for one of the' ' OpenAPI operations. The parser will continue with the' ' next operation. The OpenAPI specification is at "%s" and' ' the exception was: "%s" at %s/%s:%s():%s.') args = (spec_url, e, path, filename, _function, line) om.out.error(msg % args) else: if not self._should_audit(fuzzable_request): continue self.api_calls.append(fuzzable_request)
def test_dereferenced_pet_store(self): # See: dereferenced_pet_store.json , which was generated using # http://bigstickcarpet.com/swagger-parser/www/index.html# specification_as_string = DereferencedPetStore().get_specification() http_response = self.generate_response(specification_as_string) handler = SpecificationHandler(http_response) data = [d for d in handler.get_api_information()] self.assertEqual(len(data), 3) # # Assertions on call #1 # data_i = data[0] factory = RequestFactory(*data_i) fuzzable_request = factory.get_fuzzable_request() e_url = 'http://www.w3af.com/swagger.json/pets/John' e_headers = Headers([('Content-Type', 'application/json')]) e_data = '' self.assertEqual(fuzzable_request.get_method(), 'GET') self.assertEqual(fuzzable_request.get_uri().url_string, e_url) self.assertEqual(fuzzable_request.get_headers(), e_headers) self.assertEqual(fuzzable_request.get_data(), e_data) # # Assertions on call #2 # data_i = data[1] factory = RequestFactory(*data_i) fuzzable_request = factory.get_fuzzable_request() e_url = 'http://www.w3af.com/swagger.json/pets' e_headers = Headers([('Content-Type', 'application/json')]) e_data = '' self.assertEqual(fuzzable_request.get_method(), 'GET') self.assertEqual(fuzzable_request.get_uri().url_string, e_url) self.assertEqual(fuzzable_request.get_headers(), e_headers) self.assertEqual(fuzzable_request.get_data(), e_data) # # Assertions on call #3 # data_i = data[2] factory = RequestFactory(*data_i) fuzzable_request = factory.get_fuzzable_request() e_url = 'http://www.w3af.com/swagger.json/pets' e_headers = Headers([('Content-Type', 'application/json')]) e_data = ( '{"pet": {"owner": {"name": {"last": "Smith", "first": "56"},' ' "address": {"postalCode": "90210", "street1": "Bonsai Street 123",' ' "street2": "Bonsai Street 123", "state": "AK",' ' "city": "Buenos Aires"}}, "type": "cat", "name": "John",' ' "birthdate": "2017-06-30"}}') self.assertEqual(fuzzable_request.get_method(), 'POST') self.assertEqual(fuzzable_request.get_uri().url_string, e_url) self.assertEqual(fuzzable_request.get_headers(), e_headers) self.assertEqual(fuzzable_request.get_data(), e_data)