diff --git a/src/main/kotlin/no/nav/security/mock/oauth2/extensions/String.kt b/src/main/kotlin/no/nav/security/mock/oauth2/extensions/String.kt index f698a1c6d..ee27e2f1b 100644 --- a/src/main/kotlin/no/nav/security/mock/oauth2/extensions/String.kt +++ b/src/main/kotlin/no/nav/security/mock/oauth2/extensions/String.kt @@ -1,5 +1,7 @@ package no.nav.security.mock.oauth2.extensions +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import com.fasterxml.jackson.module.kotlin.readValue import java.net.URLDecoder import java.nio.charset.StandardCharsets @@ -13,3 +15,5 @@ internal fun String.keyValuesToMap(listDelimiter: String): Map = } internal fun String.urlDecode(): String = URLDecoder.decode(this, StandardCharsets.UTF_8) + +internal fun String.parseJson(): Map = jacksonObjectMapper().readValue(this) diff --git a/src/main/kotlin/no/nav/security/mock/oauth2/http/OAuth2HttpRequest.kt b/src/main/kotlin/no/nav/security/mock/oauth2/http/OAuth2HttpRequest.kt index f6e66404f..6ba36b3b9 100644 --- a/src/main/kotlin/no/nav/security/mock/oauth2/http/OAuth2HttpRequest.kt +++ b/src/main/kotlin/no/nav/security/mock/oauth2/http/OAuth2HttpRequest.kt @@ -16,6 +16,7 @@ import no.nav.security.mock.oauth2.extensions.toJwksUrl import no.nav.security.mock.oauth2.extensions.toRevocationEndpointUrl import no.nav.security.mock.oauth2.extensions.toTokenEndpointUrl import no.nav.security.mock.oauth2.extensions.toUserInfoUrl +import no.nav.security.mock.oauth2.extensions.parseJson import no.nav.security.mock.oauth2.grant.TokenExchangeGrant import no.nav.security.mock.oauth2.missingParameter import okhttp3.Headers @@ -28,7 +29,7 @@ data class OAuth2HttpRequest( val body: String? = null, ) { val url: HttpUrl get() = proxyAwareUrl() - val formParameters: Parameters = Parameters(body) + val formParameters: Parameters = Parameters(body, headers["Content-Type"]) val cookies: Map = headers["Cookie"]?.keyValuesToMap(";") ?: emptyMap() fun asTokenExchangeRequest(): TokenRequest { @@ -136,8 +137,12 @@ data class OAuth2HttpRequest( data class Parameters( val parameterString: String?, + val contentType: String? ) { - val map: Map = parameterString?.keyValuesToMap("&") ?: emptyMap() + val map: Map = when (contentType) { + "application/json" -> parameterString?.parseJson() ?: emptyMap() + else -> parameterString?.keyValuesToMap("&") ?: emptyMap() + } fun get(name: String): String? = map[name] } diff --git a/src/main/kotlin/no/nav/security/mock/oauth2/templates/TemplateMapper.kt b/src/main/kotlin/no/nav/security/mock/oauth2/templates/TemplateMapper.kt index f90b8cc63..c3ae6f1bc 100644 --- a/src/main/kotlin/no/nav/security/mock/oauth2/templates/TemplateMapper.kt +++ b/src/main/kotlin/no/nav/security/mock/oauth2/templates/TemplateMapper.kt @@ -26,7 +26,7 @@ class TemplateMapper( .query(null) .build() .toString(), - "query" to OAuth2HttpRequest.Parameters(oAuth2HttpRequest.url.query).map, + "query" to OAuth2HttpRequest.Parameters(oAuth2HttpRequest.url.query, null).map, ), ), ) @@ -69,7 +69,7 @@ class TemplateMapper( mapOf( "url" to urlWithoutQuery, "token_url" to url.toTokenEndpointUrl(), - "query" to OAuth2HttpRequest.Parameters(url.query).map, + "query" to OAuth2HttpRequest.Parameters(url.query, null).map, "client_auth_method" to clientAuthMethod, ), ), diff --git a/src/test/kotlin/no/nav/security/mock/oauth2/http/OAuth2HttpRequestTest.kt b/src/test/kotlin/no/nav/security/mock/oauth2/http/OAuth2HttpRequestTest.kt index abfbdf717..4296da7f0 100644 --- a/src/test/kotlin/no/nav/security/mock/oauth2/http/OAuth2HttpRequestTest.kt +++ b/src/test/kotlin/no/nav/security/mock/oauth2/http/OAuth2HttpRequestTest.kt @@ -218,4 +218,29 @@ internal class OAuth2HttpRequestTest { req1.toWellKnown().tokenEndpoint shouldBe "http://localhost:8080/mypath/token" req1.toWellKnown().jwksUri shouldBe "http://localhost:8080/mypath/jwks" } + + @Test + fun `form parameters should be parsed from urlencoded string or json`() { + val urlEncodedRequest = OAuth2HttpRequest( + headers = Headers.headersOf("Content-Type", "application/x-www-form-urlencoded"), + method = "POST", + originalUrl = "http://localhost/token".toHttpUrl(), + body = "grant_type=client_credentials&scope=test" + ) + urlEncodedRequest.formParameters.map shouldBe mapOf( + "grant_type" to "client_credentials", + "scope" to "test" + ) + + val jsonRequest = OAuth2HttpRequest( + headers = Headers.headersOf("Content-Type", "application/json"), + method = "POST", + originalUrl = "http://localhost/token".toHttpUrl(), + body = """{"grant_type": "client_credentials", "scope": "test"}""" + ) + jsonRequest.formParameters.map shouldBe mapOf( + "grant_type" to "client_credentials", + "scope" to "test" + ) + } }