Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bump(deps): kotlinter 3.16.0 to 4.0.0 #562

Merged
merged 1 commit into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ plugins {
kotlin("jvm") version "1.9.10"
id("se.patrikerdes.use-latest-versions") version "0.2.18"
id("com.github.ben-manes.versions") version "0.49.0"
id("org.jmailen.kotlinter") version "3.16.0"
id("org.jmailen.kotlinter") version "4.0.0"
id("com.google.cloud.tools.jib") version "3.4.0"
id("com.github.johnrengelman.shadow") version "8.1.1"
id("net.researchgate.release") version "3.0.2"
Expand Down
87 changes: 54 additions & 33 deletions src/main/kotlin/no/nav/security/mock/oauth2/MockOAuth2Server.kt
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,11 @@ open class MockOAuth2Server(

private val httpServer = config.httpServer
private val defaultRequestHandler: OAuth2HttpRequestHandler = OAuth2HttpRequestHandler(config)
private val router: RequestHandler = routes(
*additionalRoutes,
defaultRequestHandler.authorizationServer,
)
private val router: RequestHandler =
routes(
*additionalRoutes,
defaultRequestHandler.authorizationServer,
)

/**
* Starts the [MockOAuth2Server] on the localhost interface.
Expand All @@ -63,11 +64,12 @@ open class MockOAuth2Server(
* @exception OAuth2Exception Runtime error if unable to start server.
*/
@JvmOverloads
fun start(port: Int = 0) = try {
start(InetAddress.getByName("localhost"), port)
} catch (ex: IOException) {
throw OAuth2Exception("unable to start server: ${ex.message}", ex)
}
fun start(port: Int = 0) =
try {
start(InetAddress.getByName("localhost"), port)
} catch (ex: IOException) {
throw OAuth2Exception("unable to start server: ${ex.message}", ex)
}

/**
* Starts the [MockOAuth2Server] on the given [inetAddress] IP address at the given [port].
Expand All @@ -77,7 +79,10 @@ open class MockOAuth2Server(
*
* @exception OAuth2Exception Runtime error if unable to start server.
*/
fun start(inetAddress: InetAddress, port: Int) {
fun start(
inetAddress: InetAddress,
port: Int,
) {
log.debug("attempt to start server on port=$port")
httpServer.start(inetAddress, port, router)
}
Expand All @@ -104,7 +109,9 @@ open class MockOAuth2Server(
fun url(path: String): HttpUrl = httpServer.url(path)

@Deprecated("Use MockWebServer method/function instead", ReplaceWith("MockWebServer.enqueue()"))
fun enqueueResponse(@Suppress("UNUSED_PARAMETER") response: MockResponse) {
fun enqueueResponse(
@Suppress("UNUSED_PARAMETER") response: MockResponse,
) {
throw UnsupportedOperationException("cannot enqueue MockResponse, please use the MockWebServer directly with QueueDispatcher")
}

Expand All @@ -125,7 +132,10 @@ open class MockOAuth2Server(
* @param unit A [TimeUnit] determining how to interpret the [timeout] parameter
*/
@JvmOverloads
fun takeRequest(timeout: Long = 2, unit: TimeUnit = TimeUnit.SECONDS): RecordedRequest =
fun takeRequest(
timeout: Long = 2,
unit: TimeUnit = TimeUnit.SECONDS,
): RecordedRequest =
(httpServer as? MockWebServerWrapper)?.mockWebServer?.let {
it.takeRequest(timeout, unit) ?: throw RuntimeException("no request found in queue within timeout $timeout $unit")
} ?: throw UnsupportedOperationException("can only takeRequest when httpServer is of type MockWebServer")
Expand Down Expand Up @@ -225,14 +235,19 @@ open class MockOAuth2Server(
* @param clientId The identifier for the client or Relying Party that requests the token.
* @param tokenCallback A callback that implements the [OAuth2TokenCallback] interface for token customization.
*/
fun issueToken(issuerId: String, clientId: String, tokenCallback: OAuth2TokenCallback): SignedJWT {
fun issueToken(
issuerId: String,
clientId: String,
tokenCallback: OAuth2TokenCallback,
): SignedJWT {
val uri = tokenEndpointUrl(issuerId)
val issuerUrl = issuerUrl(issuerId)
val tokenRequest = TokenRequest(
uri.toUri(),
ClientSecretBasic(ClientID(clientId), Secret("secret")),
AuthorizationCodeGrant(AuthorizationCode("123"), URI.create("http://localhost")),
)
val tokenRequest =
TokenRequest(
uri.toUri(),
ClientSecretBasic(ClientID(clientId), Secret("secret")),
AuthorizationCodeGrant(AuthorizationCode("123"), URI.create("http://localhost")),
)
return config.tokenProvider.accessToken(tokenRequest, issuerUrl, tokenCallback, null)
}

Expand All @@ -248,29 +263,35 @@ open class MockOAuth2Server(
audience: String? = "default",
claims: Map<String, Any> = emptyMap(),
expiry: Long = 3600,
): SignedJWT = issueToken(
issuerId,
"default",
DefaultOAuth2TokenCallback(
): SignedJWT =
issueToken(
issuerId,
subject,
JOSEObjectType.JWT.type,
audience?.let { listOf(it) },
claims,
expiry,
),
)
"default",
DefaultOAuth2TokenCallback(
issuerId,
subject,
JOSEObjectType.JWT.type,
audience?.let { listOf(it) },
claims,
expiry,
),
)

/**
* Issues a signed JWT for a given [issuerUrl] containing the input set of [claims].
* The JWT's signature can be verified with the server's keys found at the [jwksUrl] endpoint.
*/
@JvmOverloads
fun anyToken(issuerUrl: HttpUrl, claims: Map<String, Any>, expiry: Duration = Duration.ofHours(1)): SignedJWT {
fun anyToken(
issuerUrl: HttpUrl,
claims: Map<String, Any>,
expiry: Duration = Duration.ofHours(1),
): SignedJWT {
val jwtClaimsSet = claims.toJwtClaimsSet()
val mockGrant: AuthorizationGrant = object : AuthorizationGrant(GrantType("MockGrant")) {
override fun toParameters(): MutableMap<String, MutableList<String>> = mutableMapOf()
}
val mockGrant: AuthorizationGrant =
object : AuthorizationGrant(GrantType("MockGrant")) {
override fun toParameters(): MutableMap<String, MutableList<String>> = mutableMapOf()
}
return this.config.tokenProvider.exchangeAccessToken(
TokenRequest(URI.create("http://mockgrant"), ClientID("mockclientid"), mockGrant),
issuerUrl,
Expand Down
152 changes: 80 additions & 72 deletions src/main/kotlin/no/nav/security/mock/oauth2/OAuth2Config.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,90 +20,98 @@ import no.nav.security.mock.oauth2.token.OAuth2TokenProvider
import no.nav.security.mock.oauth2.token.RequestMappingTokenCallback
import java.io.File

data class OAuth2Config @JvmOverloads constructor(
val interactiveLogin: Boolean = false,
val loginPagePath: String? = null,
val staticAssetsPath: String? = null,
@JsonDeserialize(using = OAuth2TokenProviderDeserializer::class)
val tokenProvider: OAuth2TokenProvider = OAuth2TokenProvider(),
@JsonDeserialize(contentAs = RequestMappingTokenCallback::class)
val tokenCallbacks: Set<OAuth2TokenCallback> = emptySet(),
@JsonDeserialize(using = OAuth2HttpServerDeserializer::class)
val httpServer: OAuth2HttpServer = MockWebServerWrapper(),
) {

class OAuth2TokenProviderDeserializer : JsonDeserializer<OAuth2TokenProvider>() {
data class OAuth2Config
@JvmOverloads
constructor(
val interactiveLogin: Boolean = false,
val loginPagePath: String? = null,
val staticAssetsPath: String? = null,
@JsonDeserialize(using = OAuth2TokenProviderDeserializer::class)
val tokenProvider: OAuth2TokenProvider = OAuth2TokenProvider(),
@JsonDeserialize(contentAs = RequestMappingTokenCallback::class)
val tokenCallbacks: Set<OAuth2TokenCallback> = emptySet(),
@JsonDeserialize(using = OAuth2HttpServerDeserializer::class)
val httpServer: OAuth2HttpServer = MockWebServerWrapper(),
) {
class OAuth2TokenProviderDeserializer : JsonDeserializer<OAuth2TokenProvider>() {
data class ProviderConfig(
val keyProvider: KeyProviderConfig?,
)

data class ProviderConfig(
val keyProvider: KeyProviderConfig?,
)
data class KeyProviderConfig(
val initialKeys: String?,
val algorithm: String,
)

data class KeyProviderConfig(
val initialKeys: String?,
val algorithm: String,
)
override fun deserialize(
p: JsonParser,
ctxt: DeserializationContext?,
): OAuth2TokenProvider {
val node: JsonNode = p.readValueAsTree()
val config: ProviderConfig =
if (!node.isObject) {
return OAuth2TokenProvider()
} else {
p.codec.treeToValue(node, ProviderConfig::class.java)
}
val jwks =
config.keyProvider?.initialKeys?.let {
listOf(JWK.parse(it))
} ?: emptyList()

override fun deserialize(p: JsonParser, ctxt: DeserializationContext?): OAuth2TokenProvider {
val node: JsonNode = p.readValueAsTree()
val config: ProviderConfig = if (!node.isObject) {
return OAuth2TokenProvider()
} else {
p.codec.treeToValue(node, ProviderConfig::class.java)
return OAuth2TokenProvider(
KeyProvider(
jwks,
config.keyProvider?.algorithm ?: JWSAlgorithm.RS256.name,
),
)
}
val jwks = config.keyProvider?.initialKeys?.let {
listOf(JWK.parse(it))
} ?: emptyList()

return OAuth2TokenProvider(
KeyProvider(
jwks,
config.keyProvider?.algorithm ?: JWSAlgorithm.RS256.name,
),
)
}
}

class OAuth2HttpServerDeserializer : JsonDeserializer<OAuth2HttpServer>() {
enum class ServerType {
MockWebServerWrapper,
NettyWrapper,
}

data class ServerConfig(
val type: ServerType,
val ssl: SslConfig? = null,
)
class OAuth2HttpServerDeserializer : JsonDeserializer<OAuth2HttpServer>() {
enum class ServerType {
MockWebServerWrapper,
NettyWrapper,
}

data class SslConfig(
val keyPassword: String = "",
val keystoreFile: File? = null,
val keystoreType: SslKeystore.KeyStoreType = SslKeystore.KeyStoreType.PKCS12,
val keystorePassword: String = "",
) {
fun ssl() = Ssl(sslKeyStore())
data class ServerConfig(
val type: ServerType,
val ssl: SslConfig? = null,
)

private fun sslKeyStore() =
if (keystoreFile == null) SslKeystore() else SslKeystore(keyPassword, keystoreFile, keystoreType, keystorePassword)
}
data class SslConfig(
val keyPassword: String = "",
val keystoreFile: File? = null,
val keystoreType: SslKeystore.KeyStoreType = SslKeystore.KeyStoreType.PKCS12,
val keystorePassword: String = "",
) {
fun ssl() = Ssl(sslKeyStore())

override fun deserialize(p: JsonParser, ctxt: DeserializationContext): OAuth2HttpServer {
val node: JsonNode = p.readValueAsTree()
val serverConfig: ServerConfig = if (node.isObject) {
p.codec.treeToValue(node, ServerConfig::class.java)
} else {
ServerConfig(ServerType.valueOf(node.textValue()))
private fun sslKeyStore() = if (keystoreFile == null) SslKeystore() else SslKeystore(keyPassword, keystoreFile, keystoreType, keystorePassword)
}
val ssl: Ssl? = serverConfig.ssl?.ssl()
return when (serverConfig.type) {
ServerType.NettyWrapper -> NettyWrapper(ssl)
ServerType.MockWebServerWrapper -> MockWebServerWrapper(ssl)

override fun deserialize(
p: JsonParser,
ctxt: DeserializationContext,
): OAuth2HttpServer {
val node: JsonNode = p.readValueAsTree()
val serverConfig: ServerConfig =
if (node.isObject) {
p.codec.treeToValue(node, ServerConfig::class.java)
} else {
ServerConfig(ServerType.valueOf(node.textValue()))
}
val ssl: Ssl? = serverConfig.ssl?.ssl()
return when (serverConfig.type) {
ServerType.NettyWrapper -> NettyWrapper(ssl)
ServerType.MockWebServerWrapper -> MockWebServerWrapper(ssl)
}
}
}
}

companion object {
fun fromJson(json: String): OAuth2Config {
return jacksonObjectMapper().readValue(json)
companion object {
fun fromJson(json: String): OAuth2Config {
return jacksonObjectMapper().readValue(json)
}
}
}
}
21 changes: 12 additions & 9 deletions src/main/kotlin/no/nav/security/mock/oauth2/OAuth2Exception.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,19 @@ class OAuth2Exception(val errorObject: ErrorObject?, msg: String, throwable: Thr
constructor(errorObject: ErrorObject?, msg: String) : this(errorObject, msg, null)
}

fun missingParameter(name: String): Nothing = "missing required parameter $name".let {
throw OAuth2Exception(OAuth2Error.INVALID_REQUEST.setDescription(it), it)
}
fun missingParameter(name: String): Nothing =
"missing required parameter $name".let {
throw OAuth2Exception(OAuth2Error.INVALID_REQUEST.setDescription(it), it)
}

fun invalidGrant(grantType: GrantType): Nothing = "grant_type $grantType not supported.".let {
throw OAuth2Exception(OAuth2Error.INVALID_GRANT, it)
}
fun invalidGrant(grantType: GrantType): Nothing =
"grant_type $grantType not supported.".let {
throw OAuth2Exception(OAuth2Error.INVALID_GRANT, it)
}

fun invalidRequest(message: String): Nothing = message.let {
throw OAuth2Exception(OAuth2Error.INVALID_REQUEST, message)
}
fun invalidRequest(message: String): Nothing =
message.let {
throw OAuth2Exception(OAuth2Error.INVALID_REQUEST, message)
}

fun notFound(message: String): Nothing = throw OAuth2Exception(ErrorObject("not_found", "Resource not found", HTTPResponse.SC_NOT_FOUND), message)
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,23 @@ object StandaloneConfig {
const val SERVER_PORT = "SERVER_PORT"
const val PORT = "PORT" // Supports running Docker image on Heroku.

fun hostname(): InetAddress = SERVER_HOSTNAME.fromEnv()
?.let { InetAddress.getByName(it) } ?: InetSocketAddress(0).address
fun hostname(): InetAddress =
SERVER_HOSTNAME.fromEnv()
?.let { InetAddress.getByName(it) } ?: InetSocketAddress(0).address

fun port(): Int = (SERVER_PORT.fromEnv()?.toInt() ?: PORT.fromEnv()?.toInt()) ?: 8080

fun oauth2Config(): OAuth2Config = with(jsonFromEnv()) {
if (this != null) {
OAuth2Config.fromJson(this)
} else {
OAuth2Config(
interactiveLogin = true,
httpServer = NettyWrapper(),
)
fun oauth2Config(): OAuth2Config =
with(jsonFromEnv()) {
if (this != null) {
OAuth2Config.fromJson(this)
} else {
OAuth2Config(
interactiveLogin = true,
httpServer = NettyWrapper(),
)
}
}
}

private fun jsonFromEnv() = JSON_CONFIG.fromEnv() ?: JSON_CONFIG_PATH.fromEnv("config.json").readFile()

Expand All @@ -56,4 +58,5 @@ fun main() {
}

fun String.fromEnv(default: String): String = System.getenv(this) ?: default

fun String.fromEnv(): String? = System.getenv(this)
Loading