Skip to content

Commit

Permalink
Add 2 new HTTP fuzzers that sends null and empty bodies
Browse files Browse the repository at this point in the history
  • Loading branch information
en-milie committed Oct 8, 2023
1 parent e9c9d59 commit f8e42bd
Show file tree
Hide file tree
Showing 6 changed files with 235 additions and 4 deletions.
32 changes: 32 additions & 0 deletions src/main/java/com/endava/cats/fuzzer/http/EmptyBodyFuzzer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.endava.cats.fuzzer.http;

import com.endava.cats.annotations.HttpFuzzer;
import com.endava.cats.fuzzer.executor.SimpleExecutor;
import com.endava.cats.model.FuzzingData;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;

@Singleton
@HttpFuzzer
public class EmptyBodyFuzzer extends BaseHttpWithPayloadSimpleFuzzer {

@Inject
public EmptyBodyFuzzer(SimpleExecutor executor) {
super(executor);
}

@Override
protected String getScenario() {
return "Send a request with an empty string body";
}

@Override
protected String getPayload(FuzzingData data) {
return "";
}

@Override
public String description() {
return "send a request with a empty string body";
}
}
32 changes: 32 additions & 0 deletions src/main/java/com/endava/cats/fuzzer/http/NullBodyFuzzer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.endava.cats.fuzzer.http;

import com.endava.cats.annotations.HttpFuzzer;
import com.endava.cats.fuzzer.executor.SimpleExecutor;
import com.endava.cats.model.FuzzingData;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;

@Singleton
@HttpFuzzer
public class NullBodyFuzzer extends BaseHttpWithPayloadSimpleFuzzer {

@Inject
public NullBodyFuzzer(SimpleExecutor executor) {
super(executor);
}

@Override
protected String getScenario() {
return "Send a request with a NULL body";
}

@Override
protected String getPayload(FuzzingData data) {
return "null";
}

@Override
public String description() {
return "send a request with a NULL body";
}
}
3 changes: 1 addition & 2 deletions src/main/java/com/endava/cats/io/ServiceCaller.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import com.endava.cats.util.WordUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.html.HtmlEscapers;
import com.google.common.net.HttpHeaders;
import com.google.common.util.concurrent.RateLimiter;
import com.google.gson.JsonElement;
Expand Down Expand Up @@ -576,7 +575,7 @@ private String replacePathWithRefData(ServiceData data, String currentUrl) {
* @return the initial payload with reference data replaced and matching POST correlations for DELETE requests
*/
String replacePayloadWithRefData(ServiceData data) {
if (!data.isReplaceRefData()) {
if (!data.isReplaceRefData() || "null".equals(data.getPayload())) {
logger.note("Bypassing reference data replacement for path {}!", data.getRelativePath());
return data.getPayload();
} else {
Expand Down
4 changes: 2 additions & 2 deletions src/test/java/com/endava/cats/args/FilterArgumentsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ void shouldIncludeAllFuzzers() {
List<String> fuzzers = filterArguments.getFirstPhaseFuzzersForPath();

Assertions.assertThat(fuzzers).contains("LeadingControlCharsInHeadersFuzzer", "LeadingWhitespacesInHeadersFuzzer", "LeadingMultiCodePointEmojisInFieldsTrimValidateFuzzer"
, "RemoveFieldsFuzzer", "CheckSecurityHeadersFuzzer").hasSize(105);
, "RemoveFieldsFuzzer", "CheckSecurityHeadersFuzzer").hasSize(107);
}

@Test
Expand Down Expand Up @@ -151,7 +151,7 @@ void shouldReturnGetAndDeleteWhenNotHttpMethodSupplied() {

@Test
void shouldReturnAllRegisteredFuzzers() {
Assertions.assertThat(filterArguments.getAllRegisteredFuzzers()).hasSize(109);
Assertions.assertThat(filterArguments.getAllRegisteredFuzzers()).hasSize(111);
}

@Test
Expand Down
84 changes: 84 additions & 0 deletions src/test/java/com/endava/cats/fuzzer/http/EmptyBodyFuzzerTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.endava.cats.fuzzer.http;

import com.endava.cats.fuzzer.executor.SimpleExecutor;
import com.endava.cats.http.HttpMethod;
import com.endava.cats.http.ResponseCodeFamily;
import com.endava.cats.io.ServiceCaller;
import com.endava.cats.model.CatsResponse;
import com.endava.cats.model.FuzzingData;
import com.endava.cats.report.TestCaseExporter;
import com.endava.cats.report.TestCaseListener;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.junit.mockito.InjectSpy;
import io.swagger.v3.oas.models.media.StringSchema;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.test.util.ReflectionTestUtils;

import java.util.List;

@QuarkusTest
class EmptyBodyFuzzerTest {
private ServiceCaller serviceCaller;
@InjectSpy
private TestCaseListener testCaseListener;
private EmptyBodyFuzzer emptyBodyFuzzer;

@BeforeEach
void setup() {
serviceCaller = Mockito.mock(ServiceCaller.class);
SimpleExecutor simpleExecutor = new SimpleExecutor(testCaseListener, serviceCaller);
emptyBodyFuzzer = new EmptyBodyFuzzer(simpleExecutor);
ReflectionTestUtils.setField(testCaseListener, "testCaseExporter", Mockito.mock(TestCaseExporter.class));
}

@Test
void shouldNotRunForEmptyPayload() {
emptyBodyFuzzer.fuzz(Mockito.mock(FuzzingData.class));

Mockito.verifyNoInteractions(testCaseListener);
}

@Test
void givenAHttpMethodWithoutPayload_whenApplyingTheMalformedJsonFuzzer_thenTheResultsAreCorrectlyReported() {
FuzzingData data = FuzzingData.builder().method(HttpMethod.GET).reqSchema(new StringSchema()).requestContentTypes(List.of("application/json")).build();
ReflectionTestUtils.setField(data, "processedPayload", "{\"id\": 1}");

CatsResponse catsResponse = CatsResponse.builder().body("{}").responseCode(400).build();
Mockito.when(serviceCaller.call(Mockito.any())).thenReturn(catsResponse);
Mockito.doNothing().when(testCaseListener).reportResult(Mockito.any(), Mockito.eq(data), Mockito.any(), Mockito.any());

emptyBodyFuzzer.fuzz(data);
Mockito.verify(testCaseListener, Mockito.times(1)).skipTest(Mockito.any(), Mockito.anyString());
}

@Test
void givenAHttpMethodWithPayload_whenApplyingTheMalformedJsonFuzzer_thenTheResultsAreCorrectlyReported() {
FuzzingData data = FuzzingData.builder().method(HttpMethod.POST).reqSchema(new StringSchema()).requestContentTypes(List.of("application/json")).build();
ReflectionTestUtils.setField(data, "processedPayload", "{\"id\": 1}");

CatsResponse catsResponse = CatsResponse.builder().body("{}").responseCode(400).build();
Mockito.when(serviceCaller.call(Mockito.any())).thenReturn(catsResponse);
Mockito.doNothing().when(testCaseListener).reportResult(Mockito.any(), Mockito.eq(data), Mockito.any(), Mockito.any());

emptyBodyFuzzer.fuzz(data);
Mockito.verify(testCaseListener, Mockito.times(1)).reportResult(Mockito.any(), Mockito.eq(data), Mockito.eq(catsResponse), Mockito.eq(ResponseCodeFamily.FOURXX));
}

@Test
void shouldHaveToString() {
Assertions.assertThat(emptyBodyFuzzer).hasToString(emptyBodyFuzzer.getClass().getSimpleName());
}

@Test
void shouldHaveDescription() {
Assertions.assertThat(emptyBodyFuzzer.description()).isNotBlank();
}

@Test
void shouldNotSkipForAnyHttpMethod() {
Assertions.assertThat(emptyBodyFuzzer.skipForHttpMethods()).isEmpty();
}
}
84 changes: 84 additions & 0 deletions src/test/java/com/endava/cats/fuzzer/http/NullBodyFuzzerTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.endava.cats.fuzzer.http;

import com.endava.cats.fuzzer.executor.SimpleExecutor;
import com.endava.cats.http.HttpMethod;
import com.endava.cats.http.ResponseCodeFamily;
import com.endava.cats.io.ServiceCaller;
import com.endava.cats.model.CatsResponse;
import com.endava.cats.model.FuzzingData;
import com.endava.cats.report.TestCaseExporter;
import com.endava.cats.report.TestCaseListener;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.junit.mockito.InjectSpy;
import io.swagger.v3.oas.models.media.StringSchema;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.test.util.ReflectionTestUtils;

import java.util.List;

@QuarkusTest
class NullBodyFuzzerTest {
private ServiceCaller serviceCaller;
@InjectSpy
private TestCaseListener testCaseListener;
private NullBodyFuzzer nullBodyFuzzer;

@BeforeEach
void setup() {
serviceCaller = Mockito.mock(ServiceCaller.class);
SimpleExecutor simpleExecutor = new SimpleExecutor(testCaseListener, serviceCaller);
nullBodyFuzzer = new NullBodyFuzzer(simpleExecutor);
ReflectionTestUtils.setField(testCaseListener, "testCaseExporter", Mockito.mock(TestCaseExporter.class));
}

@Test
void shouldNotRunForEmptyPayload() {
nullBodyFuzzer.fuzz(Mockito.mock(FuzzingData.class));

Mockito.verifyNoInteractions(testCaseListener);
}

@Test
void givenAHttpMethodWithoutPayload_whenApplyingTheMalformedJsonFuzzer_thenTheResultsAreCorrectlyReported() {
FuzzingData data = FuzzingData.builder().method(HttpMethod.GET).reqSchema(new StringSchema()).requestContentTypes(List.of("application/json")).build();
ReflectionTestUtils.setField(data, "processedPayload", "{\"id\": 1}");

CatsResponse catsResponse = CatsResponse.builder().body("{}").responseCode(400).build();
Mockito.when(serviceCaller.call(Mockito.any())).thenReturn(catsResponse);
Mockito.doNothing().when(testCaseListener).reportResult(Mockito.any(), Mockito.eq(data), Mockito.any(), Mockito.any());

nullBodyFuzzer.fuzz(data);
Mockito.verify(testCaseListener, Mockito.times(1)).skipTest(Mockito.any(), Mockito.anyString());
}

@Test
void givenAHttpMethodWithPayload_whenApplyingTheMalformedJsonFuzzer_thenTheResultsAreCorrectlyReported() {
FuzzingData data = FuzzingData.builder().method(HttpMethod.POST).reqSchema(new StringSchema()).requestContentTypes(List.of("application/json")).build();
ReflectionTestUtils.setField(data, "processedPayload", "{\"id\": 1}");

CatsResponse catsResponse = CatsResponse.builder().body("{}").responseCode(400).build();
Mockito.when(serviceCaller.call(Mockito.any())).thenReturn(catsResponse);
Mockito.doNothing().when(testCaseListener).reportResult(Mockito.any(), Mockito.eq(data), Mockito.any(), Mockito.any());

nullBodyFuzzer.fuzz(data);
Mockito.verify(testCaseListener, Mockito.times(1)).reportResult(Mockito.any(), Mockito.eq(data), Mockito.eq(catsResponse), Mockito.eq(ResponseCodeFamily.FOURXX));
}

@Test
void shouldHaveToString() {
Assertions.assertThat(nullBodyFuzzer).hasToString(nullBodyFuzzer.getClass().getSimpleName());
}

@Test
void shouldHaveDescription() {
Assertions.assertThat(nullBodyFuzzer.description()).isNotBlank();
}

@Test
void shouldNotSkipForAnyHttpMethod() {
Assertions.assertThat(nullBodyFuzzer.skipForHttpMethods()).isEmpty();
}
}

0 comments on commit f8e42bd

Please sign in to comment.