Skip to content

Commit e06b06d

Browse files
committed
Polish "Support RFC 8414 in JwtDecoders and ClientRegistrations"
See gh-17761
1 parent 8baec96 commit e06b06d

File tree

5 files changed

+31
-112
lines changed

5 files changed

+31
-112
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,8 @@ public static class Provider {
214214
private String jwkSetUri;
215215

216216
/**
217-
* URI that an OpenID Connect Provider asserts as its Issuer Identifier.
217+
* URI that can either be an OpenID Connect discovery endpoint or an OAuth 2.0
218+
* Authorization Server Metadata endpoint defined by RFC 8414.
218219
*/
219220
private String issuerUri;
220221

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ public static class Jwt {
8282
private String jwsAlgorithm = "RS256";
8383

8484
/**
85-
* URI that an OpenID Connect Provider asserts as its Issuer Identifier.
85+
* URI that can either be an OpenID Connect discovery endpoint or an OAuth 2.0
86+
* Authorization Server Metadata endpoint defined by RFC 8414.
8687
*/
8788
private String issuerUri;
8889

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java

Lines changed: 13 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
* @author Phillip Webb
4949
* @author Madhura Bhave
5050
* @author Thiago Hirata
51+
* @author HaiTao Zhang
5152
*/
5253
class OAuth2ClientPropertiesRegistrationAdapterTests {
5354

@@ -209,23 +210,7 @@ void oidcProviderConfigurationWhenProviderNotSpecifiedOnRegistration() throws Ex
209210
Registration login = new OAuth2ClientProperties.Registration();
210211
login.setClientId("clientId");
211212
login.setClientSecret("clientSecret");
212-
testOidcConfiguration(login, "okta");
213-
}
214-
215-
@Test
216-
void oidcRfc8414ProviderConfigurationWhenProviderNotSpecifiedOnRegistration() throws Exception {
217-
OAuth2ClientProperties.Registration login = new Registration();
218-
login.setClientId("clientId");
219-
login.setClientSecret("clientSecret");
220-
testOidcRfc8414Configuration(login, "okta");
221-
}
222-
223-
@Test
224-
void oAuthProviderConfigurationWhenProviderNotSpecifiedOnRegistration() throws Exception {
225-
OAuth2ClientProperties.Registration login = new Registration();
226-
login.setClientId("clientId");
227-
login.setClientSecret("clientSecret");
228-
testOAuthConfiguration(login, "okta");
213+
testIssuerConfiguration(login, "okta", 0, 1);
229214
}
230215

231216
@Test
@@ -234,25 +219,23 @@ void oidcProviderConfigurationWhenProviderSpecifiedOnRegistration() throws Excep
234219
login.setProvider("okta-oidc");
235220
login.setClientId("clientId");
236221
login.setClientSecret("clientSecret");
237-
testOidcConfiguration(login, "okta-oidc");
222+
testIssuerConfiguration(login, "okta-oidc", 0, 1);
238223
}
239224

240225
@Test
241-
void oidcRfc8414ProviderConfigurationWhenProviderSpecifiedOnRegistration() throws Exception {
226+
void issuerUriConfigurationTriesOidcRfc8414UriSecond() throws Exception {
242227
OAuth2ClientProperties.Registration login = new Registration();
243-
login.setProvider("okta-oidcRfc8414");
244228
login.setClientId("clientId");
245229
login.setClientSecret("clientSecret");
246-
testOidcRfc8414Configuration(login, "okta-oidcRfc8414");
230+
testIssuerConfiguration(login, "okta", 1, 2);
247231
}
248232

249233
@Test
250-
void oAuthProviderConfigurationWhenProviderSpecifiedOnRegistration() throws Exception {
234+
void issuerUriConfigurationTriesOAuthMetadataUriThird() throws Exception {
251235
OAuth2ClientProperties.Registration login = new Registration();
252-
login.setProvider("okta-oauth");
253236
login.setClientId("clientId");
254237
login.setClientSecret("clientSecret");
255-
testOAuthConfiguration(login, "okta-oauth");
238+
testIssuerConfiguration(login, "okta", 2, 3);
256239
}
257240

258241
@Test
@@ -307,75 +290,12 @@ private OAuth2ClientProperties.Registration createRegistration(String provider)
307290
return registration;
308291
}
309292

310-
private void testOidcConfiguration(OAuth2ClientProperties.Registration registration, String providerId)
311-
throws Exception {
293+
private void testIssuerConfiguration(OAuth2ClientProperties.Registration registration, String providerId,
294+
int errorResponseCount, int numberOfRequests) throws Exception {
312295
this.server = new MockWebServer();
313296
this.server.start();
314297
String issuer = this.server.url("").toString();
315-
setupMockResponse(issuer);
316-
OAuth2ClientProperties properties = new OAuth2ClientProperties();
317-
Provider provider = new Provider();
318-
provider.setIssuerUri(issuer);
319-
properties.getProvider().put(providerId, provider);
320-
properties.getRegistration().put("okta", registration);
321-
Map<String, ClientRegistration> registrations = OAuth2ClientPropertiesRegistrationAdapter
322-
.getClientRegistrations(properties);
323-
ClientRegistration adapted = registrations.get("okta");
324-
ProviderDetails providerDetails = adapted.getProviderDetails();
325-
assertThat(adapted.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.BASIC);
326-
assertThat(adapted.getAuthorizationGrantType()).isEqualTo(AuthorizationGrantType.AUTHORIZATION_CODE);
327-
assertThat(adapted.getRegistrationId()).isEqualTo("okta");
328-
assertThat(adapted.getClientName()).isEqualTo(issuer);
329-
assertThat(adapted.getScopes()).containsOnly("openid");
330-
assertThat(providerDetails.getAuthorizationUri()).isEqualTo("https://example.com/o/oauth2/v2/auth");
331-
assertThat(providerDetails.getTokenUri()).isEqualTo("https://example.com/oauth2/v4/token");
332-
assertThat(providerDetails.getJwkSetUri()).isEqualTo("https://example.com/oauth2/v3/certs");
333-
UserInfoEndpoint userInfoEndpoint = providerDetails.getUserInfoEndpoint();
334-
assertThat(userInfoEndpoint.getUri()).isEqualTo("https://example.com/oauth2/v3/userinfo");
335-
assertThat(userInfoEndpoint.getAuthenticationMethod())
336-
.isEqualTo(org.springframework.security.oauth2.core.AuthenticationMethod.HEADER);
337-
assertThat(this.server.getRequestCount()).isEqualTo(1);
338-
}
339-
340-
private void testOidcRfc8414Configuration(OAuth2ClientProperties.Registration registration, String providerId)
341-
throws Exception {
342-
this.server = new MockWebServer();
343-
this.server.start();
344-
String path = "test";
345-
String issuer = this.server.url(path).toString();
346-
setupMockResponseWithEmptyResponses(issuer, 1);
347-
OAuth2ClientProperties properties = new OAuth2ClientProperties();
348-
Provider provider = new Provider();
349-
provider.setIssuerUri(issuer);
350-
properties.getProvider().put(providerId, provider);
351-
properties.getRegistration().put("okta", registration);
352-
Map<String, ClientRegistration> registrations = OAuth2ClientPropertiesRegistrationAdapter
353-
.getClientRegistrations(properties);
354-
ClientRegistration adapted = registrations.get("okta");
355-
ProviderDetails providerDetails = adapted.getProviderDetails();
356-
assertThat(adapted.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.BASIC);
357-
assertThat(adapted.getAuthorizationGrantType()).isEqualTo(AuthorizationGrantType.AUTHORIZATION_CODE);
358-
assertThat(adapted.getRegistrationId()).isEqualTo("okta");
359-
assertThat(adapted.getClientName()).isEqualTo(issuer);
360-
assertThat(adapted.getScopes()).containsOnly("openid");
361-
assertThat(providerDetails.getAuthorizationUri()).isEqualTo("https://example.com/o/oauth2/v2/auth");
362-
assertThat(providerDetails.getTokenUri()).isEqualTo("https://example.com/oauth2/v4/token");
363-
assertThat(providerDetails.getJwkSetUri()).isEqualTo("https://example.com/oauth2/v3/certs");
364-
UserInfoEndpoint userInfoEndpoint = providerDetails.getUserInfoEndpoint();
365-
assertThat(userInfoEndpoint.getUri()).isEqualTo("https://example.com/oauth2/v3/userinfo");
366-
assertThat(userInfoEndpoint.getAuthenticationMethod())
367-
.isEqualTo(org.springframework.security.oauth2.core.AuthenticationMethod.HEADER);
368-
assertThat(this.server.getRequestCount()).isEqualTo(2);
369-
370-
}
371-
372-
private void testOAuthConfiguration(OAuth2ClientProperties.Registration registration, String providerId)
373-
throws Exception {
374-
this.server = new MockWebServer();
375-
this.server.start();
376-
String path = "test";
377-
String issuer = this.server.url(path).toString();
378-
setupMockResponseWithEmptyResponses(issuer, 2);
298+
setupMockResponsesWithErrors(issuer, errorResponseCount);
379299
OAuth2ClientProperties properties = new OAuth2ClientProperties();
380300
Provider provider = new Provider();
381301
provider.setIssuerUri(issuer);
@@ -397,7 +317,7 @@ private void testOAuthConfiguration(OAuth2ClientProperties.Registration registra
397317
assertThat(userInfoEndpoint.getUri()).isEqualTo("https://example.com/oauth2/v3/userinfo");
398318
assertThat(userInfoEndpoint.getAuthenticationMethod())
399319
.isEqualTo(org.springframework.security.oauth2.core.AuthenticationMethod.HEADER);
400-
assertThat(this.server.getRequestCount()).isEqualTo(3);
320+
assertThat(this.server.getRequestCount()).isEqualTo(numberOfRequests);
401321
}
402322

403323
private void setupMockResponse(String issuer) throws JsonProcessingException {
@@ -407,9 +327,8 @@ private void setupMockResponse(String issuer) throws JsonProcessingException {
407327
this.server.enqueue(mockResponse);
408328
}
409329

410-
private void setupMockResponseWithEmptyResponses(String issuer, int amountOfEmptyResponse)
411-
throws JsonProcessingException {
412-
for (int i = 0; i < amountOfEmptyResponse; i++) {
330+
private void setupMockResponsesWithErrors(String issuer, int errorResponseCount) throws JsonProcessingException {
331+
for (int i = 0; i < errorResponseCount; i++) {
413332
MockResponse emptyResponse = new MockResponse().setResponseCode(HttpStatus.NOT_FOUND.value());
414333
this.server.enqueue(emptyResponse);
415334
}

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
*
6565
* @author Madhura Bhave
6666
* @author Artsiom Yudovin
67+
* @author HaiTao Zhang
6768
*/
6869
class ReactiveOAuth2ResourceServerAutoConfigurationTests {
6970

@@ -111,12 +112,11 @@ void autoConfigurationShouldConfigureResourceServerUsingOidcIssuerUri() throws I
111112
void autoConfigurationShouldConfigureResourceServerUsingOidcRfc8414IssuerUri() throws Exception {
112113
this.server = new MockWebServer();
113114
this.server.start();
114-
String path = "test";
115-
String issuer = this.server.url(path).toString();
115+
String issuer = this.server.url("").toString();
116116
String cleanIssuerPath = cleanIssuerPath(issuer);
117-
setupMockResponseWithEmptyResponses(cleanIssuerPath, 1);
117+
setupMockResponsesWithErrors(cleanIssuerPath, 1);
118118
this.contextRunner.withPropertyValues("spring.security.oauth2.resourceserver.jwt.issuer-uri=http://"
119-
+ this.server.getHostName() + ":" + this.server.getPort() + "/" + path).run((context) -> {
119+
+ this.server.getHostName() + ":" + this.server.getPort()).run((context) -> {
120120
assertThat(context).hasSingleBean(NimbusReactiveJwtDecoder.class);
121121
assertFilterConfiguredWithJwtAuthenticationManager(context);
122122
assertThat(context.containsBean("jwtDecoderByIssuerUri")).isTrue();
@@ -128,12 +128,11 @@ void autoConfigurationShouldConfigureResourceServerUsingOidcRfc8414IssuerUri() t
128128
void autoConfigurationShouldConfigureResourceServerUsingOAuthIssuerUri() throws Exception {
129129
this.server = new MockWebServer();
130130
this.server.start();
131-
String path = "test";
132-
String issuer = this.server.url(path).toString();
131+
String issuer = this.server.url("").toString();
133132
String cleanIssuerPath = cleanIssuerPath(issuer);
134-
setupMockResponseWithEmptyResponses(cleanIssuerPath, 2);
133+
setupMockResponsesWithErrors(cleanIssuerPath, 2);
135134
this.contextRunner.withPropertyValues("spring.security.oauth2.resourceserver.jwt.issuer-uri=http://"
136-
+ this.server.getHostName() + ":" + this.server.getPort() + "/" + path).run((context) -> {
135+
+ this.server.getHostName() + ":" + this.server.getPort()).run((context) -> {
137136
assertThat(context).hasSingleBean(NimbusReactiveJwtDecoder.class);
138137
assertFilterConfiguredWithJwtAuthenticationManager(context);
139138
assertThat(context.containsBean("jwtDecoderByIssuerUri")).isTrue();
@@ -359,9 +358,8 @@ private void setupMockResponse(String issuer) throws JsonProcessingException {
359358
this.server.enqueue(mockResponse);
360359
}
361360

362-
private void setupMockResponseWithEmptyResponses(String issuer, int amountOfEmptyResponse)
363-
throws JsonProcessingException {
364-
for (int i = 0; i < amountOfEmptyResponse; i++) {
361+
private void setupMockResponsesWithErrors(String issuer, int errorResponseCount) throws JsonProcessingException {
362+
for (int i = 0; i < errorResponseCount; i++) {
365363
MockResponse emptyResponse = new MockResponse().setResponseCode(HttpStatus.NOT_FOUND.value());
366364
this.server.enqueue(emptyResponse);
367365
}

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
*
5959
* @author Madhura Bhave
6060
* @author Artsiom Yudovin
61+
* @author HaiTao Zhang
6162
*/
6263
class OAuth2ResourceServerAutoConfigurationTests {
6364

@@ -133,7 +134,7 @@ void autoConfigurationShouldConfigureResourceServerUsingOidcRfc8414IssuerUri() t
133134
String path = "test";
134135
String issuer = this.server.url(path).toString();
135136
String cleanIssuerPath = cleanIssuerPath(issuer);
136-
setupMockResponseWithEmptyResponses(cleanIssuerPath, 1);
137+
setupMockResponsesWithErrors(cleanIssuerPath, 1);
137138
this.contextRunner.withPropertyValues("spring.security.oauth2.resourceserver.jwt.issuer-uri=http://"
138139
+ this.server.getHostName() + ":" + this.server.getPort() + "/" + path).run((context) -> {
139140
assertThat(context).hasSingleBean(JwtDecoder.class);
@@ -149,7 +150,7 @@ void autoConfigurationShouldConfigureResourceServerUsingOAuthIssuerUri() throws
149150
String path = "test";
150151
String issuer = this.server.url(path).toString();
151152
String cleanIssuerPath = cleanIssuerPath(issuer);
152-
setupMockResponseWithEmptyResponses(cleanIssuerPath, 2);
153+
setupMockResponsesWithErrors(cleanIssuerPath, 2);
153154
this.contextRunner.withPropertyValues("spring.security.oauth2.resourceserver.jwt.issuer-uri=http://"
154155
+ this.server.getHostName() + ":" + this.server.getPort() + "/" + path).run((context) -> {
155156
assertThat(context).hasSingleBean(JwtDecoder.class);
@@ -340,9 +341,8 @@ private void setupMockResponse(String issuer) throws JsonProcessingException {
340341
this.server.enqueue(mockResponse);
341342
}
342343

343-
private void setupMockResponseWithEmptyResponses(String issuer, int amountOfEmptyResponse)
344-
throws JsonProcessingException {
345-
for (int i = 0; i < amountOfEmptyResponse; i++) {
344+
private void setupMockResponsesWithErrors(String issuer, int errorResponseCount) throws JsonProcessingException {
345+
for (int i = 0; i < errorResponseCount; i++) {
346346
MockResponse emptyResponse = new MockResponse().setResponseCode(HttpStatus.NOT_FOUND.value());
347347
this.server.enqueue(emptyResponse);
348348
}

0 commit comments

Comments
 (0)