Skip to content

Commit eb8976f

Browse files
tommytroentronghn
authored andcommitted
refactor: replace custom TokenExchangeGrant with Nimbus SDK grant
* breaking: TokenExchangeGrant.kt has been removed in favor of com.nimbusds.oauth2.sdk.tokenexchange.TokenExchangeGrant, this affects the extension function fun TokenRequest.tokenExchangeGrantOrNull() * use nimbus sdk to construct tokenRequest for token_exchange * remove use of deprecated constructors for nimbus TokenRequest * formatting
1 parent 6174c6c commit eb8976f

File tree

9 files changed

+21
-66
lines changed

9 files changed

+21
-66
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ open class MockOAuth2Server(
295295
TokenRequest
296296
.Builder(
297297
URI.create("http://mockgrant"),
298-
ClientID("mockclientid"),
298+
ClientSecretBasic(ClientID("mockclientid"), Secret("secret")),
299299
mockGrant,
300300
).build()
301301
return this.config.tokenProvider.exchangeAccessToken(

src/main/kotlin/no/nav/security/mock/oauth2/extensions/NimbusExtensions.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ import com.nimbusds.openid.connect.sdk.OIDCScopeValue
3030
import com.nimbusds.openid.connect.sdk.Prompt
3131
import mu.KotlinLogging
3232
import no.nav.security.mock.oauth2.OAuth2Exception
33-
import no.nav.security.mock.oauth2.grant.TokenExchangeGrant
3433
import no.nav.security.mock.oauth2.invalidRequest
3534
import java.time.Duration
3635
import java.time.Instant
@@ -63,7 +62,7 @@ fun TokenRequest.scopesWithoutOidcScopes() =
6362
OIDCScopeValue.values().map { it.toString() }.contains(value)
6463
} ?: emptyList()
6564

66-
fun TokenRequest.tokenExchangeGrantOrNull(): TokenExchangeGrant? = authorizationGrant as? TokenExchangeGrant
65+
fun TokenRequest.tokenExchangeGrantOrNull() = authorizationGrant as? com.nimbusds.oauth2.sdk.tokenexchange.TokenExchangeGrant
6766

6867
fun TokenRequest.authorizationCode(): AuthorizationCode =
6968
this.authorizationGrant

src/main/kotlin/no/nav/security/mock/oauth2/grant/TokenExchangeGrant.kt

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

src/main/kotlin/no/nav/security/mock/oauth2/grant/TokenExchangeGrantHandler.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package no.nav.security.mock.oauth2.grant
22

33
import com.nimbusds.jwt.SignedJWT
44
import com.nimbusds.oauth2.sdk.TokenRequest
5+
import com.nimbusds.oauth2.sdk.tokenexchange.TokenExchangeGrant
56
import no.nav.security.mock.oauth2.extensions.expiresIn
67
import no.nav.security.mock.oauth2.http.OAuth2HttpRequest
78
import no.nav.security.mock.oauth2.http.OAuth2TokenResponse
@@ -36,6 +37,8 @@ internal class TokenExchangeGrantHandler(
3637
}
3738
}
3839

39-
fun TokenRequest.subjectToken(): SignedJWT = SignedJWT.parse(this.tokenExchangeGrant().subjectToken)
40+
fun TokenRequest.subjectToken(): SignedJWT = SignedJWT.parse(this.tokenExchangeGrant().subjectToken.value)
41+
42+
fun TokenRequest.audienceOrEmpty(): List<String> = (this.authorizationGrant as? TokenExchangeGrant)?.audience?.map { it.value } ?: emptyList()
4043

4144
fun TokenRequest.tokenExchangeGrant() = this.authorizationGrant as? TokenExchangeGrant ?: invalidRequest("missing token exchange grant")

src/main/kotlin/no/nav/security/mock/oauth2/http/OAuth2HttpRequest.kt

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import no.nav.security.mock.oauth2.extensions.toJwksUrl
1616
import no.nav.security.mock.oauth2.extensions.toRevocationEndpointUrl
1717
import no.nav.security.mock.oauth2.extensions.toTokenEndpointUrl
1818
import no.nav.security.mock.oauth2.extensions.toUserInfoUrl
19-
import no.nav.security.mock.oauth2.grant.TokenExchangeGrant
2019
import no.nav.security.mock.oauth2.missingParameter
2120
import okhttp3.Headers
2221
import okhttp3.HttpUrl
@@ -33,27 +32,17 @@ data class OAuth2HttpRequest(
3332

3433
fun asTokenExchangeRequest(): TokenRequest {
3534
val httpRequest: HTTPRequest = this.asNimbusHTTPRequest()
36-
var clientAuthentication = httpRequest.clientAuthentication()
35+
val clientAuthentication = httpRequest.clientAuthentication()
3736
if (clientAuthentication.method == ClientAuthenticationMethod.PRIVATE_KEY_JWT) {
38-
clientAuthentication =
39-
clientAuthentication.requirePrivateKeyJwt(
40-
requiredAudience = this.url.toIssuerUrl().toString(),
41-
maxLifetimeSeconds = 120,
42-
additionalAcceptedAudience = this.url.toString(),
43-
)
44-
}
45-
val tokenExchangeGrant = TokenExchangeGrant.parse(formParameters.map)
46-
47-
// TODO: add scope if present in request
48-
val builder =
49-
TokenRequest.Builder(
50-
this.url.toUri(),
51-
clientAuthentication,
52-
tokenExchangeGrant,
37+
clientAuthentication.requirePrivateKeyJwt(
38+
requiredAudience = this.url.toIssuerUrl().toString(),
39+
maxLifetimeSeconds = 120,
40+
additionalAcceptedAudience = this.url.toString(),
5341
)
54-
formParameters.map.forEach { (key, value) -> builder.customParameter(key, value) }
55-
56-
return builder.build()
42+
}
43+
return TokenRequest.parse(
44+
this.asNimbusHTTPRequest(),
45+
)
5746
}
5847

5948
@Suppress("MemberVisibilityCanBePrivate")

src/main/kotlin/no/nav/security/mock/oauth2/http/OAuth2HttpRequestHandler.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import com.nimbusds.oauth2.sdk.GrantType.CLIENT_CREDENTIALS
88
import com.nimbusds.oauth2.sdk.GrantType.JWT_BEARER
99
import com.nimbusds.oauth2.sdk.GrantType.PASSWORD
1010
import com.nimbusds.oauth2.sdk.GrantType.REFRESH_TOKEN
11+
import com.nimbusds.oauth2.sdk.GrantType.TOKEN_EXCHANGE
1112
import com.nimbusds.oauth2.sdk.OAuth2Error
1213
import com.nimbusds.oauth2.sdk.ParseException
1314
import com.nimbusds.openid.connect.sdk.AuthenticationRequest
@@ -33,7 +34,6 @@ import no.nav.security.mock.oauth2.grant.PasswordGrantHandler
3334
import no.nav.security.mock.oauth2.grant.RefreshToken
3435
import no.nav.security.mock.oauth2.grant.RefreshTokenGrantHandler
3536
import no.nav.security.mock.oauth2.grant.RefreshTokenManager
36-
import no.nav.security.mock.oauth2.grant.TOKEN_EXCHANGE
3737
import no.nav.security.mock.oauth2.grant.TokenExchangeGrantHandler
3838
import no.nav.security.mock.oauth2.introspect.introspect
3939
import no.nav.security.mock.oauth2.invalidGrant

src/main/kotlin/no/nav/security/mock/oauth2/token/OAuth2TokenCallback.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import no.nav.security.mock.oauth2.extensions.clientIdAsString
77
import no.nav.security.mock.oauth2.extensions.grantType
88
import no.nav.security.mock.oauth2.extensions.replaceValues
99
import no.nav.security.mock.oauth2.extensions.scopesWithoutOidcScopes
10-
import no.nav.security.mock.oauth2.extensions.tokenExchangeGrantOrNull
10+
import no.nav.security.mock.oauth2.grant.audienceOrEmpty
1111
import java.time.Duration
1212
import java.util.UUID
1313

@@ -48,10 +48,10 @@ open class DefaultOAuth2TokenCallback
4848
override fun typeHeader(tokenRequest: TokenRequest): String = typeHeader
4949

5050
override fun audience(tokenRequest: TokenRequest): List<String> {
51-
val audienceParam = tokenRequest.tokenExchangeGrantOrNull()?.audience
51+
val audienceParam = tokenRequest.audienceOrEmpty()
5252
return when {
5353
audience != null -> audience
54-
audienceParam != null -> audienceParam
54+
audienceParam.isNotEmpty() -> audienceParam
5555
tokenRequest.scope != null -> tokenRequest.scopesWithoutOidcScopes()
5656
else -> listOf("default")
5757
}

src/test/kotlin/no/nav/security/mock/oauth2/e2e/TokenExchangeGrantIntegrationTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package no.nav.security.mock.oauth2.e2e
22

3+
import com.nimbusds.oauth2.sdk.GrantType.TOKEN_EXCHANGE
34
import io.kotest.matchers.collections.shouldContainExactly
45
import io.kotest.matchers.should
56
import io.kotest.matchers.shouldBe
6-
import no.nav.security.mock.oauth2.grant.TOKEN_EXCHANGE
77
import no.nav.security.mock.oauth2.testutils.ClientAssertionType
88
import no.nav.security.mock.oauth2.testutils.ParsedTokenResponse
99
import no.nav.security.mock.oauth2.testutils.SubjectTokenType

src/test/kotlin/no/nav/security/mock/oauth2/testutils/Token.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import com.nimbusds.oauth2.sdk.GrantType.CLIENT_CREDENTIALS
2121
import com.nimbusds.oauth2.sdk.GrantType.JWT_BEARER
2222
import com.nimbusds.oauth2.sdk.GrantType.PASSWORD
2323
import com.nimbusds.oauth2.sdk.GrantType.REFRESH_TOKEN
24+
import com.nimbusds.oauth2.sdk.GrantType.TOKEN_EXCHANGE
2425
import com.nimbusds.oauth2.sdk.TokenRequest
2526
import io.kotest.assertions.assertSoftly
2627
import io.kotest.matchers.Matcher
@@ -29,7 +30,6 @@ import io.kotest.matchers.ints.shouldBeGreaterThan
2930
import io.kotest.matchers.shouldBe
3031
import io.kotest.matchers.shouldNotBe
3132
import no.nav.security.mock.oauth2.MockOAuth2Server
32-
import no.nav.security.mock.oauth2.grant.TOKEN_EXCHANGE
3333
import no.nav.security.mock.oauth2.http.OAuth2HttpRequest
3434
import no.nav.security.mock.oauth2.http.OAuth2TokenResponse
3535
import no.nav.security.mock.oauth2.token.DefaultOAuth2TokenCallback

0 commit comments

Comments
 (0)