You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/main/kotlin/no/nav/security/mock/oauth2/extensions/NimbusExtensions.kt
+40-4Lines changed: 40 additions & 4 deletions
Original file line number
Diff line number
Diff line change
@@ -106,20 +106,56 @@ fun HTTPRequest.clientAuthentication() =
106
106
ClientAuthentication.parse(this)
107
107
?:throwOAuth2Exception(OAuth2Error.INVALID_REQUEST, "request must contain some form of ClientAuthentication.")
108
108
109
+
/**
110
+
* TODO: We currently accept multiple audiences for backwards compatibility as updates to RFC7523 are pending.
111
+
* Relevant excerpts:
112
+
* > The JWT MUST contain an aud (audience) claim containing the issuer identifier [RFC8414] of the authorization server as its sole value.
113
+
*
114
+
* > Unlike the aud value specified in [RFC7523], there MUST be no value other than the issuer identifier of the intended authorization server used as the audience of the JWT;
115
+
* > this includes that the token endpoint URL of the authorization server MUST NOT be used as an audience value.
116
+
*
117
+
* > The authorization server MUST reject any JWT that does not contain its issuer identifier as its sole audience value.
118
+
*
119
+
* See [RFC7523bis](https://datatracker.ietf.org/doc/draft-ietf-oauth-rfc7523bis) for details.
120
+
* Compliance with the RFC will require breaking changes.
121
+
**/
109
122
fun ClientAuthentication.requirePrivateKeyJwt(
110
123
requiredAudience:String,
111
124
maxLifetimeSeconds:Long,
125
+
additionalAcceptedAudience:String? = null,
112
126
): PrivateKeyJWT=
113
127
(thisas?PrivateKeyJWT)
114
128
?.let {
129
+
val acceptedAudiences =setOf(requiredAudience, additionalAcceptedAudience).filterNotNull().toSet()
@@ -38,25 +32,12 @@ class TokenExchangeGrantIntegrationTest {
38
32
fun`token request with token exchange grant should exchange subject_token with a new token containing many of the same claims`() {
39
33
withMockOAuth2Server {
40
34
val initialSubject ="yolo"
41
-
val initialToken =
42
-
this.issueToken(
43
-
issuerId ="idprovider",
44
-
clientId ="initialClient",
45
-
tokenCallback =
46
-
DefaultOAuth2TokenCallback(
47
-
issuerId ="idprovider",
48
-
subject = initialSubject,
49
-
claims =
50
-
mapOf(
51
-
"claim1" to "value1",
52
-
"claim2" to "value2",
53
-
),
54
-
),
55
-
)
35
+
val initialToken = issueSubjectToken(subject = initialSubject)
56
36
57
37
val issuerId ="tokenx"
58
38
val tokenEndpointUrl =this.tokenEndpointUrl(issuerId)
59
-
val clientAssertion = clientAssertion("tokenExchangeClient", tokenEndpointUrl.toUrl()).serialize()
39
+
val issuerUrl =this.issuerUrl(issuerId)
40
+
val clientAssertion = clientAssertion(clientId ="tokenExchangeClient", audience = issuerUrl.toString()).serialize()
60
41
val targetAudienceForToken ="targetAudience"
61
42
62
43
val response:ParsedTokenResponse=
@@ -92,21 +73,7 @@ class TokenExchangeGrantIntegrationTest {
92
73
fun`token request with token exchange grant and client basic auth should exchange subject_token with a new token containing many of the same claims`() {
93
74
withMockOAuth2Server {
94
75
val initialSubject ="yolo"
95
-
val initialToken =
96
-
this.issueToken(
97
-
issuerId ="idprovider",
98
-
clientId ="initialClient",
99
-
tokenCallback =
100
-
DefaultOAuth2TokenCallback(
101
-
issuerId ="idprovider",
102
-
subject = initialSubject,
103
-
claims =
104
-
mapOf(
105
-
"claim1" to "value1",
106
-
"claim2" to "value2",
107
-
),
108
-
),
109
-
)
76
+
val initialToken = issueSubjectToken(subject = initialSubject)
110
77
111
78
val issuerId ="tokenx"
112
79
val tokenEndpointUrl =this.tokenEndpointUrl(issuerId)
@@ -140,6 +107,46 @@ class TokenExchangeGrantIntegrationTest {
140
107
}
141
108
}
142
109
110
+
@Test
111
+
fun`token request with client_assertion containing aud equal token endpoint should be allowed`() {
112
+
withMockOAuth2Server {
113
+
val initialSubject ="yolo"
114
+
val initialToken = issueSubjectToken(subject = initialSubject)
115
+
116
+
val issuerId ="tokenx"
117
+
val tokenEndpointUrl =this.tokenEndpointUrl(issuerId)
118
+
val clientAssertion = clientAssertion("clientid", tokenEndpointUrl.toString()).serialize()
119
+
val targetAudienceForToken ="targetAudience"
120
+
121
+
val response:ParsedTokenResponse=
122
+
client
123
+
.tokenRequest(
124
+
url = tokenEndpointUrl,
125
+
parameters =
126
+
mapOf(
127
+
"grant_type" to TOKEN_EXCHANGE.value,
128
+
"client_assertion_type" to ClientAssertionType.JWT_BEARER,
129
+
"client_assertion" to clientAssertion,
130
+
"subject_token_type" to SubjectTokenType.TOKEN_TYPE_JWT,
0 commit comments