Support RFC 8414 in JwtDecoders and ClientRegistrations

See gh-17761
pull/17776/head
HaiTao Zhang 5 years ago committed by Madhura Bhave
parent f7f858bce8
commit 8baec96453

@ -80,7 +80,7 @@ public final class OAuth2ClientPropertiesRegistrationAdapter {
Provider provider = providers.get(providerId);
String issuer = provider.getIssuerUri();
if (issuer != null) {
Builder builder = ClientRegistrations.fromOidcIssuerLocation(issuer).registrationId(registrationId);
Builder builder = ClientRegistrations.fromIssuerLocation(issuer).registrationId(registrationId);
return getBuilder(builder, provider);
}
}

@ -79,7 +79,7 @@ class ReactiveOAuth2ResourceServerJwkConfiguration {
@Bean
@Conditional(IssuerUriCondition.class)
ReactiveJwtDecoder jwtDecoderByIssuerUri() {
return ReactiveJwtDecoders.fromOidcIssuerLocation(this.properties.getIssuerUri());
return ReactiveJwtDecoders.fromIssuerLocation(this.properties.getIssuerUri());
}
}

@ -81,7 +81,7 @@ class OAuth2ResourceServerJwtConfiguration {
@Bean
@Conditional(IssuerUriCondition.class)
JwtDecoder jwtDecoderByIssuerUri() {
return JwtDecoders.fromOidcIssuerLocation(this.properties.getIssuerUri());
return JwtDecoders.fromIssuerLocation(this.properties.getIssuerUri());
}
}

@ -212,6 +212,22 @@ class OAuth2ClientPropertiesRegistrationAdapterTests {
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");
}
@Test
void oidcProviderConfigurationWhenProviderSpecifiedOnRegistration() throws Exception {
OAuth2ClientProperties.Registration login = new Registration();
@ -221,6 +237,24 @@ class OAuth2ClientPropertiesRegistrationAdapterTests {
testOidcConfiguration(login, "okta-oidc");
}
@Test
void oidcRfc8414ProviderConfigurationWhenProviderSpecifiedOnRegistration() throws Exception {
OAuth2ClientProperties.Registration login = new Registration();
login.setProvider("okta-oidcRfc8414");
login.setClientId("clientId");
login.setClientSecret("clientSecret");
testOidcRfc8414Configuration(login, "okta-oidcRfc8414");
}
@Test
void oAuthProviderConfigurationWhenProviderSpecifiedOnRegistration() throws Exception {
OAuth2ClientProperties.Registration login = new Registration();
login.setProvider("okta-oauth");
login.setClientId("clientId");
login.setClientSecret("clientSecret");
testOAuthConfiguration(login, "okta-oauth");
}
@Test
void oidcProviderConfigurationWithCustomConfigurationOverridesProviderDefaults() throws Exception {
this.server = new MockWebServer();
@ -300,6 +334,70 @@ 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<String, ClientRegistration> 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<String, ClientRegistration> 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);
}
private void setupMockResponse(String issuer) throws JsonProcessingException {
@ -309,6 +407,15 @@ class OAuth2ClientPropertiesRegistrationAdapterTests {
this.server.enqueue(mockResponse);
}
private void setupMockResponseWithEmptyResponses(String issuer, int amountOfEmptyResponse)
throws JsonProcessingException {
for (int i = 0; i < amountOfEmptyResponse; i++) {
MockResponse emptyResponse = new MockResponse().setResponseCode(HttpStatus.NOT_FOUND.value());
this.server.enqueue(emptyResponse);
}
setupMockResponse(issuer);
}
private Map<String, Object> getResponse(String issuer) {
Map<String, Object> response = new HashMap<>();
response.put("authorization_endpoint", "https://example.com/o/oauth2/v2/auth");

@ -94,14 +94,51 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests {
void autoConfigurationShouldConfigureResourceServerUsingOidcIssuerUri() throws IOException {
this.server = new MockWebServer();
this.server.start();
String issuer = this.server.url("").toString();
String path = "test";
String issuer = this.server.url(path).toString();
String cleanIssuerPath = cleanIssuerPath(issuer);
setupMockResponse(cleanIssuerPath);
this.contextRunner.withPropertyValues("spring.security.oauth2.resourceserver.jwt.issuer-uri=http://"
+ this.server.getHostName() + ":" + this.server.getPort()).run((context) -> {
+ this.server.getHostName() + ":" + this.server.getPort() + "/" + path).run((context) -> {
assertThat(context).hasSingleBean(NimbusReactiveJwtDecoder.class);
assertFilterConfiguredWithJwtAuthenticationManager(context);
assertThat(context.containsBean("jwtDecoderByIssuerUri")).isTrue();
});
assertThat(this.server.getRequestCount()).isEqualTo(1);
}
@Test
void autoConfigurationShouldConfigureResourceServerUsingOidcRfc8414IssuerUri() throws Exception {
this.server = new MockWebServer();
this.server.start();
String path = "test";
String issuer = this.server.url(path).toString();
String cleanIssuerPath = cleanIssuerPath(issuer);
setupMockResponseWithEmptyResponses(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(NimbusReactiveJwtDecoder.class);
assertFilterConfiguredWithJwtAuthenticationManager(context);
assertThat(context.containsBean("jwtDecoderByIssuerUri")).isTrue();
});
assertThat(this.server.getRequestCount()).isEqualTo(2);
}
@Test
void autoConfigurationShouldConfigureResourceServerUsingOAuthIssuerUri() throws Exception {
this.server = new MockWebServer();
this.server.start();
String path = "test";
String issuer = this.server.url(path).toString();
String cleanIssuerPath = cleanIssuerPath(issuer);
setupMockResponseWithEmptyResponses(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(NimbusReactiveJwtDecoder.class);
assertFilterConfiguredWithJwtAuthenticationManager(context);
assertThat(context.containsBean("jwtDecoderByIssuerUri")).isTrue();
});
assertThat(this.server.getRequestCount()).isEqualTo(3);
}
@Test
@ -322,6 +359,15 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests {
this.server.enqueue(mockResponse);
}
private void setupMockResponseWithEmptyResponses(String issuer, int amountOfEmptyResponse)
throws JsonProcessingException {
for (int i = 0; i < amountOfEmptyResponse; i++) {
MockResponse emptyResponse = new MockResponse().setResponseCode(HttpStatus.NOT_FOUND.value());
this.server.enqueue(emptyResponse);
}
setupMockResponse(issuer);
}
private Map<String, Object> getResponse(String issuer) {
Map<String, Object> response = new HashMap<>();
response.put("authorization_endpoint", "https://example.com/o/oauth2/v2/auth");

@ -114,14 +114,48 @@ class OAuth2ResourceServerAutoConfigurationTests {
void autoConfigurationShouldConfigureResourceServerUsingOidcIssuerUri() throws Exception {
this.server = new MockWebServer();
this.server.start();
String issuer = this.server.url("").toString();
String path = "test";
String issuer = this.server.url(path).toString();
String cleanIssuerPath = cleanIssuerPath(issuer);
setupMockResponse(cleanIssuerPath);
this.contextRunner.withPropertyValues("spring.security.oauth2.resourceserver.jwt.issuer-uri=http://"
+ this.server.getHostName() + ":" + this.server.getPort()).run((context) -> {
+ this.server.getHostName() + ":" + this.server.getPort() + "/" + path).run((context) -> {
assertThat(context).hasSingleBean(JwtDecoder.class);
assertThat(getBearerTokenFilter(context)).isNotNull();
assertThat(context.containsBean("jwtDecoderByIssuerUri")).isTrue();
});
assertThat(this.server.getRequestCount()).isEqualTo(1);
}
@Test
void autoConfigurationShouldConfigureResourceServerUsingOidcRfc8414IssuerUri() throws Exception {
this.server = new MockWebServer();
this.server.start();
String path = "test";
String issuer = this.server.url(path).toString();
String cleanIssuerPath = cleanIssuerPath(issuer);
setupMockResponseWithEmptyResponses(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);
assertThat(context.containsBean("jwtDecoderByIssuerUri")).isTrue();
});
assertThat(this.server.getRequestCount()).isEqualTo(2);
}
@Test
void autoConfigurationShouldConfigureResourceServerUsingOAuthIssuerUri() throws Exception {
this.server = new MockWebServer();
this.server.start();
String path = "test";
String issuer = this.server.url(path).toString();
String cleanIssuerPath = cleanIssuerPath(issuer);
setupMockResponseWithEmptyResponses(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);
assertThat(context.containsBean("jwtDecoderByIssuerUri")).isTrue();
});
assertThat(this.server.getRequestCount()).isEqualTo(3);
}
@Test
@ -306,6 +340,15 @@ class OAuth2ResourceServerAutoConfigurationTests {
this.server.enqueue(mockResponse);
}
private void setupMockResponseWithEmptyResponses(String issuer, int amountOfEmptyResponse)
throws JsonProcessingException {
for (int i = 0; i < amountOfEmptyResponse; i++) {
MockResponse emptyResponse = new MockResponse().setResponseCode(HttpStatus.NOT_FOUND.value());
this.server.enqueue(emptyResponse);
}
setupMockResponse(issuer);
}
private Map<String, Object> getResponse(String issuer) {
Map<String, Object> response = new HashMap<>();
response.put("authorization_endpoint", "https://example.com/o/oauth2/v2/auth");

Loading…
Cancel
Save