Skip to content

Commit cf78e5c

Browse files
authored
Oppgradere til ktor2 (#123)
- Kopierte API_KEY authentisering fra dp-biblioteker/ktor-utils til ApiKeyAuthentication.kt - Oppgraderte expedia graphql bibliotek som har ktor 2.x versjoner ** NB 1 Vi burde fjerne denne til fordel for dp-biblioteker/pdl - Fjerne dependency-lock fra prosjektet - Oppgraderte til ktor-moshi bibliotek ** NB 2 - Ser ut til moshi er abandoware - Vi må fjerne til fordel for Jackson - Oppgraderte gradle til 7.5.1
1 parent 7fe401a commit cf78e5c

File tree

53 files changed

+239
-1329
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+239
-1329
lines changed

buildSrc/src/main/kotlin/Constants.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ object Cucumber {
2424
object Dagpenger {
2525

2626
object Biblioteker {
27-
const val version = "2022.11.24-14.34.528555d5f3df"
27+
const val version = "2022.12.07-09.10.209e073691b5"
2828
const val stsKlient = "com.github.navikt.dp-biblioteker:sts-klient:$version"
2929
const val ktorUtils = "com.github.navikt.dp-biblioteker:ktor-utils:$version"
3030

@@ -200,7 +200,7 @@ object Moshi {
200200
const val moshiAdapters = "com.squareup.moshi:moshi-adapters:$version"
201201

202202
// waiting for https://github.com/rharter/ktor-moshi/pull/8
203-
const val moshiKtor = "com.github.cs125-illinois:ktor-moshi:7252ca49ed"
203+
const val moshiKtor = "com.github.cs125-illinois:ktor-moshi:2b13e43520"
204204
fun library(name: String) = "com.squareup.moshi:moshi-$name:$version"
205205
}
206206

@@ -270,7 +270,7 @@ object Wiremock {
270270
}
271271

272272
object Graphql {
273-
const val version = "5.2.0"
273+
const val version = "6.3.3"
274274
const val graphql = "com.expediagroup.graphql"
275275
val client = library("client")
276276
fun library(name: String) = "com.expediagroup:graphql-kotlin-$name:$version"

buildSrc/src/main/kotlin/DependencyResolver.kt

Lines changed: 0 additions & 15 deletions
This file was deleted.

dp-inntekt-api/build.gradle.kts

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -31,27 +31,33 @@ dependencies {
3131

3232
implementation(Dagpenger.Events)
3333

34-
implementation(Ktor.server)
35-
implementation(Ktor.serverNetty)
36-
implementation(Ktor.auth)
37-
implementation(Ktor.authJwt)
38-
implementation(Ktor.micrometerMetrics)
39-
implementation(Dagpenger.Biblioteker.ktorUtils)
34+
implementation(Ktor2.Server.library("netty"))
35+
implementation(Ktor2.Server.library("auth"))
36+
implementation(Ktor2.Server.library("auth-jwt"))
37+
implementation(Ktor2.Server.library("status-pages"))
38+
implementation(Ktor2.Server.library("call-id"))
39+
implementation(Ktor2.Server.library("call-logging"))
40+
implementation(Ktor2.Server.library("default-headers"))
41+
implementation(Ktor2.Server.library("content-negotiation"))
42+
implementation(Ktor2.Server.library("metrics-micrometer"))
43+
implementation(Ktor2.Server.library("metrics-micrometer"))
44+
45+
// implementation(Dagpenger.Biblioteker.ktorUtils)
4046
implementation(Micrometer.prometheusRegistry)
4147

4248
implementation(Graphql.client)
4349
implementation(Graphql.library("ktor-client"))
4450
implementation(Graphql.library("client-jackson"))
45-
implementation(Ktor.library("client-logging-jvm"))
46-
implementation(Ktor.library("client-apache"))
51+
implementation(Ktor2.Client.library("logging-jvm"))
52+
implementation(Ktor2.Client.library("apache"))
4753

4854
// unleash
4955
implementation("no.finn.unleash:unleash-client-java:3.3.1")
5056

5157
implementation(Moshi.moshi)
5258
implementation(Moshi.moshiAdapters)
5359
implementation(Moshi.moshiKotlin)
54-
implementation(Moshi.moshiKtor)
60+
implementation("com.github.cs125-illinois:ktor-moshi:2b13e43520")
5561

5662
implementation(Dagpenger.Streams)
5763
implementation(Kafka.clients)
@@ -94,13 +100,13 @@ dependencies {
94100
runtimeOnly("io.grpc:grpc-netty-shaded:$grpcVersion")
95101

96102
testImplementation(kotlin("test"))
97-
testImplementation(Ktor.ktorTest) {
103+
testImplementation(Ktor2.Server.library("test-host")) {
98104
// https://youtrack.jetbrains.com/issue/KT-46090
99105
exclude("org.jetbrains.kotlin", "kotlin-test-junit")
100106
}
101107

102-
testImplementation("no.nav.security:mock-oauth2-server:0.4.3")
103-
testImplementation(Ktor.library("client-mock"))
108+
testImplementation("no.nav.security:mock-oauth2-server:0.5.7")
109+
testImplementation(Ktor2.Client.library("mock"))
104110
testImplementation(Junit5.api)
105111
testImplementation(Junit5.params)
106112
testRuntimeOnly(Junit5.engine)
@@ -160,17 +166,6 @@ java {
160166
mainJavaSourceSet.srcDirs(graphqlDir)
161167
}
162168

163-
dependencyLocking {
164-
lockAllConfigurations()
165-
}
166-
167-
configurations.all {
168-
resolutionStrategy.failOnVersionConflict()
169-
resolutionStrategy.activateDependencyLocking()
170-
resolutionStrategy.preferProjectModules()
171-
resolutionStrategy.eachDependency { DependencyResolver.execute(this) }
172-
}
173-
174169
tasks.withType<ShadowJar> {
175170
transform(Log4j2PluginsCacheFileTransformer::class.java)
176171
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
package no.nav.dagpenger.inntekt
2+
3+
import io.ktor.http.auth.HeaderValueEncoding
4+
import io.ktor.http.auth.HttpAuthHeader
5+
import io.ktor.server.application.ApplicationCall
6+
import io.ktor.server.auth.AuthenticationConfig
7+
import io.ktor.server.auth.AuthenticationContext
8+
import io.ktor.server.auth.AuthenticationFailedCause
9+
import io.ktor.server.auth.AuthenticationProvider
10+
import io.ktor.server.auth.Credential
11+
import io.ktor.server.auth.Principal
12+
import io.ktor.server.auth.UnauthorizedResponse
13+
import io.ktor.server.request.ApplicationRequest
14+
import io.ktor.server.response.respond
15+
import org.apache.commons.codec.binary.Hex
16+
import java.nio.charset.StandardCharsets
17+
import javax.crypto.Mac
18+
import javax.crypto.spec.SecretKeySpec
19+
20+
enum class ApiKeyLocation(val location: String) {
21+
QUERY("query"),
22+
HEADER("header")
23+
}
24+
25+
fun ApplicationRequest.apiKeyAuthenticationCredentials(
26+
apiKeyName: String,
27+
apiKeyLocation: ApiKeyLocation
28+
): ApiKeyCredential? {
29+
return when (
30+
val value: String? = when (apiKeyLocation) {
31+
ApiKeyLocation.QUERY -> this.queryParameters[apiKeyName]
32+
ApiKeyLocation.HEADER -> this.headers[apiKeyName]
33+
}
34+
) {
35+
null -> null
36+
else -> ApiKeyCredential(value)
37+
}
38+
}
39+
40+
data class ApiKeyCredential(val value: String) : Credential
41+
data class ApiPrincipal(val apiKeyCredential: ApiKeyCredential?) : Principal
42+
43+
class ApiKeyAuthenticationProvider internal constructor(config: Configuration) : AuthenticationProvider(config) {
44+
45+
private var apiKeyName: String = config.apiKeyName
46+
private var apiKeyLocation: ApiKeyLocation = config.apiKeyLocation
47+
private val authenticationFunction = config.authenticationFunction
48+
49+
class Configuration(name: String?) : Config(name) {
50+
internal var authenticationFunction: suspend ApplicationCall.(ApiKeyCredential) -> Principal? = { null }
51+
52+
var apiKeyName: String = ""
53+
54+
var apiKeyLocation: ApiKeyLocation = ApiKeyLocation.HEADER
55+
56+
fun validate(body: suspend ApplicationCall.(ApiKeyCredential) -> Principal?) {
57+
authenticationFunction = body
58+
}
59+
60+
internal fun build() = ApiKeyAuthenticationProvider(this)
61+
}
62+
63+
override suspend fun onAuthenticate(context: AuthenticationContext) {
64+
val call = context.call
65+
val credential = call.request.apiKeyAuthenticationCredentials(apiKeyName, apiKeyLocation)
66+
val principal = credential?.let { authenticationFunction(call, it) }
67+
68+
val cause = when {
69+
credential == null -> AuthenticationFailedCause.NoCredentials
70+
principal == null -> AuthenticationFailedCause.InvalidCredentials
71+
else -> null
72+
}
73+
74+
if (cause != null) {
75+
context.challenge(apiKeyName, cause) { challenge, call ->
76+
call.respond(
77+
UnauthorizedResponse(
78+
HttpAuthHeader.Parameterized(
79+
"API_KEY",
80+
mapOf("key" to apiKeyName),
81+
HeaderValueEncoding.QUOTED_ALWAYS
82+
)
83+
)
84+
)
85+
challenge.complete()
86+
}
87+
}
88+
89+
if (principal != null) {
90+
context.principal(principal)
91+
}
92+
}
93+
}
94+
95+
fun AuthenticationConfig.apiKeyAuth(
96+
name: String? = null,
97+
configure: ApiKeyAuthenticationProvider.Configuration.() -> Unit
98+
) {
99+
val provider = ApiKeyAuthenticationProvider.Configuration(name).apply(configure).build()
100+
register(provider)
101+
}
102+
103+
internal class ApiKeyVerifier(private val secret: String) {
104+
105+
private val algorithm = "HmacSHA256"
106+
107+
fun verify(apiKey: String, expectedApiKey: String): Boolean {
108+
return apiKey == generate(expectedApiKey)
109+
}
110+
111+
fun generate(apiKey: String): String {
112+
return String(Hex.encodeHex(generateDigest(apiKey.toByteArray(StandardCharsets.UTF_8))))
113+
}
114+
115+
private fun generateDigest(apiKey: ByteArray): ByteArray {
116+
val secret = SecretKeySpec(secret.toByteArray(StandardCharsets.UTF_8), algorithm)
117+
val mac = Mac.getInstance(algorithm)
118+
mac.init(secret)
119+
return mac.doFinal(apiKey)
120+
}
121+
}

dp-inntekt-api/src/main/kotlin/no/nav/dagpenger/inntekt/Application.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import no.nav.dagpenger.inntekt.oppslag.pdl.PdlGraphQLRepository
2121
import no.nav.dagpenger.inntekt.rpc.InntektGrpcServer
2222
import no.nav.dagpenger.inntekt.subsumsjonbrukt.KafkaSubsumsjonBruktDataConsumer
2323
import no.nav.dagpenger.inntekt.subsumsjonbrukt.Vaktmester
24-
import no.nav.dagpenger.ktor.auth.ApiKeyVerifier
2524
import no.nav.dagpenger.oidc.StsOidcClient
2625
import java.net.URL
2726
import java.util.concurrent.TimeUnit

dp-inntekt-api/src/main/kotlin/no/nav/dagpenger/inntekt/AzureAuth.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@ import com.auth0.jwk.JwkProviderBuilder
55
import com.natpryce.konfig.Configuration
66
import com.natpryce.konfig.Key
77
import com.natpryce.konfig.stringType
8-
import io.ktor.auth.jwt.JWTAuthenticationProvider
9-
import io.ktor.auth.jwt.JWTCredential
10-
import io.ktor.auth.jwt.JWTPrincipal
8+
import io.ktor.server.auth.jwt.JWTAuthenticationProvider
9+
import io.ktor.server.auth.jwt.JWTCredential
10+
import io.ktor.server.auth.jwt.JWTPrincipal
1111
import mu.KotlinLogging
1212
import java.net.URL
1313
import java.util.concurrent.TimeUnit
1414

1515
private val LOGGER = KotlinLogging.logger {}
1616

17-
internal fun JWTAuthenticationProvider.Configuration.azureAdJWT(config: Configuration) {
17+
internal fun JWTAuthenticationProvider.Config.azureAdJWT(config: Configuration) {
1818
val jwksUri = config[Key("AZURE_OPENID_CONFIG_JWKS_URI", stringType)]
1919
val issuer = config[Key("AZURE_OPENID_CONFIG_ISSUER", stringType)]
2020
val clientId = config[Key("AZURE_APP_CLIENT_ID", stringType)]

0 commit comments

Comments
 (0)