Skip to content

Commit

Permalink
feat(build): replace detekt with kotlinter (#561)
Browse files Browse the repository at this point in the history
* feat(build): replace detekt with kotlinter

* add newline

* update license
  • Loading branch information
ybelMekk authored Jan 7, 2025
1 parent 583fb42 commit d61a8b6
Show file tree
Hide file tree
Showing 56 changed files with 1,504 additions and 1,271 deletions.
6 changes: 0 additions & 6 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,3 @@ ij_kotlin_while_on_new_line = false
ij_kotlin_wrap_elvis_expressions = 1
ij_kotlin_wrap_expression_body_functions = 1
ij_kotlin_wrap_first_method_in_call_chain = false


# Comma-separated list of rules to disable (Since 0.34.0)
# Note that rules in any ruleset other than the standard ruleset will need to be prefixed
# by the ruleset identifier.
disabled_rules=import-ordering
39 changes: 0 additions & 39 deletions .github/workflows/detekt.yml

This file was deleted.

2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2021 NAV IKT
Copyright (c) 2024 NAV IKT

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ val mainClassKt = "io.nais.security.oauth2.TokenExchangeAppKt"
plugins {
application
kotlin("jvm") version "2.0.21"
id("org.jmailen.kotlinter") version "5.0.1"
id("com.github.johnrengelman.shadow") version "8.1.1"
id("com.github.ben-manes.versions") version "0.51.0"
}
Expand Down
78 changes: 44 additions & 34 deletions src/main/kotlin/io/nais/security/oauth2/TokenExchangeApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,15 @@ fun server(): EmbeddedServer<NettyApplicationEngine, NettyApplicationEngine.Conf
},
module = {
tokenExchangeApp(config, DefaultRouting(config))
}
},
)
}

@Suppress("LongMethod")
fun Application.tokenExchangeApp(config: AppConfiguration, routing: ApiRouting) {
fun Application.tokenExchangeApp(
config: AppConfiguration,
routing: ApiRouting,
) {
install(CallId) {
header(HttpHeaders.XCorrelationId)
generate { UUID.randomUUID().toString() }
Expand All @@ -121,23 +124,25 @@ fun Application.tokenExchangeApp(config: AppConfiguration, routing: ApiRouting)
}

install(MicrometerMetrics) {
registry = PrometheusMeterRegistry(
PrometheusConfig.DEFAULT,
CollectorRegistry.defaultRegistry,
Clock.SYSTEM
)
meterBinders = listOf(
ClassLoaderMetrics(),
JvmMemoryMetrics(),
JvmGcMetrics(),
ProcessorMetrics(),
JvmThreadMetrics(),
LogbackMetrics()
)
registry =
PrometheusMeterRegistry(
PrometheusConfig.DEFAULT,
CollectorRegistry.defaultRegistry,
Clock.SYSTEM,
)
meterBinders =
listOf(
ClassLoaderMetrics(),
JvmMemoryMetrics(),
JvmGcMetrics(),
ProcessorMetrics(),
JvmThreadMetrics(),
LogbackMetrics(),
)
}

install(ContentNegotiation) {
jackson() {
jackson {
configure(FAIL_ON_UNKNOWN_PROPERTIES, true)
setSerializationInclusion(NON_NULL)
}
Expand Down Expand Up @@ -176,7 +181,10 @@ fun Application.tokenExchangeApp(config: AppConfiguration, routing: ApiRouting)
}
}

private suspend fun ApplicationCall.respondWithError(exception: OAuth2Exception, includeErrorDetails: Boolean) {
private suspend fun ApplicationCall.respondWithError(
exception: OAuth2Exception,
includeErrorDetails: Boolean,
) {
val errorObject = exception.toErrorObject(includeErrorDetails)
Metrics.oauth2ErrorCounter.labels(errorObject.code).inc()
this.respond(HttpStatusCode.fromValue(errorObject.httpStatusCode), errorObject.toJSONObject())
Expand All @@ -200,27 +208,29 @@ private fun ErrorObject.toGeneric(): ErrorObject =
else -> "unexpected error"
},
this.httpStatusCode,
this.uri
this.uri,
)

internal val defaultHttpClient = HttpClient(CIO) {
install(ClientContentNegotiation) {
jackson() {
setSerializationInclusion(NON_NULL)
configure(FAIL_ON_UNKNOWN_PROPERTIES, false)
internal val defaultHttpClient =
HttpClient(CIO) {
install(ClientContentNegotiation) {
jackson {
setSerializationInclusion(NON_NULL)
configure(FAIL_ON_UNKNOWN_PROPERTIES, false)
}
}
}
}

internal val retryingHttpClient = HttpClient(CIO) {
install(ClientContentNegotiation) {
jackson() {
setSerializationInclusion(NON_NULL)
configure(FAIL_ON_UNKNOWN_PROPERTIES, false)
internal val retryingHttpClient =
HttpClient(CIO) {
install(ClientContentNegotiation) {
jackson {
setSerializationInclusion(NON_NULL)
configure(FAIL_ON_UNKNOWN_PROPERTIES, false)
}
}
install(HttpRequestRetry) {
retryOnExceptionOrServerErrors(maxRetries = 10)
exponentialDelay()
}
}
install(HttpRequestRetry) {
retryOnExceptionOrServerErrors(maxRetries = 10)
exponentialDelay()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,16 @@ fun AuthenticationConfig.clientRegistrationAuth(appConfig: AppConfiguration) {
require(payload.audience.containsAll(properties.acceptedAudience)) {
throw OAuth2Exception(
OAuth2Error.INVALID_CLIENT.setDescription(
"audience claim does not contain accepted audience (${properties.acceptedAudience})"
)
"audience claim does not contain accepted audience (${properties.acceptedAudience})",
),
)
}
val roles: MutableList<String> = payload.getClaim("roles") ?.asList(String::class.java) ?: mutableListOf()
require(roles.containsAll(properties.acceptedRoles)) {
throw OAuth2Exception(
OAuth2Error.INVALID_CLIENT.setDescription(
"roles claim does not contain accepted roles (${properties.acceptedRoles}"
)
"roles claim does not contain accepted roles (${properties.acceptedRoles}",
),
)
}
JWTPrincipal(credentials.payload)
Expand All @@ -62,36 +62,39 @@ fun AuthenticationConfig.clientRegistrationAuth(appConfig: AppConfiguration) {
internal fun bearerTokenVerifier(
jwkProvider: JwkProvider,
issuer: String,
token: HttpAuthHeader
): JWTVerifier {
return try {
val jwk = token.getBlob()?.let { jwkProvider.get(JWT.decode(it).keyId) }
?: throw OAuth2Exception(OAuth2Error.INVALID_REQUEST.setDescription("unable to find public key for token"))
token: HttpAuthHeader,
): JWTVerifier =
try {
val jwk =
token.getBlob()?.let { jwkProvider.get(JWT.decode(it).keyId) }
?: throw OAuth2Exception(OAuth2Error.INVALID_REQUEST.setDescription("unable to find public key for token"))
val algorithm = jwk.makeAlgorithm()

DelegatingJWTVerifier(
JWT.require(algorithm)
JWT
.require(algorithm)
.withIssuer(issuer)
.build()
.build(),
)
} catch (t: Throwable) {
log.error("received exception when validating token, message: ${t.message}", t)
throw t
}
}

private fun HttpAuthHeader.getBlob(): String? = when {
this is HttpAuthHeader.Single && authScheme.lowercase() in listOf("bearer") -> blob
else -> null
}
private fun HttpAuthHeader.getBlob(): String? =
when {
this is HttpAuthHeader.Single && authScheme.lowercase() in listOf("bearer") -> blob
else -> null
}

private fun Jwk.makeAlgorithm(): Algorithm = when (algorithm) {
"RS256" -> Algorithm.RSA256(publicKey as RSAPublicKey, null)
"RS384" -> Algorithm.RSA384(publicKey as RSAPublicKey, null)
"RS512" -> Algorithm.RSA512(publicKey as RSAPublicKey, null)
"ES256" -> Algorithm.ECDSA256(publicKey as ECPublicKey, null)
"ES384" -> Algorithm.ECDSA384(publicKey as ECPublicKey, null)
"ES512" -> Algorithm.ECDSA512(publicKey as ECPublicKey, null)
null -> Algorithm.RSA256(publicKey as RSAPublicKey, null)
else -> throw IllegalArgumentException("Unsupported algorithm $algorithm")
}
private fun Jwk.makeAlgorithm(): Algorithm =
when (algorithm) {
"RS256" -> Algorithm.RSA256(publicKey as RSAPublicKey, null)
"RS384" -> Algorithm.RSA384(publicKey as RSAPublicKey, null)
"RS512" -> Algorithm.RSA512(publicKey as RSAPublicKey, null)
"ES256" -> Algorithm.ECDSA256(publicKey as ECPublicKey, null)
"ES384" -> Algorithm.ECDSA384(publicKey as ECPublicKey, null)
"ES512" -> Algorithm.ECDSA512(publicKey as ECPublicKey, null)
null -> Algorithm.RSA256(publicKey as RSAPublicKey, null)
else -> throw IllegalArgumentException("Unsupported algorithm $algorithm")
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ import java.nio.charset.Charset

private val log = KotlinLogging.logger { }

internal class DelegatingJWTVerifier(private val verifier: JWTVerifier) : JWTVerifier {

internal class DelegatingJWTVerifier(
private val verifier: JWTVerifier,
) : JWTVerifier {
override fun verify(token: String?): DecodedJWT =
logVerificationException {
verifier.verify(token)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,18 @@ import io.ktor.http.Parameters
import io.nais.security.oauth2.model.OAuth2Exception

@Throws(OAuth2Exception::class)
fun Parameters.require(name: String, requiredValue: String? = null): String =
fun Parameters.require(
name: String,
requiredValue: String? = null,
): String =
when {
requiredValue != null -> {
this[name]
?.takeIf { it == requiredValue }
?: throw OAuth2Exception(
OAuth2Error.INVALID_REQUEST.setDescription(
"Parameter $name must be $requiredValue"
)
"Parameter $name must be $requiredValue",
),
)
}
else -> {
Expand Down
Loading

0 comments on commit d61a8b6

Please sign in to comment.