Skip to content

Commit

Permalink
add oauth flows
Browse files Browse the repository at this point in the history
  • Loading branch information
SMILEY4 committed Sep 3, 2022
1 parent 6eb61cd commit 0d973e7
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 32 deletions.
145 changes: 119 additions & 26 deletions src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerUIPluginConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand All @@ -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
*/
Expand Down Expand Up @@ -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
}

Expand All @@ -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
) {
Expand All @@ -279,30 +264,138 @@ 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.
*/
var description: String? = null
}


/**
* 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<String, String>? = null

}


/**
* Adds metadata to a single tag.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -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) }
}
}
}
}

}
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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"
Expand All @@ -45,6 +45,8 @@ class OApiSecuritySchemesGenerator {
AuthScheme.VAPID -> "vapid"
else -> null
}
bearerFormat = it.bearerFormat
flows = it.getFlows()?.let { f -> OApiOAuthFlowsGenerator().generate(f) }
})
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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") {
Expand Down

0 comments on commit 0d973e7

Please sign in to comment.