diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerUIPluginConfig.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerUIPluginConfig.kt index 7bb2d73..efb8fd3 100644 --- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerUIPluginConfig.kt +++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerUIPluginConfig.kt @@ -12,11 +12,12 @@ class SwaggerUIPluginConfig { private var defaultUnauthorizedResponse: SingleResponseDocumentation? = null fun defaultUnauthorizedResponse(block: SingleResponseDocumentation.() -> Unit) { - defaultUnauthorizedResponse = SingleResponseDocumentation(HttpStatusCode.Unauthorized).apply(block) + defaultUnauthorizedResponse = SingleResponseDocumentation(HttpStatusCode.Unauthorized).apply(block) } fun getDefaultUnauthorizedResponse() = defaultUnauthorizedResponse + /** * The name of the security scheme to use for the protected paths */ @@ -35,11 +36,13 @@ class SwaggerUIPluginConfig { */ var schemasInComponentSection: Boolean = false + /** * Whether to put example objects in the component section and reference them or inline the examples at the actual place of usage. */ var examplesInComponentSection: Boolean = false + /** * Swagger-UI configuration */ @@ -228,30 +231,11 @@ class OpenApiServerConfig { } -/** - * Allows referencing an external resource for extended documentation. - */ -class OpenApiExternalDocumentationConfig { - - /** - * The URL for the target documentation. Value MUST be in the format of a URL. - */ - var url: String = "/" - - - /** - * A short description of the target documentation - */ - var description: String? = null - -} - - enum class AuthType { API_KEY, HTTP, OAUTH2, OPENID_CONNECT, MUTUAL_TLS } -enum class KeyLocation { +enum class AuthKeyLocation { QUERY, HEADER, COOKIE } @@ -267,7 +251,8 @@ enum class AuthScheme { */ class OpenApiSecuritySchemeConfig( /** - * The name of the header, query or cookie parameter to be used + * The name of the header, query or cookie parameter to be used. + * Required for type [AuthType.API_KEY] */ val name: String ) { @@ -279,23 +264,46 @@ class OpenApiSecuritySchemeConfig( /** - * The location of the API key (OpenAPI 'in') + * The location of the API key (OpenAPI 'in'). + * Required for type [AuthType.API_KEY] */ - var location: KeyLocation? = null + var location: AuthKeyLocation? = null /** - * The name of the HTTP Authorization scheme to be used + * The name of the HTTP Authorization scheme to be used. + * Required for type [AuthType.HTTP] */ var scheme: AuthScheme? = null /** - * A hint to the client to identify how the bearer token is formatted + * A hint to the client to identify how the bearer token is formatted. + * Used for type [AuthType.HTTP] and schema [AuthScheme.BEARER] */ var bearerFormat: String? = null + /** + * information for the oauth flow types supported. + * Required for type [AuthType.OAUTH2] + */ + private var flows: OpenIdOAuthFlowsConfig? = null + + fun flows(block: OpenIdOAuthFlowsConfig.() -> Unit) { + flows = OpenIdOAuthFlowsConfig().apply(block) + } + + fun getFlows() = flows + + + /** + * OpenId Connect URL to discover OAuth2 configuration values. + * Required for type [AuthType.OPENID_CONNECT] + */ + var openIdConnectUrl: String? = null + + /** * A short description for security scheme. */ @@ -303,6 +311,91 @@ class OpenApiSecuritySchemeConfig( } +/** + * An object containing configuration information for the oauth flow types supported + */ +class OpenIdOAuthFlowsConfig { + /** + * Configuration for the OAuth Implicit flow + */ + private var implicit: OpenIdOAuthFlowConfig? = null + + fun implicit(block: OpenIdOAuthFlowConfig.() -> Unit) { + implicit = OpenIdOAuthFlowConfig().apply(block) + } + + fun getImplicit() = implicit + + + /** + * Configuration for the OAuth Resource Owner Password flow + */ + private var password: OpenIdOAuthFlowConfig? = null + + fun password(block: OpenIdOAuthFlowConfig.() -> Unit) { + password = OpenIdOAuthFlowConfig().apply(block) + } + + fun getPassword() = implicit + + + /** + * Configuration for the OAuth Client Credentials flow. + */ + private var clientCredentials: OpenIdOAuthFlowConfig? = null + + fun clientCredentials(block: OpenIdOAuthFlowConfig.() -> Unit) { + clientCredentials = OpenIdOAuthFlowConfig().apply(block) + } + + fun getClientCredentials() = implicit + + + /** + * Configuration for the OAuth Authorization Code flow. + */ + private var authorizationCode: OpenIdOAuthFlowConfig? = null + + fun authorizationCode(block: OpenIdOAuthFlowConfig.() -> Unit) { + authorizationCode = OpenIdOAuthFlowConfig().apply(block) + } + + fun getAuthorizationCode() = implicit + +} + + +/** + * Configuration details for a supported OAuth Flow + */ +class OpenIdOAuthFlowConfig { + + /** + * The authorization URL to be used for this flow + */ + var authorizationUrl: String? = null + + + /** + * The token URL to be used for this flow + */ + var tokenUrl: String? = null + + + /** + * The URL to be used for obtaining refresh tokens + */ + var refreshUrl: String? = null + + + /** + * The available scopes for the OAuth2 security scheme. A map between the scope name and a short description for it + */ + var scopes: Map? = null + +} + + /** * Adds metadata to a single tag. */ diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/apispec/OApiOAuthFlowsGenerator.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/apispec/OApiOAuthFlowsGenerator.kt new file mode 100644 index 0000000..2114301 --- /dev/null +++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/apispec/OApiOAuthFlowsGenerator.kt @@ -0,0 +1,39 @@ +package io.github.smiley4.ktorswaggerui.apispec + +import io.github.smiley4.ktorswaggerui.OpenIdOAuthFlowConfig +import io.github.smiley4.ktorswaggerui.OpenIdOAuthFlowsConfig +import io.swagger.v3.oas.models.security.OAuthFlow +import io.swagger.v3.oas.models.security.OAuthFlows +import io.swagger.v3.oas.models.security.Scopes + +/** + * Generator for the Flows Info-Object + */ +class OApiOAuthFlowsGenerator { + + /** + * Generate the OpenAPI Flows-Object from the given config + */ + fun generate(config: OpenIdOAuthFlowsConfig): OAuthFlows { + return OAuthFlows().apply { + implicit = config.getImplicit()?.let { generate(it) } + password = config.getPassword()?.let { generate(it) } + clientCredentials = config.getClientCredentials()?.let { generate(it) } + authorizationCode = config.getAuthorizationCode()?.let { generate(it) } + } + } + + private fun generate(flow: OpenIdOAuthFlowConfig): OAuthFlow { + return OAuthFlow().apply { + authorizationUrl = flow.authorizationUrl + tokenUrl = flow.tokenUrl + refreshUrl = flow.refreshUrl + scopes = flow.scopes?.let { s -> + Scopes().apply { + s.forEach { (k, v) -> addString(k, v) } + } + } + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/apispec/OApiSecuritySchemesGenerator.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/apispec/OApiSecuritySchemesGenerator.kt index 18930b7..5981ff7 100644 --- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/apispec/OApiSecuritySchemesGenerator.kt +++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/apispec/OApiSecuritySchemesGenerator.kt @@ -1,8 +1,8 @@ package io.github.smiley4.ktorswaggerui.apispec +import io.github.smiley4.ktorswaggerui.AuthKeyLocation import io.github.smiley4.ktorswaggerui.AuthScheme import io.github.smiley4.ktorswaggerui.AuthType -import io.github.smiley4.ktorswaggerui.KeyLocation import io.github.smiley4.ktorswaggerui.OpenApiSecuritySchemeConfig import io.swagger.v3.oas.models.security.SecurityScheme @@ -28,12 +28,12 @@ class OApiSecuritySchemesGenerator { } name = it.name `in` = when (it.location) { - KeyLocation.QUERY -> SecurityScheme.In.QUERY - KeyLocation.HEADER -> SecurityScheme.In.HEADER - KeyLocation.COOKIE -> SecurityScheme.In.COOKIE + AuthKeyLocation.QUERY -> SecurityScheme.In.QUERY + AuthKeyLocation.HEADER -> SecurityScheme.In.HEADER + AuthKeyLocation.COOKIE -> SecurityScheme.In.COOKIE null -> null } - scheme = when(it.scheme) { + scheme = when (it.scheme) { AuthScheme.BASIC -> "Basic" AuthScheme.BEARER -> "Bearer" AuthScheme.DIGEST -> "Digest" @@ -45,6 +45,8 @@ class OApiSecuritySchemesGenerator { AuthScheme.VAPID -> "vapid" else -> null } + bearerFormat = it.bearerFormat + flows = it.getFlows()?.let { f -> OApiOAuthFlowsGenerator().generate(f) } }) } } diff --git a/src/test/kotlin/io/github/smiley4/ktorswaggerui/examples/CompleteExample.kt b/src/test/kotlin/io/github/smiley4/ktorswaggerui/examples/CompleteExample.kt index ae0397b..c0aed0f 100644 --- a/src/test/kotlin/io/github/smiley4/ktorswaggerui/examples/CompleteExample.kt +++ b/src/test/kotlin/io/github/smiley4/ktorswaggerui/examples/CompleteExample.kt @@ -24,7 +24,7 @@ import io.ktor.server.routing.routing import java.util.Random /** - * Arbitrary example to show (and test) as many features as possible (for authentication see "AuthExample") + * Arbitrary examples to show (and test) as many features as possible (for authentication see "AuthExample") */ fun main() { embeddedServer(Netty, port = 8080, host = "localhost") {