Skip to content

Commit 4dd5c9d

Browse files
authored
Merge pull request #250 from MikAoJk/ktor2
Update to use ktor 2.0.1
2 parents 505e012 + 73ffa54 commit 4dd5c9d

File tree

7 files changed

+91
-90
lines changed

7 files changed

+91
-90
lines changed

build.gradle.kts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ val kotestVersion = "5.3.0"
1515
val bouncyCastleVersion = "1.70"
1616
val springBootVersion = "2.6.7"
1717
val reactorTestVersion = "3.4.17"
18-
val ktorVersion = "1.6.8"
18+
val ktorVersion = "2.0.1"
1919

2020
val mavenRepoBaseUrl = "https://oss.sonatype.org"
2121
val mainClassKt = "no.nav.security.mock.oauth2.StandaloneMockOAuth2ServerKt"
@@ -80,11 +80,13 @@ dependencies {
8080
testImplementation("io.projectreactor:reactor-test:$reactorTestVersion")
8181
testImplementation("io.ktor:ktor-server-netty:$ktorVersion")
8282
testImplementation("io.ktor:ktor-server-sessions:$ktorVersion")
83-
testImplementation("io.ktor:ktor-locations:$ktorVersion")
84-
testImplementation("io.ktor:ktor-auth:$ktorVersion")
85-
testImplementation("io.ktor:ktor-auth-jwt:$ktorVersion")
83+
testImplementation("io.ktor:ktor-server-locations:$ktorVersion")
84+
testImplementation("io.ktor:ktor-server-auth:$ktorVersion")
85+
testImplementation("io.ktor:ktor-server-auth-jwt:$ktorVersion")
86+
testImplementation("io.ktor:ktor-server-content-negotiation:$ktorVersion")
8687
testImplementation("io.ktor:ktor-client-core:$ktorVersion")
87-
testImplementation("io.ktor:ktor-client-jackson:$ktorVersion")
88+
testImplementation("io.ktor:ktor-client-content-negotiation:$ktorVersion")
89+
testImplementation("io.ktor:ktor-serialization-jackson:$ktorVersion")
8890
testImplementation("io.ktor:ktor-client-cio:$ktorVersion")
8991
testImplementation("io.ktor:ktor-server-test-host:$ktorVersion")
9092
}

src/test/kotlin/examples/kotlin/ktor/client/OAuth2Client.kt

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,13 @@ import com.fasterxml.jackson.annotation.JsonProperty
77
import com.fasterxml.jackson.databind.DeserializationFeature
88
import io.ktor.client.HttpClient
99
import io.ktor.client.engine.cio.CIO
10-
import io.ktor.client.features.json.JacksonSerializer
11-
import io.ktor.client.features.json.JsonFeature
10+
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
1211
import io.ktor.client.request.forms.submitForm
1312
import io.ktor.client.request.header
1413
import io.ktor.http.Headers
1514
import io.ktor.http.Parameters
1615
import io.ktor.http.headersOf
17-
import io.ktor.util.InternalAPI
16+
import io.ktor.serialization.jackson.jackson
1817
import java.nio.charset.StandardCharsets
1918
import java.security.KeyPair
2019
import java.security.interfaces.RSAPrivateKey
@@ -26,17 +25,16 @@ import java.util.Date
2625
import java.util.UUID
2726

2827
val httpClient = HttpClient(CIO) {
29-
install(JsonFeature) {
30-
serializer = JacksonSerializer {
28+
install(ContentNegotiation) {
29+
jackson {
3130
configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
3231
setSerializationInclusion(JsonInclude.Include.NON_NULL)
3332
}
3433
}
3534
}
3635

37-
@OptIn(InternalAPI::class)
3836
suspend fun HttpClient.tokenRequest(url: String, auth: Auth, params: Map<String, String>) =
39-
submitForm<TokenResponse>(
37+
submitForm(
4038
url = url,
4139
formParameters = Parameters.build {
4240
auth.parameters.forEach {

src/test/kotlin/examples/kotlin/ktor/client/OAuth2ClientTest.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.auth0.jwt.JWT
44
import io.kotest.assertions.asClue
55
import io.kotest.matchers.collections.shouldContainExactly
66
import io.kotest.matchers.shouldBe
7+
import io.ktor.client.call.body
78
import kotlinx.coroutines.runBlocking
89
import no.nav.security.mock.oauth2.MockOAuth2Server
910
import no.nav.security.mock.oauth2.token.DefaultOAuth2TokenCallback
@@ -33,8 +34,8 @@ internal class OAuth2ClientTest {
3334
)
3435

3536
tokenResponse.asClue {
36-
it.accessToken.asDecodedJWT().subject shouldBe "client1"
37-
it.accessToken.asDecodedJWT().audience.shouldContainExactly("targetScope")
37+
it.body<TokenResponse>().accessToken.asDecodedJWT().subject shouldBe "client1"
38+
it.body<TokenResponse>().accessToken.asDecodedJWT().audience.shouldContainExactly("targetScope")
3839
}
3940
}
4041
}
@@ -56,8 +57,8 @@ internal class OAuth2ClientTest {
5657
)
5758

5859
tokenResponse.asClue {
59-
it.accessToken.asDecodedJWT().subject shouldBe "enduser"
60-
it.accessToken.asDecodedJWT().audience.shouldContainExactly("targetScope")
60+
it.body<TokenResponse>().accessToken.asDecodedJWT().subject shouldBe "enduser"
61+
it.body<TokenResponse>().accessToken.asDecodedJWT().audience.shouldContainExactly("targetScope")
6162
}
6263
}
6364
}

src/test/kotlin/examples/kotlin/ktor/login/OAuth2LoginApp.kt

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,35 @@ package examples.kotlin.ktor.login
33
import com.auth0.jwt.JWT
44
import com.fasterxml.jackson.annotation.JsonInclude
55
import com.fasterxml.jackson.databind.DeserializationFeature
6-
import io.ktor.application.Application
7-
import io.ktor.application.ApplicationCall
8-
import io.ktor.application.call
9-
import io.ktor.application.install
10-
import io.ktor.auth.Authentication
11-
import io.ktor.auth.OAuthAccessTokenResponse
12-
import io.ktor.auth.OAuthServerSettings
13-
import io.ktor.auth.authenticate
14-
import io.ktor.auth.authentication
15-
import io.ktor.auth.oauth
166
import io.ktor.client.HttpClient
177
import io.ktor.client.engine.cio.CIO
18-
import io.ktor.client.features.json.JacksonSerializer
19-
import io.ktor.client.features.json.JsonFeature
8+
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
209
import io.ktor.http.ContentType
2110
import io.ktor.http.HttpMethod
2211
import io.ktor.http.HttpStatusCode
23-
import io.ktor.locations.Location
24-
import io.ktor.locations.Locations
25-
import io.ktor.locations.location
26-
import io.ktor.locations.locations
27-
import io.ktor.locations.url
28-
import io.ktor.response.respondText
29-
import io.ktor.routing.get
30-
import io.ktor.routing.param
31-
import io.ktor.routing.routing
12+
import io.ktor.serialization.jackson.jackson
13+
import io.ktor.server.application.Application
14+
import io.ktor.server.application.ApplicationCall
15+
import io.ktor.server.application.call
16+
import io.ktor.server.application.install
17+
import io.ktor.server.auth.Authentication
18+
import io.ktor.server.auth.OAuthAccessTokenResponse
19+
import io.ktor.server.auth.OAuthServerSettings
20+
import io.ktor.server.auth.authenticate
21+
import io.ktor.server.auth.authentication
22+
import io.ktor.server.auth.oauth
3223
import io.ktor.server.engine.embeddedServer
24+
import io.ktor.server.locations.KtorExperimentalLocationsAPI
25+
import io.ktor.server.locations.Location
26+
import io.ktor.server.locations.Locations
27+
import io.ktor.server.locations.location
28+
import io.ktor.server.locations.locations
29+
import io.ktor.server.locations.url
3330
import io.ktor.server.netty.Netty
31+
import io.ktor.server.response.respondText
32+
import io.ktor.server.routing.get
33+
import io.ktor.server.routing.param
34+
import io.ktor.server.routing.routing
3435

3536
fun main() {
3637
embeddedServer(Netty, port = 8080) {
@@ -53,6 +54,7 @@ fun main() {
5354
}.start(true)
5455
}
5556

57+
@OptIn(KtorExperimentalLocationsAPI::class)
5658
fun Application.module(authConfig: AuthConfig) {
5759

5860
val idProviders = authConfig.providers.map { it.settings }.associateBy { it.name }
@@ -121,8 +123,8 @@ private fun ApplicationCall.subject(): String? {
121123
}
122124

123125
internal val httpClient = HttpClient(CIO) {
124-
install(JsonFeature) {
125-
serializer = JacksonSerializer {
126+
install(ContentNegotiation) {
127+
jackson {
126128
configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
127129
setSerializationInclusion(JsonInclude.Include.NON_NULL)
128130
}

src/test/kotlin/examples/kotlin/ktor/login/OAuth2LoginAppTest.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ package examples.kotlin.ktor.login
22

33
import io.kotest.assertions.asClue
44
import io.kotest.matchers.shouldBe
5-
import io.ktor.application.Application
6-
import io.ktor.client.request.get
5+
import io.ktor.client.request.prepareGet
6+
import io.ktor.server.application.Application
77
import io.ktor.server.engine.ApplicationEngine
88
import io.ktor.server.engine.embeddedServer
99
import io.ktor.server.netty.Netty
@@ -46,7 +46,7 @@ internal class OAuth2LoginAppTest {
4646
}
4747
}
4848

49-
private inline fun <reified R> get(url: String): R = runBlocking { httpClient.get(url) }
49+
private inline fun <reified R> get(url: String): R = runBlocking { httpClient.prepareGet(url).body() }
5050

5151
private fun <R> withEmbeddedServer(
5252
moduleFunction: Application.() -> Unit,

src/test/kotlin/examples/kotlin/ktor/resourceserver/OAuth2ResourceServerApp.kt

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,25 @@ import com.auth0.jwt.interfaces.Payload
55
import com.fasterxml.jackson.annotation.JsonInclude
66
import com.fasterxml.jackson.annotation.JsonProperty
77
import com.fasterxml.jackson.databind.DeserializationFeature
8-
import io.ktor.application.Application
9-
import io.ktor.application.call
10-
import io.ktor.application.install
11-
import io.ktor.auth.Authentication
12-
import io.ktor.auth.authenticate
13-
import io.ktor.auth.jwt.JWTCredential
14-
import io.ktor.auth.jwt.JWTPrincipal
15-
import io.ktor.auth.jwt.jwt
16-
import io.ktor.auth.principal
178
import io.ktor.client.HttpClient
189
import io.ktor.client.engine.cio.CIO
19-
import io.ktor.client.features.json.JacksonSerializer
20-
import io.ktor.client.features.json.JsonFeature
21-
import io.ktor.client.request.get
22-
import io.ktor.response.respond
23-
import io.ktor.routing.get
24-
import io.ktor.routing.routing
10+
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
11+
import io.ktor.client.request.prepareGet
12+
import io.ktor.serialization.jackson.jackson
13+
import io.ktor.server.application.Application
14+
import io.ktor.server.application.call
15+
import io.ktor.server.application.install
16+
import io.ktor.server.auth.Authentication
17+
import io.ktor.server.auth.authenticate
18+
import io.ktor.server.auth.jwt.JWTCredential
19+
import io.ktor.server.auth.jwt.JWTPrincipal
20+
import io.ktor.server.auth.jwt.jwt
21+
import io.ktor.server.auth.principal
2522
import io.ktor.server.engine.embeddedServer
2623
import io.ktor.server.netty.Netty
24+
import io.ktor.server.response.respond
25+
import io.ktor.server.routing.get
26+
import io.ktor.server.routing.routing
2727
import kotlinx.coroutines.runBlocking
2828
import mu.KotlinLogging
2929
import java.net.URL
@@ -99,15 +99,15 @@ class AuthConfig(
9999
val requiredClaims: Map<String, Any> = emptyMap()
100100
) {
101101
private val httpClient = HttpClient(CIO) {
102-
install(JsonFeature) {
103-
serializer = JacksonSerializer {
102+
install(ContentNegotiation) {
103+
jackson {
104104
configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
105105
setSerializationInclusion(JsonInclude.Include.NON_NULL)
106106
}
107107
}
108108
}
109109

110-
val wellKnown: WellKnown = runBlocking { httpClient.get(wellKnownUrl) }
110+
val wellKnown: WellKnown = runBlocking { httpClient.prepareGet(wellKnownUrl).body() }
111111
val jwkProvider = JwkProviderBuilder(URL(wellKnown.jwksUri))
112112
.cached(10, 24, TimeUnit.HOURS)
113113
.rateLimited(10, 1, TimeUnit.MINUTES)

src/test/kotlin/examples/kotlin/ktor/resourceserver/OAuth2ResourceServerAppTest.kt

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
package examples.kotlin.ktor.resourceserver
22

33
import io.kotest.matchers.shouldBe
4-
import io.ktor.http.HttpMethod
4+
import io.ktor.client.request.get
5+
import io.ktor.client.request.header
6+
import io.ktor.client.statement.bodyAsText
57
import io.ktor.http.HttpStatusCode
6-
import io.ktor.server.testing.handleRequest
7-
import io.ktor.server.testing.withTestApplication
8+
import io.ktor.server.testing.testApplication
89
import no.nav.security.mock.oauth2.MockOAuth2Server
910
import no.nav.security.mock.oauth2.withMockOAuth2Server
1011
import org.junit.jupiter.api.Test
@@ -15,14 +16,13 @@ class OAuth2ResourceServerAppTest {
1516
fun `http get to secured endpoint without token should return 401`() {
1617
withMockOAuth2Server {
1718
val authConfig = authConfig()
18-
withTestApplication({
19-
module(authConfig)
20-
}) {
21-
with(
22-
handleRequest(HttpMethod.Get, "/hello1")
23-
) {
24-
response.status() shouldBe HttpStatusCode.Unauthorized
19+
20+
testApplication {
21+
this.application {
22+
module(authConfig)
2523
}
24+
val response = client.get("/hello1")
25+
response.status shouldBe HttpStatusCode.Unauthorized
2626
}
2727
}
2828
}
@@ -32,17 +32,16 @@ class OAuth2ResourceServerAppTest {
3232
withMockOAuth2Server {
3333
val mockOAuth2Server = this
3434
val authConfig = authConfig()
35-
withTestApplication({
36-
module(authConfig)
37-
}) {
38-
with(
39-
handleRequest(HttpMethod.Get, "/hello1") {
40-
addHeader("Authorization", "Bearer ${mockOAuth2Server.tokenFromProvider1()}")
41-
}
42-
) {
43-
response.status() shouldBe HttpStatusCode.OK
44-
response.content shouldBe "hello1 foo from issuer ${mockOAuth2Server.issuerUrl("provider1")}"
35+
testApplication {
36+
this.application {
37+
module(authConfig)
38+
}
39+
val response = client.get("/hello1") {
40+
header("Authorization", "Bearer ${mockOAuth2Server.tokenFromProvider1()}")
4541
}
42+
43+
response.status shouldBe HttpStatusCode.OK
44+
response.bodyAsText() shouldBe "hello1 foo from issuer ${mockOAuth2Server.issuerUrl("provider1")}"
4645
}
4746
}
4847
}
@@ -52,17 +51,16 @@ class OAuth2ResourceServerAppTest {
5251
withMockOAuth2Server {
5352
val mockOAuth2Server = this
5453
val authConfig = authConfig()
55-
withTestApplication({
56-
module(authConfig)
57-
}) {
58-
with(
59-
handleRequest(HttpMethod.Get, "/hello2") {
60-
addHeader("Authorization", "Bearer ${mockOAuth2Server.tokenFromProvider2()}")
61-
}
62-
) {
63-
response.status() shouldBe HttpStatusCode.OK
64-
response.content shouldBe "hello2 foo from issuer ${mockOAuth2Server.issuerUrl("provider2")}"
54+
testApplication {
55+
this.application {
56+
module(authConfig)
57+
}
58+
59+
val response = client.get("/hello2") {
60+
header("Authorization", "Bearer ${mockOAuth2Server.tokenFromProvider2()}")
6561
}
62+
response.status shouldBe HttpStatusCode.OK
63+
response.bodyAsText() shouldBe "hello2 foo from issuer ${mockOAuth2Server.issuerUrl("provider2")}"
6664
}
6765
}
6866
}

0 commit comments

Comments
 (0)