diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java index 2bb49a2453..8b16e6b2fd 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java @@ -214,7 +214,8 @@ public class OAuth2ClientProperties { private String jwkSetUri; /** - * URI that an OpenID Connect Provider asserts as its Issuer Identifier. + * URI that can either be an OpenID Connect discovery endpoint or an OAuth 2.0 + * Authorization Server Metadata endpoint defined by RFC 8414. */ private String issuerUri; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java index 54d6c5665d..fe6eff975d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java @@ -82,7 +82,8 @@ public class OAuth2ResourceServerProperties { private String jwsAlgorithm = "RS256"; /** - * URI that an OpenID Connect Provider asserts as its Issuer Identifier. + * URI that can either be an OpenID Connect discovery endpoint or an OAuth 2.0 + * Authorization Server Metadata endpoint defined by RFC 8414. */ private String issuerUri; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java index cf873de272..cda74fae72 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java @@ -48,6 +48,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException; * @author Phillip Webb * @author Madhura Bhave * @author Thiago Hirata + * @author HaiTao Zhang */ class OAuth2ClientPropertiesRegistrationAdapterTests { @@ -209,23 +210,7 @@ class OAuth2ClientPropertiesRegistrationAdapterTests { Registration login = new OAuth2ClientProperties.Registration(); login.setClientId("clientId"); login.setClientSecret("clientSecret"); - testOidcConfiguration(login, "okta"); - } - - @Test - void oidcRfc8414ProviderConfigurationWhenProviderNotSpecifiedOnRegistration() throws Exception { - OAuth2ClientProperties.Registration login = new Registration(); - login.setClientId("clientId"); - login.setClientSecret("clientSecret"); - testOidcRfc8414Configuration(login, "okta"); - } - - @Test - void oAuthProviderConfigurationWhenProviderNotSpecifiedOnRegistration() throws Exception { - OAuth2ClientProperties.Registration login = new Registration(); - login.setClientId("clientId"); - login.setClientSecret("clientSecret"); - testOAuthConfiguration(login, "okta"); + testIssuerConfiguration(login, "okta", 0, 1); } @Test @@ -234,25 +219,23 @@ class OAuth2ClientPropertiesRegistrationAdapterTests { login.setProvider("okta-oidc"); login.setClientId("clientId"); login.setClientSecret("clientSecret"); - testOidcConfiguration(login, "okta-oidc"); + testIssuerConfiguration(login, "okta-oidc", 0, 1); } @Test - void oidcRfc8414ProviderConfigurationWhenProviderSpecifiedOnRegistration() throws Exception { + void issuerUriConfigurationTriesOidcRfc8414UriSecond() throws Exception { OAuth2ClientProperties.Registration login = new Registration(); - login.setProvider("okta-oidcRfc8414"); login.setClientId("clientId"); login.setClientSecret("clientSecret"); - testOidcRfc8414Configuration(login, "okta-oidcRfc8414"); + testIssuerConfiguration(login, "okta", 1, 2); } @Test - void oAuthProviderConfigurationWhenProviderSpecifiedOnRegistration() throws Exception { + void issuerUriConfigurationTriesOAuthMetadataUriThird() throws Exception { OAuth2ClientProperties.Registration login = new Registration(); - login.setProvider("okta-oauth"); login.setClientId("clientId"); login.setClientSecret("clientSecret"); - testOAuthConfiguration(login, "okta-oauth"); + testIssuerConfiguration(login, "okta", 2, 3); } @Test @@ -307,12 +290,12 @@ class OAuth2ClientPropertiesRegistrationAdapterTests { return registration; } - private void testOidcConfiguration(OAuth2ClientProperties.Registration registration, String providerId) - throws Exception { + private void testIssuerConfiguration(OAuth2ClientProperties.Registration registration, String providerId, + int errorResponseCount, int numberOfRequests) throws Exception { this.server = new MockWebServer(); this.server.start(); String issuer = this.server.url("").toString(); - setupMockResponse(issuer); + setupMockResponsesWithErrors(issuer, errorResponseCount); OAuth2ClientProperties properties = new OAuth2ClientProperties(); Provider provider = new Provider(); provider.setIssuerUri(issuer); @@ -334,70 +317,7 @@ class OAuth2ClientPropertiesRegistrationAdapterTests { assertThat(userInfoEndpoint.getUri()).isEqualTo("https://example.com/oauth2/v3/userinfo"); assertThat(userInfoEndpoint.getAuthenticationMethod()) .isEqualTo(org.springframework.security.oauth2.core.AuthenticationMethod.HEADER); - assertThat(this.server.getRequestCount()).isEqualTo(1); - } - - private void testOidcRfc8414Configuration(OAuth2ClientProperties.Registration registration, String providerId) - throws Exception { - this.server = new MockWebServer(); - this.server.start(); - String path = "test"; - String issuer = this.server.url(path).toString(); - setupMockResponseWithEmptyResponses(issuer, 1); - OAuth2ClientProperties properties = new OAuth2ClientProperties(); - Provider provider = new Provider(); - provider.setIssuerUri(issuer); - properties.getProvider().put(providerId, provider); - properties.getRegistration().put("okta", registration); - Map registrations = OAuth2ClientPropertiesRegistrationAdapter - .getClientRegistrations(properties); - ClientRegistration adapted = registrations.get("okta"); - ProviderDetails providerDetails = adapted.getProviderDetails(); - assertThat(adapted.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.BASIC); - assertThat(adapted.getAuthorizationGrantType()).isEqualTo(AuthorizationGrantType.AUTHORIZATION_CODE); - assertThat(adapted.getRegistrationId()).isEqualTo("okta"); - assertThat(adapted.getClientName()).isEqualTo(issuer); - assertThat(adapted.getScopes()).containsOnly("openid"); - assertThat(providerDetails.getAuthorizationUri()).isEqualTo("https://example.com/o/oauth2/v2/auth"); - assertThat(providerDetails.getTokenUri()).isEqualTo("https://example.com/oauth2/v4/token"); - assertThat(providerDetails.getJwkSetUri()).isEqualTo("https://example.com/oauth2/v3/certs"); - UserInfoEndpoint userInfoEndpoint = providerDetails.getUserInfoEndpoint(); - assertThat(userInfoEndpoint.getUri()).isEqualTo("https://example.com/oauth2/v3/userinfo"); - assertThat(userInfoEndpoint.getAuthenticationMethod()) - .isEqualTo(org.springframework.security.oauth2.core.AuthenticationMethod.HEADER); - assertThat(this.server.getRequestCount()).isEqualTo(2); - - } - - private void testOAuthConfiguration(OAuth2ClientProperties.Registration registration, String providerId) - throws Exception { - this.server = new MockWebServer(); - this.server.start(); - String path = "test"; - String issuer = this.server.url(path).toString(); - setupMockResponseWithEmptyResponses(issuer, 2); - OAuth2ClientProperties properties = new OAuth2ClientProperties(); - Provider provider = new Provider(); - provider.setIssuerUri(issuer); - properties.getProvider().put(providerId, provider); - properties.getRegistration().put("okta", registration); - Map registrations = OAuth2ClientPropertiesRegistrationAdapter - .getClientRegistrations(properties); - ClientRegistration adapted = registrations.get("okta"); - ProviderDetails providerDetails = adapted.getProviderDetails(); - assertThat(adapted.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.BASIC); - assertThat(adapted.getAuthorizationGrantType()).isEqualTo(AuthorizationGrantType.AUTHORIZATION_CODE); - assertThat(adapted.getRegistrationId()).isEqualTo("okta"); - assertThat(adapted.getClientName()).isEqualTo(issuer); - assertThat(adapted.getScopes()).containsOnly("openid"); - assertThat(providerDetails.getAuthorizationUri()).isEqualTo("https://example.com/o/oauth2/v2/auth"); - assertThat(providerDetails.getTokenUri()).isEqualTo("https://example.com/oauth2/v4/token"); - assertThat(providerDetails.getJwkSetUri()).isEqualTo("https://example.com/oauth2/v3/certs"); - UserInfoEndpoint userInfoEndpoint = providerDetails.getUserInfoEndpoint(); - assertThat(userInfoEndpoint.getUri()).isEqualTo("https://example.com/oauth2/v3/userinfo"); - assertThat(userInfoEndpoint.getAuthenticationMethod()) - .isEqualTo(org.springframework.security.oauth2.core.AuthenticationMethod.HEADER); - assertThat(this.server.getRequestCount()).isEqualTo(3); + assertThat(this.server.getRequestCount()).isEqualTo(numberOfRequests); } private void setupMockResponse(String issuer) throws JsonProcessingException { @@ -407,9 +327,8 @@ class OAuth2ClientPropertiesRegistrationAdapterTests { this.server.enqueue(mockResponse); } - private void setupMockResponseWithEmptyResponses(String issuer, int amountOfEmptyResponse) - throws JsonProcessingException { - for (int i = 0; i < amountOfEmptyResponse; i++) { + private void setupMockResponsesWithErrors(String issuer, int errorResponseCount) throws JsonProcessingException { + for (int i = 0; i < errorResponseCount; i++) { MockResponse emptyResponse = new MockResponse().setResponseCode(HttpStatus.NOT_FOUND.value()); this.server.enqueue(emptyResponse); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java index 5253e5f879..b63e5eea3d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java @@ -64,6 +64,7 @@ import static org.mockito.Mockito.mock; * * @author Madhura Bhave * @author Artsiom Yudovin + * @author HaiTao Zhang */ class ReactiveOAuth2ResourceServerAutoConfigurationTests { @@ -111,12 +112,11 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests { void autoConfigurationShouldConfigureResourceServerUsingOidcRfc8414IssuerUri() throws Exception { this.server = new MockWebServer(); this.server.start(); - String path = "test"; - String issuer = this.server.url(path).toString(); + String issuer = this.server.url("").toString(); String cleanIssuerPath = cleanIssuerPath(issuer); - setupMockResponseWithEmptyResponses(cleanIssuerPath, 1); + setupMockResponsesWithErrors(cleanIssuerPath, 1); this.contextRunner.withPropertyValues("spring.security.oauth2.resourceserver.jwt.issuer-uri=http://" - + this.server.getHostName() + ":" + this.server.getPort() + "/" + path).run((context) -> { + + this.server.getHostName() + ":" + this.server.getPort()).run((context) -> { assertThat(context).hasSingleBean(NimbusReactiveJwtDecoder.class); assertFilterConfiguredWithJwtAuthenticationManager(context); assertThat(context.containsBean("jwtDecoderByIssuerUri")).isTrue(); @@ -128,12 +128,11 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests { void autoConfigurationShouldConfigureResourceServerUsingOAuthIssuerUri() throws Exception { this.server = new MockWebServer(); this.server.start(); - String path = "test"; - String issuer = this.server.url(path).toString(); + String issuer = this.server.url("").toString(); String cleanIssuerPath = cleanIssuerPath(issuer); - setupMockResponseWithEmptyResponses(cleanIssuerPath, 2); + setupMockResponsesWithErrors(cleanIssuerPath, 2); this.contextRunner.withPropertyValues("spring.security.oauth2.resourceserver.jwt.issuer-uri=http://" - + this.server.getHostName() + ":" + this.server.getPort() + "/" + path).run((context) -> { + + this.server.getHostName() + ":" + this.server.getPort()).run((context) -> { assertThat(context).hasSingleBean(NimbusReactiveJwtDecoder.class); assertFilterConfiguredWithJwtAuthenticationManager(context); assertThat(context.containsBean("jwtDecoderByIssuerUri")).isTrue(); @@ -359,9 +358,8 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests { this.server.enqueue(mockResponse); } - private void setupMockResponseWithEmptyResponses(String issuer, int amountOfEmptyResponse) - throws JsonProcessingException { - for (int i = 0; i < amountOfEmptyResponse; i++) { + private void setupMockResponsesWithErrors(String issuer, int errorResponseCount) throws JsonProcessingException { + for (int i = 0; i < errorResponseCount; i++) { MockResponse emptyResponse = new MockResponse().setResponseCode(HttpStatus.NOT_FOUND.value()); this.server.enqueue(emptyResponse); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java index f62afd6f53..6ab7a67ac5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java @@ -58,6 +58,7 @@ import static org.mockito.Mockito.mock; * * @author Madhura Bhave * @author Artsiom Yudovin + * @author HaiTao Zhang */ class OAuth2ResourceServerAutoConfigurationTests { @@ -133,7 +134,7 @@ class OAuth2ResourceServerAutoConfigurationTests { String path = "test"; String issuer = this.server.url(path).toString(); String cleanIssuerPath = cleanIssuerPath(issuer); - setupMockResponseWithEmptyResponses(cleanIssuerPath, 1); + setupMockResponsesWithErrors(cleanIssuerPath, 1); this.contextRunner.withPropertyValues("spring.security.oauth2.resourceserver.jwt.issuer-uri=http://" + this.server.getHostName() + ":" + this.server.getPort() + "/" + path).run((context) -> { assertThat(context).hasSingleBean(JwtDecoder.class); @@ -149,7 +150,7 @@ class OAuth2ResourceServerAutoConfigurationTests { String path = "test"; String issuer = this.server.url(path).toString(); String cleanIssuerPath = cleanIssuerPath(issuer); - setupMockResponseWithEmptyResponses(cleanIssuerPath, 2); + setupMockResponsesWithErrors(cleanIssuerPath, 2); this.contextRunner.withPropertyValues("spring.security.oauth2.resourceserver.jwt.issuer-uri=http://" + this.server.getHostName() + ":" + this.server.getPort() + "/" + path).run((context) -> { assertThat(context).hasSingleBean(JwtDecoder.class); @@ -340,9 +341,8 @@ class OAuth2ResourceServerAutoConfigurationTests { this.server.enqueue(mockResponse); } - private void setupMockResponseWithEmptyResponses(String issuer, int amountOfEmptyResponse) - throws JsonProcessingException { - for (int i = 0; i < amountOfEmptyResponse; i++) { + private void setupMockResponsesWithErrors(String issuer, int errorResponseCount) throws JsonProcessingException { + for (int i = 0; i < errorResponseCount; i++) { MockResponse emptyResponse = new MockResponse().setResponseCode(HttpStatus.NOT_FOUND.value()); this.server.enqueue(emptyResponse); }