fix: As a developer I want tests for the new API's and document them

This commit is contained in:
Marcel Haag 2022-11-21 13:33:57 +01:00 committed by Cel
parent a4536e9735
commit 076fa087e8
8 changed files with 564 additions and 58 deletions

View File

@ -95,10 +95,114 @@ include::{snippets}/updateProject/http-response.adoc[]
include::{snippets}/updateProject/response-fields.adoc[]
== Pentest
=== Get pentests for category
To get pentests by projectId and category, call the GET request /pentests with the appropriate parameters.
==== Request example
include::{snippets}/getPentestsByProjectIdAndCategory/http-request.adoc[]
==== Request structure
include::{snippets}/getPentestsByProjectIdAndCategory/request-parameters.adoc[]
==== Response example
include::{snippets}/getPentestsByProjectIdAndCategory/http-response.adoc[]
==== Response structure
include::{snippets}/getPentestsByProjectIdAndCategory/response-fields.adoc[]
=== Save pentest
To save a pentest, call the POST request /pentests/+{projectId}+
==== Request example
include::{snippets}/savePentestByProjectId/http-request.adoc[]
==== Request structure
include::{snippets}/savePentestByProjectId/path-parameters.adoc[]
==== Response example
include::{snippets}/savePentestByProjectId/http-response.adoc[]
==== Response structure
include::{snippets}/savePentestByProjectId/response-fields.adoc[]
=== Update pentest
To update a pentest, call the PATCH request /pentests/+{pentestId}+
==== Request example
include::{snippets}/updatePentestByProjectId/http-request.adoc[]
==== Response example
include::{snippets}/updatePentestByProjectId/http-response.adoc[]
==== Response structure
include::{snippets}/updatePentestByProjectId/response-fields.adoc[]
== Finding
=== Get findings for pentest
To get findings by pentestId, call the GET request /pentests/+{pentestId}+/findings.
==== Request example
include::{snippets}/getFindingsByPentestId/http-request.adoc[]
==== Request structure
include::{snippets}/getFindingsByPentestId/path-parameters.adoc[]
==== Response example
include::{snippets}/getFindingsByPentestId/http-response.adoc[]
==== Response structure
include::{snippets}/getFindingsByPentestId/response-fields.adoc[]
=== Save finding
To save a finding, call the POST request /pentests/+{pentestId}+/finding
==== Request example
include::{snippets}/saveFindingByPentestId/http-request.adoc[]
==== Request structure
include::{snippets}/saveFindingByPentestId/path-parameters.adoc[]
==== Response example
include::{snippets}/saveFindingByPentestId/http-response.adoc[]
==== Response structure
include::{snippets}/saveFindingByPentestId/response-fields.adoc[]
== Change History
|===
|Date |Change
|2022-12-02
|Added GET and POST endpoint for Findings
|2022-11-21
|Added GET, POST and PATCH endpoint for Pentests
|2022-03-07
|Added PATCH endpoint to update Projects
|2022-02-01
@ -110,25 +214,3 @@ include::{snippets}/updateProject/response-fields.adoc[]
|2021-02-12
|Initial version
|===
== Pentest
=== Get pentests by projectId and category
To get pentests by projectId and category, call the GET request /pentests with the appropriate parameters.
==== Request example
include::{snippets}/getPentestsByProjectIdAndCategory/http-request.adoc[]
==== Request Structure
include::{snippets}/getPentestsByProjectIdAndCategory/request-parameters.adoc[]
==== Response example
include::{snippets}/getPentestsByProjectIdAndCategory/http-response.adoc[]
==== Response structure
include::{snippets}/getPentestsByProjectIdAndCategory/response-fields.adoc[]

View File

@ -12,7 +12,7 @@ data class Finding (
val description: String,
val impact: String,
val affectedUrls: List<String>? = emptyList(),
val reproduction: String?,
val reproduction: String,
val mitigation: String?
)
@ -22,7 +22,7 @@ data class FindingRequestBody(
val description: String,
val impact: String,
val affectedUrls: List<String>? = emptyList(),
val reproduction: String?,
val reproduction: String,
val mitigation: String?
)

View File

@ -50,7 +50,6 @@ class PentestController(private val pentestService: PentestService, private val
}
}*/
// ToDo: Add Documentation & Tests
@PostMapping("/{projectId}")
fun savePentest(
@PathVariable(value = "projectId") projectId: String,
@ -61,7 +60,6 @@ class PentestController(private val pentestService: PentestService, private val
}
}
// ToDo: Add Documentation & Tests
@PatchMapping("/{pentestId}")
fun updatePentest(
@PathVariable(value = "pentestId") pentestId: String,
@ -72,18 +70,6 @@ class PentestController(private val pentestService: PentestService, private val
}
}
// ToDo: Add Documentation & Tests
@PostMapping("/{pentestId}/finding")
fun saveFinidng(
@PathVariable(value = "pentestId") pentestId: String,
@RequestBody body: FindingRequestBody
): Mono<ResponseEntity<ResponseBody>> {
return this.findingService.saveFinding(pentestId, body).map {
ResponseEntity.accepted().body(it.toFindingResponseBody())
}
}
// ToDo: Add Documentation & Tests
@GetMapping("/{pentestId}/findings")
fun getFindings(@PathVariable(value = "pentestId") pentestId: String): Mono<ResponseEntity<List<ResponseBody>>> {
return this.pentestService.getFindingIdsByPentestId(pentestId).flatMap { findingIds: List<String> ->
@ -95,4 +81,14 @@ class PentestController(private val pentestService: PentestService, private val
else ResponseEntity.ok(it)
}
}
@PostMapping("/{pentestId}/finding")
fun saveFinding(
@PathVariable(value = "pentestId") pentestId: String,
@RequestBody body: FindingRequestBody
): Mono<ResponseEntity<ResponseBody>> {
return this.findingService.saveFinding(pentestId, body).map {
ResponseEntity.accepted().body(it.toFindingResponseBody())
}
}
}

View File

@ -151,7 +151,7 @@ class ProjectService(private val projectRepository: ProjectRepository) {
it.toProject()
}.doOnError {
throw wrappedException(
logging = { logger.warn("Project Pentests could not be updated in Database. Thrown exception: ", it) },
logging = { logger.warn("Project Pentests could not be updated or saved in Database. Thrown exception: ", it) },
mappedException = TransactionInterruptedException(
"Project could not be updated.",
Errorcode.ProjectInsertionFailed

View File

@ -1,10 +1,14 @@
package com.securityc4po.api.pentest
import com.fasterxml.jackson.databind.ObjectMapper
import com.github.tomakehurst.wiremock.common.Json
import com.securityc4po.api.BaseDocumentationIntTest
import com.securityc4po.api.configuration.NP_NONNULL_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR
import com.securityc4po.api.configuration.RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE
import com.securityc4po.api.configuration.SIC_INNER_SHOULD_BE_STATIC
import com.securityc4po.api.finding.*
import com.securityc4po.api.project.Project
import com.securityc4po.api.project.ProjectEntity
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
@ -18,6 +22,7 @@ import org.springframework.restdocs.payload.JsonFieldType
import org.springframework.restdocs.payload.PayloadDocumentation
import org.springframework.restdocs.request.RequestDocumentation
import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation
import reactor.core.publisher.Mono
@SuppressFBWarnings(
SIC_INNER_SHOULD_BE_STATIC,
@ -28,6 +33,7 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
@Autowired
lateinit var mongoTemplate: MongoTemplate
var mapper = ObjectMapper()
@BeforeEach
fun init() {
@ -44,7 +50,7 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
inner class GetPentests {
@Test
fun getPentestsByProjectIdAndCategory() {
val projectId = "d2e126ba-f608-11ec-b939-0242ac120002"
val projectId = "d2e126ba-f608-11ec-b939-0242ac120025"
val category = "INFORMATION_GATHERING"
webTestClient.get()
.uri("/pentests?projectId={projectId}&category={category}", projectId, category)
@ -90,7 +96,7 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
private val pentestOne = Pentest(
id = "9c8af320-f608-11ec-b939-0242ac120002",
projectId = "d2e126ba-f608-11ec-b939-0242ac120002",
projectId = "d2e126ba-f608-11ec-b939-0242ac120025",
category = PentestCategory.INFORMATION_GATHERING,
refNumber = "OTG-INFO-001",
status = PentestStatus.NOT_STARTED,
@ -99,11 +105,11 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
)
private val pentestTwo = Pentest(
id = "43fbc63c-f624-11ec-b939-0242ac120002",
projectId = "d2e126ba-f608-11ec-b939-0242ac120002",
projectId = "d2e126ba-f608-11ec-b939-0242ac120025",
category = PentestCategory.INFORMATION_GATHERING,
refNumber = "OTG-INFO-002",
status = PentestStatus.IN_PROGRESS,
findingIds = emptyList(),
findingIds = listOf("ab62d365-1b1d-4da1-89bc-5496616e220f"),
commentIds = emptyList()
)
@ -113,11 +119,260 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
)
}
@Nested
inner class SavePentest {
@Test
fun savePentestByProjectId() {
val projectId = "d2e126ba-f608-11ec-b939-0242ac120025"
webTestClient.post()
.uri("/pentests/{projectId}", projectId)
.header("Authorization", "Bearer $tokenAdmin")
.body(Mono.just(newPentestBody), PentestRequestBody::class.java)
.exchange()
.expectStatus().isAccepted
.expectHeader().doesNotExist("")
.expectBody().json(Json.write(newPentestBody))
.consumeWith(
WebTestClientRestDocumentation.document(
"{methodName}",
Preprocessors.preprocessRequest(
Preprocessors.prettyPrint(),
Preprocessors.modifyUris().removePort(),
Preprocessors.removeHeaders("Host", "Content-Length")
),
Preprocessors.preprocessResponse(
Preprocessors.prettyPrint()
),
RequestDocumentation.relaxedPathParameters(
RequestDocumentation.parameterWithName("projectId").description("The id of the project you want to save the pentest for")
),
PayloadDocumentation.relaxedResponseFields(
PayloadDocumentation.fieldWithPath("id").type(JsonFieldType.STRING)
.description("The id of the created pentest"),
PayloadDocumentation.fieldWithPath("projectId").type(JsonFieldType.STRING)
.description("The id of the project of the created pentest"),
PayloadDocumentation.fieldWithPath("category").type(JsonFieldType.STRING)
.description("The category of the created pentest"),
PayloadDocumentation.fieldWithPath("refNumber").type(JsonFieldType.STRING)
.description("The reference number of the created pentest according to the current OWASP Testing Guide"),
PayloadDocumentation.fieldWithPath("status").type(JsonFieldType.STRING)
.description("The status of the created pentest"),
PayloadDocumentation.fieldWithPath("findingIds").type(JsonFieldType.ARRAY)
.description("List of ids of the findings in the created pentest"),
PayloadDocumentation.fieldWithPath("commentIds").type(JsonFieldType.ARRAY)
.description("List of ids of the comments of the created pentest")
)
)
)
}
val newPentestBody = PentestRequestBody(
projectId = "d2e126ba-f608-11ec-b939-0242ac120025",
category = "CLIENT_SIDE_TESTING",
refNumber = "OTG-CLIENT-001",
status = "IN_PROGRESS",
findingIds = emptyList<String>(),
commentIds = emptyList<String>()
)
}
@Nested
inner class UpdatePentest {
@Test
fun updatePentestByProjectId() {
val pentestOneId = "9c8af320-f608-11ec-b939-0242ac120002"
webTestClient.patch()
.uri("/pentests/{pentestId}", pentestOneId)
.header("Authorization", "Bearer $tokenAdmin")
.body(Mono.just(pentestOneBody), PentestRequestBody::class.java)
.exchange()
.expectStatus().isAccepted
.expectHeader().doesNotExist("")
.expectBody().json(Json.write(pentestOneBody))
.consumeWith(
WebTestClientRestDocumentation.document(
"{methodName}",
Preprocessors.preprocessRequest(
Preprocessors.prettyPrint(),
Preprocessors.modifyUris().removePort(),
Preprocessors.removeHeaders("Host", "Content-Length")
),
Preprocessors.preprocessResponse(
Preprocessors.prettyPrint()
),
RequestDocumentation.relaxedPathParameters(
RequestDocumentation.parameterWithName("pentestId").description("The id of the pentest you want to update")
),
PayloadDocumentation.relaxedResponseFields(
PayloadDocumentation.fieldWithPath("id").type(JsonFieldType.STRING)
.description("The id of the updated pentest"),
PayloadDocumentation.fieldWithPath("projectId").type(JsonFieldType.STRING)
.description("The id of the project of the updated pentest"),
PayloadDocumentation.fieldWithPath("category").type(JsonFieldType.STRING)
.description("The category of the updated pentest"),
PayloadDocumentation.fieldWithPath("refNumber").type(JsonFieldType.STRING)
.description("The reference number of the updated pentest according to the current OWASP Testing Guide"),
PayloadDocumentation.fieldWithPath("status").type(JsonFieldType.STRING)
.description("The status of the updated pentest"),
PayloadDocumentation.fieldWithPath("findingIds").type(JsonFieldType.ARRAY)
.description("List of ids of the findings in the updated pentest"),
PayloadDocumentation.fieldWithPath("commentIds").type(JsonFieldType.ARRAY)
.description("List of ids of the comments of the updated pentest")
)
)
)
}
val pentestOneBody = PentestRequestBody(
projectId = "d2e126ba-f608-11ec-b939-0242ac120025",
category = "INFORMATION_GATHERING",
refNumber = "OTG-INFO-001",
status = "OPEN",
findingIds = emptyList<String>(),
commentIds = emptyList<String>()
)
}
@Nested
inner class GetFindings {
@Test
fun getFindingsByPentestId() {
val pentestTwoId = "43fbc63c-f624-11ec-b939-0242ac120002"
webTestClient.get()
.uri("/pentests/{pentestId}/findings", pentestTwoId)
.header("Authorization", "Bearer $tokenAdmin")
.exchange()
.expectStatus().isOk
.expectHeader().doesNotExist("")
.expectBody().json(Json.write(getFindingsResponse()))
.consumeWith(
WebTestClientRestDocumentation.document(
"{methodName}",
Preprocessors.preprocessRequest(
Preprocessors.prettyPrint(),
Preprocessors.modifyUris().removePort(),
Preprocessors.removeHeaders("Host", "Content-Length")
),
Preprocessors.preprocessResponse(
Preprocessors.prettyPrint()
),
RequestDocumentation.relaxedPathParameters(
RequestDocumentation.parameterWithName("pentestId").description("The id of the pentest you want to get the findings for")
),
PayloadDocumentation.relaxedResponseFields(
PayloadDocumentation.fieldWithPath("[].id").type(JsonFieldType.STRING)
.description("The id of the requested pentest"),
PayloadDocumentation.fieldWithPath("[].severity").type(JsonFieldType.STRING)
.description("The severity of the finding"),
PayloadDocumentation.fieldWithPath("[].title").type(JsonFieldType.STRING)
.description("The title of the requested finding"),
PayloadDocumentation.fieldWithPath("[].description").type(JsonFieldType.STRING)
.description("The description number of the finding"),
PayloadDocumentation.fieldWithPath("[].impact").type(JsonFieldType.STRING)
.description("The impact of the finding"),
PayloadDocumentation.fieldWithPath("[].affectedUrls").type(JsonFieldType.ARRAY)
.description("List of affected Urls of the finding"),
PayloadDocumentation.fieldWithPath("[].reproduction").type(JsonFieldType.STRING)
.description("The reproduction steps of the finding"),
PayloadDocumentation.fieldWithPath("[].mitigation").type(JsonFieldType.STRING)
.description("The example mitigation for the finding")
)
)
)
}
private val findingOne = Finding(
id = "ab62d365-1b1d-4da1-89bc-5496616e220f",
severity = Severity.LOW,
title = "Found Bug",
description = "OTG-INFO-002 Bug",
impact = "Service",
affectedUrls = emptyList(),
reproduction = "Step 1: Hack",
mitigation = "None"
)
private fun getFindingsResponse() = listOf(
findingOne.toFindingResponseBody()
)
}
@Nested
inner class SaveFinding {
@Test
fun saveFindingByPentestId() {
val pentestTwoId = "43fbc63c-f624-11ec-b939-0242ac120002"
webTestClient.post()
.uri("/pentests/{pentestId}/finding", pentestTwoId)
.header("Authorization", "Bearer $tokenAdmin")
.body(Mono.just(findingBody), FindingRequestBody::class.java)
.exchange()
.expectStatus().isAccepted
.expectHeader().doesNotExist("")
.expectBody().json(Json.write(findingBody))
.consumeWith(
WebTestClientRestDocumentation.document(
"{methodName}",
Preprocessors.preprocessRequest(
Preprocessors.prettyPrint(),
Preprocessors.modifyUris().removePort(),
Preprocessors.removeHeaders("Host", "Content-Length")
),
Preprocessors.preprocessResponse(
Preprocessors.prettyPrint()
),
RequestDocumentation.relaxedPathParameters(
RequestDocumentation.parameterWithName("pentestId").description("The id of the pentest you want to save the finding for")
),
PayloadDocumentation.relaxedResponseFields(
PayloadDocumentation.fieldWithPath("id").type(JsonFieldType.STRING)
.description("The id of the requested pentest"),
PayloadDocumentation.fieldWithPath("severity").type(JsonFieldType.STRING)
.description("The severity of the finding"),
PayloadDocumentation.fieldWithPath("title").type(JsonFieldType.STRING)
.description("The title of the requested finding"),
PayloadDocumentation.fieldWithPath("description").type(JsonFieldType.STRING)
.description("The description number of the finding"),
PayloadDocumentation.fieldWithPath("impact").type(JsonFieldType.STRING)
.description("The impact of the finding"),
PayloadDocumentation.fieldWithPath("affectedUrls").type(JsonFieldType.ARRAY)
.description("List of affected Urls of the finding"),
PayloadDocumentation.fieldWithPath("reproduction").type(JsonFieldType.STRING)
.description("The reproduction steps of the finding"),
PayloadDocumentation.fieldWithPath("mitigation").type(JsonFieldType.STRING)
.description("The example mitigation for the finding")
)
)
)
}
private val findingBody = FindingRequestBody(
severity = "MEDIUM",
title = "Found another Bug",
description = "Another OTG-INFO-002 Bug",
impact = "Service",
affectedUrls = emptyList(),
reproduction = "Step 1: Hack more",
mitigation = "Another None"
)
}
private fun persistBasicTestScenario() {
// setup test data
// Project
val projectOne = Project(
id = "d2e126ba-f608-11ec-b939-0242ac120025",
client = "E Corp",
title = "Some Mock API (v1.0) Scanning",
createdAt = "2021-01-10T18:05:00Z",
tester = "Novatester",
projectPentests = emptyList(),
createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032"
)
// Pentests
val pentestOne = Pentest(
id = "9c8af320-f608-11ec-b939-0242ac120002",
projectId = "d2e126ba-f608-11ec-b939-0242ac120002",
projectId = "d2e126ba-f608-11ec-b939-0242ac120025",
category = PentestCategory.INFORMATION_GATHERING,
refNumber = "OTG-INFO-001",
status = PentestStatus.NOT_STARTED,
@ -126,26 +381,39 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
)
val pentestTwo = Pentest(
id = "43fbc63c-f624-11ec-b939-0242ac120002",
projectId = "d2e126ba-f608-11ec-b939-0242ac120002",
projectId = "d2e126ba-f608-11ec-b939-0242ac120025",
category = PentestCategory.INFORMATION_GATHERING,
refNumber = "OTG-INFO-002",
status = PentestStatus.IN_PROGRESS,
findingIds = emptyList(),
findingIds = listOf("ab62d365-1b1d-4da1-89bc-5496616e220f"),
commentIds = emptyList()
)
val pentestThree = Pentest(
id = "74eae112-f62c-11ec-b939-0242ac120002",
projectId = "6fad3474-fc29-49f9-bd37-e039e9e60c18",
projectId = "d2e126ba-f608-11ec-b939-0242ac120025",
category = PentestCategory.AUTHENTICATION_TESTING,
refNumber = "OTG-AUTHN-001",
status = PentestStatus.COMPLETED,
findingIds = emptyList(),
commentIds = emptyList()
)
// Findings
val findingOne = Finding(
id = "ab62d365-1b1d-4da1-89bc-5496616e220f",
severity = Severity.LOW,
title = "Found Bug",
description = "OTG-INFO-002 Bug",
impact = "Service",
affectedUrls = emptyList(),
reproduction = "Step 1: Hack",
mitigation = "None"
)
// persist test data in database
mongoTemplate.save(ProjectEntity(projectOne))
mongoTemplate.save(PentestEntity(pentestOne))
mongoTemplate.save(PentestEntity(pentestTwo))
mongoTemplate.save(PentestEntity(pentestThree))
mongoTemplate.save(FindingEntity(findingOne))
}
private fun configureAdminToken() {
@ -153,7 +421,9 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
}
private fun cleanUp() {
mongoTemplate.findAllAndRemove(Query(), ProjectEntity::class.java)
mongoTemplate.findAllAndRemove(Query(), PentestEntity::class.java)
mongoTemplate.findAllAndRemove(Query(), FindingEntity::class.java)
tokenAdmin = "n/a"
}

View File

@ -5,6 +5,9 @@ import com.securityc4po.api.BaseIntTest
import com.securityc4po.api.configuration.NP_NONNULL_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR
import com.securityc4po.api.configuration.RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE
import com.securityc4po.api.configuration.SIC_INNER_SHOULD_BE_STATIC
import com.securityc4po.api.finding.*
import com.securityc4po.api.project.Project
import com.securityc4po.api.project.ProjectEntity
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
@ -15,6 +18,7 @@ import org.springframework.boot.web.server.LocalServerPort
import org.springframework.data.mongodb.core.MongoTemplate
import org.springframework.data.mongodb.core.query.Query
import org.springframework.test.web.reactive.server.WebTestClient
import reactor.core.publisher.Mono
import java.time.Duration
@SuppressFBWarnings(
@ -56,8 +60,10 @@ class PentestControllerIntTest : BaseIntTest() {
inner class GetPentests {
@Test
fun `requesting pentests by projectId and category successfully`() {
val projectId = "d2e126ba-f608-11ec-b939-0242ac120025"
val category = "INFORMATION_GATHERING"
webTestClient.get()
.uri("/pentests?projectId=d2e126ba-f608-11ec-b939-0242ac120002&category=INFORMATION_GATHERING")
.uri("/pentests?projectId={projectId}&category={category}", projectId, category)
.header("Authorization", "Bearer $tokenAdmin")
.exchange()
.expectStatus().isOk
@ -67,7 +73,7 @@ class PentestControllerIntTest : BaseIntTest() {
private val pentestOne = Pentest(
id = "9c8af320-f608-11ec-b939-0242ac120002",
projectId = "d2e126ba-f608-11ec-b939-0242ac120002",
projectId = "d2e126ba-f608-11ec-b939-0242ac120025",
category = PentestCategory.INFORMATION_GATHERING,
refNumber = "OTG-INFO-001",
status = PentestStatus.NOT_STARTED,
@ -76,11 +82,11 @@ class PentestControllerIntTest : BaseIntTest() {
)
private val pentestTwo = Pentest(
id = "43fbc63c-f624-11ec-b939-0242ac120002",
projectId = "d2e126ba-f608-11ec-b939-0242ac120002",
projectId = "d2e126ba-f608-11ec-b939-0242ac120025",
category = PentestCategory.INFORMATION_GATHERING,
refNumber = "OTG-INFO-002",
status = PentestStatus.IN_PROGRESS,
findingIds = emptyList(),
findingIds = listOf("ab62d365-1b1d-4da1-89bc-5496616e220f"),
commentIds = emptyList()
)
@ -90,11 +96,147 @@ class PentestControllerIntTest : BaseIntTest() {
)
}
@Nested
inner class SavePentest {
@Test
fun `save pentest successfully`() {
val projectId = "d2e126ba-f608-11ec-b939-0242ac120025"
webTestClient.post()
.uri("/pentests/{projectId}", projectId)
.header("Authorization", "Bearer $tokenAdmin")
.body(Mono.just(pentestRequestBody), PentestRequestBody::class.java)
.exchange()
.expectStatus().isAccepted
.expectHeader().valueEquals("Application-Name", "SecurityC4PO")
.expectBody()
.jsonPath("$.projectId").isEqualTo("d2e126ba-f608-11ec-b939-0242ac120025")
.jsonPath("$.category").isEqualTo("CLIENT_SIDE_TESTING")
.jsonPath("$.refNumber").isEqualTo("OTG-CLIENT-001")
.jsonPath("$.status").isEqualTo("IN_PROGRESS")
.jsonPath("$.findingIds").isEmpty
.jsonPath("$.commentIds").isEmpty
}
val pentestRequestBody = PentestRequestBody(
projectId = "d2e126ba-f608-11ec-b939-0242ac120025",
category = "CLIENT_SIDE_TESTING",
refNumber = "OTG-CLIENT-001",
status = "IN_PROGRESS",
findingIds = emptyList<String>(),
commentIds = emptyList<String>()
)
}
@Nested
inner class UpdatePentest {
@Test
fun `update pentest successfully`() {
val pentestOneId = "9c8af320-f608-11ec-b939-0242ac120002"
webTestClient.patch()
.uri("/pentests/{pentestId}", pentestOneId)
.header("Authorization", "Bearer $tokenAdmin")
.body(Mono.just(pentestOneRequestBody), PentestRequestBody::class.java)
.exchange()
.expectStatus().isAccepted
.expectHeader().valueEquals("Application-Name", "SecurityC4PO")
.expectBody()
.jsonPath("$.id").isEqualTo(pentestOneId)
.jsonPath("$.projectId").isEqualTo("d2e126ba-f608-11ec-b939-0242ac120025")
.jsonPath("$.category").isEqualTo("INFORMATION_GATHERING")
.jsonPath("$.refNumber").isEqualTo("OTG-INFO-001")
.jsonPath("$.status").isEqualTo("OPEN")
.jsonPath("$.findingIds").isEmpty
.jsonPath("$.commentIds").isEmpty
}
val pentestOneRequestBody = PentestRequestBody(
projectId = "d2e126ba-f608-11ec-b939-0242ac120025",
category = "INFORMATION_GATHERING",
refNumber = "OTG-INFO-001",
status = "OPEN",
findingIds = emptyList<String>(),
commentIds = emptyList<String>()
)
}
@Nested
inner class GetFindings {
@Test
fun `requesting findings by pentestId successfully`() {
val pentestTwoId = "43fbc63c-f624-11ec-b939-0242ac120002"
webTestClient.get()
.uri("/pentests/{pentestId}/findings", pentestTwoId)
.header("Authorization", "Bearer $tokenAdmin")
.exchange()
.expectStatus().isOk
.expectHeader().valueEquals("Application-Name", "SecurityC4PO")
.expectBody().json(Json.write(getFindings()))
}
private val findingOne = Finding(
id = "ab62d365-1b1d-4da1-89bc-5496616e220f",
severity = Severity.LOW,
title = "Found Bug",
description = "OTG-INFO-002 Bug",
impact = "Service",
affectedUrls = emptyList(),
reproduction = "Step 1: Hack",
mitigation = "None"
)
private fun getFindings() = listOf(
findingOne.toFindingResponseBody()
)
}
@Nested
inner class SaveFindings {
@Test
fun `save finding successfully`() {
val pentestTwoId = "43fbc63c-f624-11ec-b939-0242ac120002"
webTestClient.post()
.uri("/pentests/{pentestId}/finding", pentestTwoId)
.header("Authorization", "Bearer $tokenAdmin")
.body(Mono.just(findingBody), FindingRequestBody::class.java)
.exchange()
.expectStatus().isAccepted
.expectHeader().valueEquals("Application-Name", "SecurityC4PO")
.expectBody()
.jsonPath("$.severity").isEqualTo("MEDIUM")
.jsonPath("$.title").isEqualTo("Found another Bug")
.jsonPath("$.description").isEqualTo("Another OTG-INFO-002 Bug")
.jsonPath("$.impact").isEqualTo("Service")
.jsonPath("$.affectedUrls").isEmpty
.jsonPath("$.reproduction").isEqualTo("Step 1: Hack more")
.jsonPath("$.mitigation").isEqualTo("Another None")
}
private val findingBody = FindingRequestBody(
severity = "MEDIUM",
title = "Found another Bug",
description = "Another OTG-INFO-002 Bug",
impact = "Service",
affectedUrls = emptyList(),
reproduction = "Step 1: Hack more",
mitigation = "Another None"
)
}
private fun persistBasicTestScenario() {
// setup test data
// project
val projectOne = Project(
id = "d2e126ba-f608-11ec-b939-0242ac120025",
client = "E Corp",
title = "Some Mock API (v1.0) Scanning",
createdAt = "2021-01-10T18:05:00Z",
tester = "Novatester",
createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032"
)
// pentests
val pentestOne = Pentest(
id = "9c8af320-f608-11ec-b939-0242ac120002",
projectId = "d2e126ba-f608-11ec-b939-0242ac120002",
projectId = "d2e126ba-f608-11ec-b939-0242ac120025",
category = PentestCategory.INFORMATION_GATHERING,
refNumber = "OTG-INFO-001",
status = PentestStatus.NOT_STARTED,
@ -103,26 +245,39 @@ class PentestControllerIntTest : BaseIntTest() {
)
val pentestTwo = Pentest(
id = "43fbc63c-f624-11ec-b939-0242ac120002",
projectId = "d2e126ba-f608-11ec-b939-0242ac120002",
projectId = "d2e126ba-f608-11ec-b939-0242ac120025",
category = PentestCategory.INFORMATION_GATHERING,
refNumber = "OTG-INFO-002",
status = PentestStatus.IN_PROGRESS,
findingIds = emptyList(),
findingIds = listOf("ab62d365-1b1d-4da1-89bc-5496616e220f"),
commentIds = emptyList()
)
val pentestThree = Pentest(
id = "74eae112-f62c-11ec-b939-0242ac120002",
projectId = "6fad3474-fc29-49f9-bd37-e039e9e60c18",
id = "16vbc63c-f624-11ec-b939-0242ac120002",
projectId = "d2e126ba-f608-11ec-b939-0242ac120025",
category = PentestCategory.AUTHENTICATION_TESTING,
refNumber = "OTG-AUTHN-001",
status = PentestStatus.COMPLETED,
findingIds = emptyList(),
commentIds = emptyList()
)
// Finding
val findingOne = Finding(
id = "ab62d365-1b1d-4da1-89bc-5496616e220f",
severity = Severity.LOW,
title = "Found Bug",
description = "OTG-INFO-002 Bug",
impact = "Service",
affectedUrls = emptyList(),
reproduction = "Step 1: Hack",
mitigation = "None"
)
// persist test data in database
mongoTemplate.save(ProjectEntity(projectOne))
mongoTemplate.save(PentestEntity(pentestOne))
mongoTemplate.save(PentestEntity(pentestTwo))
mongoTemplate.save(PentestEntity(pentestThree))
mongoTemplate.save(FindingEntity(findingOne))
}
private fun configureAdminToken() {
@ -130,7 +285,9 @@ class PentestControllerIntTest : BaseIntTest() {
}
private fun cleanUp() {
mongoTemplate.findAllAndRemove(Query(), ProjectEntity::class.java)
mongoTemplate.findAllAndRemove(Query(), PentestEntity::class.java)
mongoTemplate.findAllAndRemove(Query(), FindingEntity::class.java)
tokenAdmin = "n/a"
}

View File

@ -92,7 +92,8 @@ class ProjectControllerIntTest : BaseIntTest() {
inner class SaveProject {
@Test
fun `save project successfully`() {
webTestClient.post().uri("/projects")
webTestClient.post()
.uri("/projects")
.header("Authorization", "Bearer $tokenAdmin")
.body(Mono.just(project), ProjectRequestBody::class.java)
.exchange()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 286 KiB

After

Width:  |  Height:  |  Size: 283 KiB