From d456b6d595a1a488877bbaa58aeaf3c233618629 Mon Sep 17 00:00:00 2001 From: Anthony Legay Date: Thu, 17 Oct 2024 22:10:00 +0200 Subject: [PATCH] feat: handle root security requirements on root DSL --- .../zoroark/tegral/openapi/dsl/RootDsl.kt | 12 ++++++++-- .../zoroark/tegral/openapi/ktor/PluginTest.kt | 23 +++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/tegral-openapi/tegral-openapi-dsl/src/main/kotlin/guru/zoroark/tegral/openapi/dsl/RootDsl.kt b/tegral-openapi/tegral-openapi-dsl/src/main/kotlin/guru/zoroark/tegral/openapi/dsl/RootDsl.kt index 8b724ab6..d1d27e4b 100644 --- a/tegral-openapi/tegral-openapi-dsl/src/main/kotlin/guru/zoroark/tegral/openapi/dsl/RootDsl.kt +++ b/tegral-openapi/tegral-openapi-dsl/src/main/kotlin/guru/zoroark/tegral/openapi/dsl/RootDsl.kt @@ -20,6 +20,7 @@ import io.swagger.v3.oas.models.Components import io.swagger.v3.oas.models.ExternalDocumentation import io.swagger.v3.oas.models.OpenAPI import io.swagger.v3.oas.models.info.Info +import io.swagger.v3.oas.models.security.SecurityRequirement import io.swagger.v3.oas.models.servers.Server /** @@ -52,6 +53,9 @@ interface RootDsl : InfoDsl, TagsDsl, PathsDsl { @TegralDsl infix fun String.server(server: ServerDsl.() -> Unit) + @TegralDsl + fun security(vararg name: String) + /** * Description for additional external documentation for this API. */ @@ -76,7 +80,7 @@ class RootBuilder( ) : RootDsl, InfoDsl by infoBuilder, PathsDsl by paths, Buildable { private val tags = mutableListOf() private val servers = mutableListOf>() - + private val security = mutableListOf() override var externalDocsDescription: String? = null override var externalDocsUrl: String? = null @@ -93,6 +97,10 @@ class RootBuilder( servers.add(serverBuilder) } + override fun security(vararg name: String) { + security.add(SecurityRequirement().apply { name.forEach(::addList) }) + } + override fun build(): OpenAPI = OpenAPI().apply { tags = this@RootBuilder.tags.map { it.build() }.ifEmpty { null } // In case the info part is completely empty, output 'null' to avoid getting an empty, useless object. @@ -114,7 +122,7 @@ class RootBuilder( description = externalDocsDescription } } - + security = this@RootBuilder.security.ifEmpty { null } servers = this@RootBuilder.servers.map { it.build() }.ifEmpty { null } } } diff --git a/tegral-openapi/tegral-openapi-ktor/src/test/kotlin/guru/zoroark/tegral/openapi/ktor/PluginTest.kt b/tegral-openapi/tegral-openapi-ktor/src/test/kotlin/guru/zoroark/tegral/openapi/ktor/PluginTest.kt index 26426ee1..83989b5a 100644 --- a/tegral-openapi/tegral-openapi-ktor/src/test/kotlin/guru/zoroark/tegral/openapi/ktor/PluginTest.kt +++ b/tegral-openapi/tegral-openapi-ktor/src/test/kotlin/guru/zoroark/tegral/openapi/ktor/PluginTest.kt @@ -18,6 +18,7 @@ import io.ktor.server.application.MissingApplicationPluginException import io.ktor.server.testing.testApplication import io.swagger.v3.oas.models.OpenAPI import io.swagger.v3.oas.models.info.Info +import io.swagger.v3.oas.models.security.SecurityRequirement import org.junit.jupiter.api.assertDoesNotThrow import kotlin.test.Test import kotlin.test.assertEquals @@ -70,4 +71,26 @@ class PluginTest { } } } + + @Test + fun `Add security requirements on root`() { + testApplication { + environment { developmentMode = false } // HACK see KTOR-4729 + install(TegralOpenApiKtor) { + security("ApiKeyAuth") + security("BearerAuth") + } + + application { + val document = openApi.buildOpenApiDocument() + val expected = OpenAPI().apply { + security = listOf( + SecurityRequirement().addList("ApiKeyAuth"), + SecurityRequirement().addList("BearerAuth"), + ) + } + assertEquals(expected, document) + } + } + } }