Test all security of routes #76
This commit is contained in:
@@ -124,8 +124,6 @@ paths:
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/article'
|
||||
get:
|
||||
security:
|
||||
- JWTAuth: []
|
||||
summary: Get one article
|
||||
tags:
|
||||
- article
|
||||
@@ -1138,8 +1136,6 @@ paths:
|
||||
/workgroups:
|
||||
get:
|
||||
summary: Get all Workgroup (Paginated)
|
||||
security:
|
||||
- JWTAuth: [ ]
|
||||
tags:
|
||||
- workgroup
|
||||
parameters:
|
||||
@@ -1206,8 +1202,6 @@ paths:
|
||||
- $ref: '#/components/parameters/workgroup'
|
||||
get:
|
||||
summary: Get one workgroup by ID
|
||||
security:
|
||||
- JWTAuth: [ ]
|
||||
tags:
|
||||
- workgroup
|
||||
responses:
|
||||
|
||||
147
src/test/kotlin/integration/Check auth on all routes.kt
Normal file
147
src/test/kotlin/integration/Check auth on all routes.kt
Normal file
@@ -0,0 +1,147 @@
|
||||
package integration
|
||||
|
||||
import fr.dcproject.common.utils.getResource
|
||||
import io.ktor.http.ContentType
|
||||
import io.ktor.http.HttpHeaders
|
||||
import io.ktor.http.HttpMethod
|
||||
import io.ktor.http.HttpStatusCode
|
||||
import org.junit.jupiter.api.Tag
|
||||
import org.junit.jupiter.api.Tags
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import org.openapi4j.core.model.OAIContext
|
||||
import org.openapi4j.parser.OpenApi3Parser
|
||||
import org.openapi4j.parser.model.v3.OpenApi3
|
||||
import org.openapi4j.parser.model.v3.Operation
|
||||
import org.openapi4j.parser.model.v3.Parameter
|
||||
import org.openapi4j.parser.model.v3.Path
|
||||
import java.io.File
|
||||
import java.util.UUID
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
@Tags(Tag("integration"), Tag("auth"))
|
||||
class `Check auth on all routes` : BaseTest() {
|
||||
@Test
|
||||
fun `Check all routes`() {
|
||||
val filePath = "/openapi.yaml"
|
||||
OpenApi3Parser().parse(File(filePath.getResource().toURI()), true).let { api: OpenApi3 ->
|
||||
/* Loop on paths and http methods */
|
||||
api.paths.flatMap { (pathName: String, path: Path) ->
|
||||
path.operations
|
||||
/* Take only the secure route */
|
||||
.filter { (_, operation: Operation) -> operation.hasSecurityRequirements() }
|
||||
.map { (methodName, _) ->
|
||||
/* Send request to check security */
|
||||
sendRequest(
|
||||
path.buildUrl(pathName, methodName, api.context), /* Replace route to real URL */
|
||||
HttpMethod.parse(methodName.toUpperCase()) /* Convert http method name to enum */
|
||||
)
|
||||
}
|
||||
}.let { requests ->
|
||||
/* Check security of routes */
|
||||
assertTrue(
|
||||
requests.all { it.statusCode == HttpStatusCode.Forbidden },
|
||||
requests
|
||||
.filter { it.statusCode != HttpStatusCode.Forbidden }
|
||||
.joinToString("\n") { it.toString() }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendRequest(uri: String, method: HttpMethod): RequestResponse {
|
||||
return try {
|
||||
withIntegrationApplication {
|
||||
handleRequest(true) {
|
||||
this.method = method
|
||||
this.uri = uri
|
||||
addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString())
|
||||
addHeader(HttpHeaders.Accept, ContentType.Application.Json.toString())
|
||||
}.run {
|
||||
RequestResponse(
|
||||
response.status() ?: error("Request error"),
|
||||
method,
|
||||
uri
|
||||
)
|
||||
}
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
RequestResponse(
|
||||
HttpStatusCode.InternalServerError,
|
||||
method,
|
||||
uri
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private data class RequestResponse(
|
||||
val statusCode: HttpStatusCode,
|
||||
val method: HttpMethod,
|
||||
val uri: String
|
||||
) {
|
||||
override fun toString(): String {
|
||||
return """HttpStatus ${statusCode.value} for: ${method.value.padStart(6, ' ')} $uri"""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Path.buildUrl(path: String, methodName: String, context: OAIContext): String {
|
||||
val urlReplaced = this.getParametersIn(context, "path")
|
||||
.fold(path) { pathToReplace: String, parameter: Parameter ->
|
||||
"""\{${parameter.name}}""".toRegex().replace(
|
||||
pathToReplace,
|
||||
parameter.generateFakeValue()
|
||||
)
|
||||
}
|
||||
|
||||
val rootQueryParameters = this.getParametersIn(context, "query")
|
||||
.filter { it.isRequired }
|
||||
.map { parameter ->
|
||||
parameter
|
||||
.generateFakeArray()
|
||||
.joinToString("&") { "${parameter.name}=$it" }
|
||||
}
|
||||
|
||||
val queryParameters = this.getOperation(methodName).getParametersIn(context, "query")
|
||||
.filter { it.isRequired }
|
||||
.map { parameter ->
|
||||
parameter
|
||||
.generateFakeArray()
|
||||
.joinToString("&") { "${parameter.name}=$it" }
|
||||
}
|
||||
val allParameters: String = (rootQueryParameters + queryParameters)
|
||||
.joinToString("&")
|
||||
.let {
|
||||
if (it.isNotEmpty()) {
|
||||
"?$it"
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
|
||||
return "$urlReplaced$allParameters"
|
||||
}
|
||||
|
||||
private fun Parameter.generateFakeValue(): String {
|
||||
return if (example != null) {
|
||||
example.toString()
|
||||
} else if (schema.type == "string" && schema.format == "uuid") {
|
||||
UUID.randomUUID().toString()
|
||||
} else {
|
||||
"example123"
|
||||
}
|
||||
}
|
||||
|
||||
private fun Parameter.generateFakeArray(): List<String> {
|
||||
if (schema.type != "array") {
|
||||
error("Parameter is not an array")
|
||||
}
|
||||
return if (example != null && example is Iterable<*>) {
|
||||
(example as Iterable<*>).map { it.toString() }
|
||||
} else if (schema.itemsSchema.type == "string" && schema.itemsSchema.format == "uuid") {
|
||||
listOf(UUID.randomUUID().toString())
|
||||
} else {
|
||||
listOf("example123")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user