Skip to content

Commit 4a1d254

Browse files
committed
ensure server is using localhost when no address i specified. add more tests, including verifying tokens issued by the server
1 parent bde1d07 commit 4a1d254

File tree

4 files changed

+92
-14
lines changed

4 files changed

+92
-14
lines changed

src/main/kotlin/no/nav/security/mock/oauth2/MockOAuth2Server.kt

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,29 +22,28 @@ import okhttp3.mockwebserver.MockResponse
2222
import okhttp3.mockwebserver.MockWebServer
2323
import okhttp3.mockwebserver.RecordedRequest
2424
import java.io.IOException
25-
import java.net.InetSocketAddress
25+
import java.net.InetAddress
2626
import java.net.URI
2727
import java.util.concurrent.BlockingQueue
2828
import java.util.concurrent.LinkedBlockingQueue
2929

3030
private val log = KotlinLogging.logger {}
3131

32+
// TODO make open so others can extend?
3233
class MockOAuth2Server(
3334
val config: OAuth2Config = OAuth2Config()
3435
) {
3536
private val mockWebServer: MockWebServer = MockWebServer()
3637

3738
var dispatcher: Dispatcher = MockOAuth2Dispatcher(config)
3839

39-
fun start() {
40-
mockWebServer.start()
41-
mockWebServer.dispatcher = dispatcher
42-
}
40+
@Throws(IOException::class)
41+
@JvmOverloads
42+
fun start(port: Int = 0) = start(InetAddress.getByName("localhost"), port)
4343

44-
fun start(port: Int = 0) {
45-
val address = InetSocketAddress(0).address
46-
log.info("attempting to start server on port $port and InetAddress=$address")
47-
mockWebServer.start(address, port)
44+
@Throws(IOException::class)
45+
fun start(inetAddress: InetAddress, port: Int) {
46+
mockWebServer.start(inetAddress, port)
4847
mockWebServer.dispatcher = dispatcher
4948
}
5049

src/main/kotlin/no/nav/security/mock/oauth2/StandaloneMockOAuth2Server.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.natpryce.konfig.Key
66
import com.natpryce.konfig.intType
77
import com.natpryce.konfig.overriding
88
import com.natpryce.konfig.stringType
9+
import java.net.InetSocketAddress
910

1011
private val config = ConfigurationProperties.systemProperties() overriding
1112
EnvironmentVariables()
@@ -21,9 +22,10 @@ data class Configuration(
2122

2223
fun main() {
2324
val config = Configuration()
25+
// TODO check if ok in docker compose
2426
MockOAuth2Server(
2527
OAuth2Config(
2628
interactiveLogin = true
2729
)
28-
).start(config.server.port)
30+
).start(InetSocketAddress(0).address, config.server.port)
2931
}

src/test/kotlin/no/nav/security/mock/oauth2/MockOAuth2ServerTest.kt

Lines changed: 80 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,14 @@ package no.nav.security.mock.oauth2
22

33
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
44
import com.fasterxml.jackson.module.kotlin.readValue
5+
import com.nimbusds.jose.jwk.JWKSet
6+
import com.nimbusds.jwt.JWTClaimsSet
57
import com.nimbusds.jwt.SignedJWT
68
import com.nimbusds.oauth2.sdk.GrantType
9+
import com.nimbusds.oauth2.sdk.id.Issuer
10+
import no.nav.security.mock.oauth2.extensions.verifySignatureAndIssuer
711
import no.nav.security.mock.oauth2.http.OAuth2TokenResponse
12+
import no.nav.security.mock.oauth2.http.WellKnown
813
import no.nav.security.mock.oauth2.token.DefaultOAuth2TokenCallback
914
import no.nav.security.mock.oauth2.token.OAuth2TokenProvider
1015
import okhttp3.Credentials
@@ -52,6 +57,31 @@ class MockOAuth2ServerTest {
5257
interactiveLoginServer.shutdown()
5358
}
5459

60+
@Test
61+
fun startServerWithFixedPort() {
62+
val serverWithFixedPort = MockOAuth2Server()
63+
serverWithFixedPort.start(1234)
64+
val wellKnown: WellKnown = assertWellKnownResponseForIssuer(serverWithFixedPort, "default")
65+
66+
val tokenIssuedDirectlyFromServer: SignedJWT = serverWithFixedPort.issueToken("default", "yo", DefaultOAuth2TokenCallback())
67+
assertThat(tokenIssuedDirectlyFromServer.verifySignatureAndIssuer(Issuer(wellKnown.issuer), retrieveJwks(wellKnown.jwksUri))).isNotNull
68+
69+
val authCodeTokenResponse: Response = client.newCall(
70+
authCodeTokenRequest(
71+
wellKnown.tokenEndpoint.toHttpUrlOrNull()!!,
72+
"client",
73+
"someredirect",
74+
"scope1",
75+
"123"
76+
)
77+
).execute()
78+
79+
val tokenResponse: OAuth2TokenResponse = jacksonObjectMapper().readValue(authCodeTokenResponse.body!!.string())
80+
val tokenFromAuthCode: SignedJWT = tokenResponse.idToken!!.let { SignedJWT.parse(it) }
81+
assertThat(tokenFromAuthCode.verifySignatureAndIssuer(Issuer(wellKnown.issuer), retrieveJwks(wellKnown.jwksUri))).isNotNull
82+
serverWithFixedPort.shutdown()
83+
}
84+
5585
@Test
5686
fun wellKnownUrlForMultipleIssuers() {
5787
assertWellKnownResponseForIssuer("default")
@@ -62,9 +92,10 @@ class MockOAuth2ServerTest {
6292
@Test
6393
fun enqueuedResponse() {
6494
assertWellKnownResponseForIssuer("default")
65-
server.enqueueResponse(MockResponse()
66-
.setResponseCode(200)
67-
.setBody("some body")
95+
server.enqueueResponse(
96+
MockResponse()
97+
.setResponseCode(200)
98+
.setBody("some body")
6899
)
69100
val request: Request = Request.Builder()
70101
.url(server.url("/someurl"))
@@ -281,6 +312,52 @@ class MockOAuth2ServerTest {
281312
assertThat(accessToken.jwtClaimsSet.issuer).endsWith("default")
282313
}
283314

315+
@Test
316+
fun issueTokenDirectlyFromMockOAuth2Server() {
317+
val signedJWT: SignedJWT = server.issueToken(
318+
"default", "client1", DefaultOAuth2TokenCallback(
319+
issuerId = "default",
320+
subject = "mysub",
321+
audience = "muyaud",
322+
claims = mapOf("someclaim" to "claimvalue")
323+
)
324+
)
325+
val wellKnownResponseBody = assertWellKnownResponseForIssuer("default")!!
326+
val wellKnown: WellKnown = jacksonObjectMapper().readValue(wellKnownResponseBody)
327+
val jwkSet: JWKSet = retrieveJwks(wellKnown.jwksUri)
328+
val jwtClaimsSet: JWTClaimsSet = signedJWT.verifySignatureAndIssuer(Issuer(wellKnown.issuer), jwkSet)
329+
assertThat(jwtClaimsSet.issuer).isEqualTo(wellKnown.issuer)
330+
assertThat(jwtClaimsSet.subject).isEqualTo("mysub")
331+
assertThat(jwtClaimsSet.audience).containsExactly("muyaud")
332+
assertThat(jwtClaimsSet.getClaim("someclaim")).isEqualTo("claimvalue")
333+
}
334+
335+
private fun retrieveJwks(jwksUri: String): JWKSet {
336+
return client.newCall(
337+
Request.Builder()
338+
.url(jwksUri)
339+
.get()
340+
.build()
341+
).execute().body?.string()?.let {
342+
JWKSet.parse(it)
343+
} ?: throw RuntimeException("could not retrieve jwks")
344+
}
345+
346+
private fun assertWellKnownResponseForIssuer(mockOAuth2Server: MockOAuth2Server, issuerId: String): WellKnown {
347+
val wellKnownResponse: Response = client.newCall(
348+
Request.Builder()
349+
.url(mockOAuth2Server.wellKnownUrl(issuerId))
350+
.get()
351+
.build()
352+
).execute()
353+
val wellKnown: WellKnown = jacksonObjectMapper().readValue(wellKnownResponse.body!!.string())
354+
assertThat(wellKnown.issuer).isEqualTo(mockOAuth2Server.issuerUrl(issuerId).toString())
355+
assertThat(wellKnown.authorizationEndpoint).isEqualTo(mockOAuth2Server.authorizationEndpointUrl(issuerId).toString())
356+
assertThat(wellKnown.tokenEndpoint).isEqualTo(mockOAuth2Server.tokenEndpointUrl(issuerId).toString())
357+
assertThat(wellKnown.jwksUri).isEqualTo(mockOAuth2Server.jwksUrl(issuerId).toString())
358+
return wellKnown
359+
}
360+
284361
private fun assertWellKnownResponseForIssuer(issuerId: String): String? {
285362
val request: Request = Request.Builder()
286363
.url(server.wellKnownUrl(issuerId))

src/test/kotlin/no/nav/security/mock/oauth2/examples/AbstractExampleApp.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ abstract class AbstractExampleApp(oauth2DiscoveryUrl: String) {
105105

106106
fun json(value: Any): MockResponse = MockResponse()
107107
.setResponseCode(200)
108-
.setHeader("Content-Type","application/json")
108+
.setHeader("Content-Type", "application/json")
109109
.setBody(ObjectMapper().writeValueAsString(value))
110110

111111
abstract fun handleRequest(request: RecordedRequest): MockResponse

0 commit comments

Comments
 (0)