Commit 7054a33e authored by Madhura Bhave's avatar Madhura Bhave

Add support for public key file for OAuth2 resource server

Closes gh-15814
parent cd914aaa
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.security.oauth2.resource;
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.StringUtils;
/**
* Condition for creating a jwt decoder using a public key value.
*
* @author Madhura Bhave
* @since 2.2.0
*/
public class KeyValueCondition extends SpringBootCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
ConditionMessage.Builder message = ConditionMessage
.forCondition("Public Key Value Condition");
Environment environment = context.getEnvironment();
String publicKeyLocation = environment.getProperty(
"spring.security.oauth2.resourceserver.jwt.public-key-location");
if (!StringUtils.hasText(publicKeyLocation)) {
return ConditionOutcome
.noMatch(message.didNotFind("issuer-uri property").atAll());
}
String issuerUri = environment
.getProperty("spring.security.oauth2.resourceserver.jwt.issuer-uri");
String jwkSetUri = environment
.getProperty("spring.security.oauth2.resourceserver.jwt.jwk-set-uri");
if (StringUtils.hasText(jwkSetUri)) {
return ConditionOutcome
.noMatch(message.found("jwk-set-uri property").items(jwkSetUri));
}
if (StringUtils.hasText(issuerUri)) {
return ConditionOutcome
.noMatch(message.found("issuer-uri property").items(issuerUri));
}
return ConditionOutcome
.match(message.foundExactly("public key location property"));
}
}
...@@ -50,6 +50,11 @@ public class OAuth2ResourceServerProperties { ...@@ -50,6 +50,11 @@ public class OAuth2ResourceServerProperties {
*/ */
private String issuerUri; private String issuerUri;
/**
* Location of the file containing the public key used to verify a JWT.
*/
private String publicKeyLocation;
public String getJwkSetUri() { public String getJwkSetUri() {
return this.jwkSetUri; return this.jwkSetUri;
} }
...@@ -74,6 +79,14 @@ public class OAuth2ResourceServerProperties { ...@@ -74,6 +79,14 @@ public class OAuth2ResourceServerProperties {
this.issuerUri = issuerUri; this.issuerUri = issuerUri;
} }
public String getPublicKeyLocation() {
return this.publicKeyLocation;
}
public void setPublicKeyLocation(String publicKeyLocation) {
this.publicKeyLocation = publicKeyLocation;
}
} }
} }
...@@ -15,9 +15,16 @@ ...@@ -15,9 +15,16 @@
*/ */
package org.springframework.boot.autoconfigure.security.oauth2.resource.reactive; package org.springframework.boot.autoconfigure.security.oauth2.resource.reactive;
import java.io.InputStreamReader;
import java.security.KeyFactory;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.security.oauth2.resource.IssuerUriCondition; import org.springframework.boot.autoconfigure.security.oauth2.resource.IssuerUriCondition;
import org.springframework.boot.autoconfigure.security.oauth2.resource.KeyValueCondition;
import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties; import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Conditional;
...@@ -25,9 +32,12 @@ import org.springframework.context.annotation.Configuration; ...@@ -25,9 +32,12 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder; import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder;
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoders; import org.springframework.security.oauth2.jwt.ReactiveJwtDecoders;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.ResourceUtils;
/** /**
* Configures a {@link ReactiveJwtDecoder} when a JWK Set URI is available. * Configures a {@link ReactiveJwtDecoder} when a JWK Set URI, OpenID Connect Issuer URI
* or Public Key configuration is available.
* *
* @author Madhura Bhave * @author Madhura Bhave
* @author Artsiom Yudovin * @author Artsiom Yudovin
...@@ -35,26 +45,42 @@ import org.springframework.security.oauth2.jwt.ReactiveJwtDecoders; ...@@ -35,26 +45,42 @@ import org.springframework.security.oauth2.jwt.ReactiveJwtDecoders;
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
class ReactiveOAuth2ResourceServerJwkConfiguration { class ReactiveOAuth2ResourceServerJwkConfiguration {
private final OAuth2ResourceServerProperties properties; private final OAuth2ResourceServerProperties.Jwt properties;
ReactiveOAuth2ResourceServerJwkConfiguration( ReactiveOAuth2ResourceServerJwkConfiguration(
OAuth2ResourceServerProperties properties) { OAuth2ResourceServerProperties properties) {
this.properties = properties; this.properties = properties.getJwt();
} }
@Bean @Bean
@ConditionalOnProperty(name = "spring.security.oauth2.resourceserver.jwt.jwk-set-uri") @ConditionalOnProperty(name = "spring.security.oauth2.resourceserver.jwt.jwk-set-uri")
@ConditionalOnMissingBean @ConditionalOnMissingBean
public ReactiveJwtDecoder jwtDecoder() { public ReactiveJwtDecoder jwtDecoder() {
return new NimbusReactiveJwtDecoder(this.properties.getJwt().getJwkSetUri()); return new NimbusReactiveJwtDecoder(this.properties.getJwkSetUri());
}
@Bean
@Conditional(KeyValueCondition.class)
@ConditionalOnMissingBean
public NimbusReactiveJwtDecoder jwtDecoderByPublicKeyValue() throws Exception {
String keyValue = FileCopyUtils.copyToString(new InputStreamReader(ResourceUtils
.getURL(this.properties.getPublicKeyLocation()).openStream()));
RSAPublicKey publicKey = (RSAPublicKey) KeyFactory.getInstance("RSA")
.generatePublic(new X509EncodedKeySpec(getKeySpec(keyValue)));
return NimbusReactiveJwtDecoder.withPublicKey(publicKey).build();
}
private byte[] getKeySpec(String keyValue) {
keyValue = keyValue.replace("-----BEGIN PUBLIC KEY-----", "")
.replace("-----END PUBLIC KEY-----", "").replace("\n", "");
return Base64.getDecoder().decode(keyValue);
} }
@Bean @Bean
@Conditional(IssuerUriCondition.class) @Conditional(IssuerUriCondition.class)
@ConditionalOnMissingBean @ConditionalOnMissingBean
public ReactiveJwtDecoder jwtDecoderByIssuerUri() { public ReactiveJwtDecoder jwtDecoderByIssuerUri() {
return ReactiveJwtDecoders return ReactiveJwtDecoders.fromOidcIssuerLocation(this.properties.getIssuerUri());
.fromOidcIssuerLocation(this.properties.getJwt().getIssuerUri());
} }
} }
...@@ -15,20 +15,29 @@ ...@@ -15,20 +15,29 @@
*/ */
package org.springframework.boot.autoconfigure.security.oauth2.resource.servlet; package org.springframework.boot.autoconfigure.security.oauth2.resource.servlet;
import java.io.InputStreamReader;
import java.security.KeyFactory;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.security.oauth2.resource.IssuerUriCondition; import org.springframework.boot.autoconfigure.security.oauth2.resource.IssuerUriCondition;
import org.springframework.boot.autoconfigure.security.oauth2.resource.KeyValueCondition;
import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties; import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.jwt.JwtDecoder; import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtDecoders; import org.springframework.security.oauth2.jwt.JwtDecoders;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoderJwkSupport; import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.ResourceUtils;
/** /**
* Configures a {@link JwtDecoder} when a JWK Set URI or OpenID Connect Issuer URI is * Configures a {@link JwtDecoder} when a JWK Set URI, OpenID Connect Issuer URI or Public
* available. * Key configuration is available.
* *
* @author Madhura Bhave * @author Madhura Bhave
* @author Artsiom Yudovin * @author Artsiom Yudovin
...@@ -46,8 +55,25 @@ class OAuth2ResourceServerJwtConfiguration { ...@@ -46,8 +55,25 @@ class OAuth2ResourceServerJwtConfiguration {
@ConditionalOnProperty(name = "spring.security.oauth2.resourceserver.jwt.jwk-set-uri") @ConditionalOnProperty(name = "spring.security.oauth2.resourceserver.jwt.jwk-set-uri")
@ConditionalOnMissingBean @ConditionalOnMissingBean
public JwtDecoder jwtDecoderByJwkKeySetUri() { public JwtDecoder jwtDecoderByJwkKeySetUri() {
return new NimbusJwtDecoderJwkSupport(this.properties.getJwkSetUri(), return NimbusJwtDecoder.withJwkSetUri(this.properties.getJwkSetUri())
this.properties.getJwsAlgorithm()); .jwsAlgorithm(this.properties.getJwsAlgorithm()).build();
}
@Bean
@Conditional(KeyValueCondition.class)
@ConditionalOnMissingBean
public JwtDecoder jwtDecoderByPublicKeyValue() throws Exception {
String keyValue = FileCopyUtils.copyToString(new InputStreamReader(ResourceUtils
.getURL(this.properties.getPublicKeyLocation()).openStream()));
RSAPublicKey publicKey = (RSAPublicKey) KeyFactory.getInstance("RSA")
.generatePublic(new X509EncodedKeySpec(getKeySpec(keyValue)));
return NimbusJwtDecoder.withPublicKey(publicKey).build();
}
private byte[] getKeySpec(String keyValue) {
keyValue = keyValue.replace("-----BEGIN PUBLIC KEY-----", "")
.replace("-----END PUBLIC KEY-----", "").replace("\n", "");
return Base64.getDecoder().decode(keyValue);
} }
@Bean @Bean
......
...@@ -82,8 +82,7 @@ public class ReactiveOAuth2ResourceServerAutoConfigurationTests { ...@@ -82,8 +82,7 @@ public class ReactiveOAuth2ResourceServerAutoConfigurationTests {
this.contextRunner.withPropertyValues( this.contextRunner.withPropertyValues(
"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com") "spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com")
.run((context) -> { .run((context) -> {
assertThat(context.getBean(ReactiveJwtDecoder.class)) assertThat(context).hasSingleBean(NimbusReactiveJwtDecoder.class);
.isInstanceOf(NimbusReactiveJwtDecoder.class);
assertFilterConfiguredWithJwtAuthenticationManager(context); assertFilterConfiguredWithJwtAuthenticationManager(context);
}); });
} }
...@@ -101,26 +100,54 @@ public class ReactiveOAuth2ResourceServerAutoConfigurationTests { ...@@ -101,26 +100,54 @@ public class ReactiveOAuth2ResourceServerAutoConfigurationTests {
"spring.security.oauth2.resourceserver.jwt.issuer-uri=http://" "spring.security.oauth2.resourceserver.jwt.issuer-uri=http://"
+ this.server.getHostName() + ":" + this.server.getPort()) + this.server.getHostName() + ":" + this.server.getPort())
.run((context) -> { .run((context) -> {
assertThat(context.getBean(ReactiveJwtDecoder.class)) assertThat(context).hasSingleBean(NimbusReactiveJwtDecoder.class);
.isInstanceOf(NimbusReactiveJwtDecoder.class);
assertFilterConfiguredWithJwtAuthenticationManager(context); assertFilterConfiguredWithJwtAuthenticationManager(context);
}); });
} }
@Test @Test
public void autoConfigurationWhenBothSetUriAndIssuerUriPresentShouldUseSetUri() { public void autoConfigurationShouldConfigureResourceServerUsingPublicKeyValue() {
this.contextRunner.withPropertyValues(
"spring.security.oauth2.resourceserver.jwt.public-key-location=classpath:public-key-location")
.run((context) -> {
assertThat(context).hasSingleBean(NimbusReactiveJwtDecoder.class);
assertFilterConfiguredWithJwtAuthenticationManager(context);
});
}
@Test
public void autoConfigurationWhenSetUriKeyLocationIssuerUriPresentShouldUseSetUri() {
this.contextRunner.withPropertyValues( this.contextRunner.withPropertyValues(
"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com", "spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com",
"spring.security.oauth2.resourceserver.jwt.public-key-location=classpath:public-key-location",
"spring.security.oauth2.resourceserver.jwt.issuer-uri=https://jwk-oidc-issuer-location.com") "spring.security.oauth2.resourceserver.jwt.issuer-uri=https://jwk-oidc-issuer-location.com")
.run((context) -> { .run((context) -> {
assertThat(context.getBean(ReactiveJwtDecoder.class)) assertThat(context).hasSingleBean(NimbusReactiveJwtDecoder.class);
.isInstanceOf(NimbusReactiveJwtDecoder.class);
assertFilterConfiguredWithJwtAuthenticationManager(context); assertFilterConfiguredWithJwtAuthenticationManager(context);
assertThat(context.containsBean("jwtDecoder")).isTrue(); assertThat(context.containsBean("jwtDecoder")).isTrue();
assertThat(context.containsBean("jwtDecoderByIssuerUri")).isFalse(); assertThat(context.containsBean("jwtDecoderByIssuerUri")).isFalse();
}); });
} }
@Test
public void autoConfigurationWhenKeyLocationAndIssuerUriPresentShouldUseIssuerUri()
throws Exception {
this.server = new MockWebServer();
this.server.start();
String issuer = this.server.url("").toString();
String cleanIssuerPath = cleanIssuerPath(issuer);
setupMockResponse(cleanIssuerPath);
this.contextRunner.withPropertyValues(
"spring.security.oauth2.resourceserver.jwt.issuer-uri=http://"
+ this.server.getHostName() + ":" + this.server.getPort(),
"spring.security.oauth2.resourceserver.jwt.public-key-location=classpath:public-key-location")
.run((context) -> {
assertThat(context).hasSingleBean(NimbusReactiveJwtDecoder.class);
assertFilterConfiguredWithJwtAuthenticationManager(context);
assertThat(context.containsBean("jwtDecoderByIssuerUri")).isTrue();
});
}
@Test @Test
public void autoConfigurationWhenJwkSetUriNullShouldNotFail() { public void autoConfigurationWhenJwkSetUriNullShouldNotFail() {
this.contextRunner.run((context) -> assertThat(context) this.contextRunner.run((context) -> assertThat(context)
......
...@@ -42,11 +42,11 @@ import org.springframework.http.MediaType; ...@@ -42,11 +42,11 @@ import org.springframework.http.MediaType;
import org.springframework.security.config.BeanIds; import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.jwt.JwtDecoder; import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoderJwkSupport;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter; import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter;
import org.springframework.security.web.FilterChainProxy; import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.SecurityFilterChain;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
...@@ -78,8 +78,7 @@ public class OAuth2ResourceServerAutoConfigurationTests { ...@@ -78,8 +78,7 @@ public class OAuth2ResourceServerAutoConfigurationTests {
this.contextRunner.withPropertyValues( this.contextRunner.withPropertyValues(
"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com") "spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com")
.run((context) -> { .run((context) -> {
assertThat(context.getBean(JwtDecoder.class)) assertThat(context).hasSingleBean(JwtDecoder.class);
.isInstanceOf(NimbusJwtDecoderJwkSupport.class);
assertThat(getBearerTokenFilter(context)).isNotNull(); assertThat(getBearerTokenFilter(context)).isNotNull();
}); });
} }
...@@ -90,7 +89,11 @@ public class OAuth2ResourceServerAutoConfigurationTests { ...@@ -90,7 +89,11 @@ public class OAuth2ResourceServerAutoConfigurationTests {
"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com") "spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com")
.run((context) -> { .run((context) -> {
JwtDecoder jwtDecoder = context.getBean(JwtDecoder.class); JwtDecoder jwtDecoder = context.getBean(JwtDecoder.class);
assertThat(jwtDecoder).hasFieldOrPropertyWithValue("jwsAlgorithm", Object processor = ReflectionTestUtils.getField(jwtDecoder,
"jwtProcessor");
Object keySelector = ReflectionTestUtils.getField(processor,
"jwsKeySelector");
assertThat(keySelector).hasFieldOrPropertyWithValue("jwsAlg",
JWSAlgorithm.RS256); JWSAlgorithm.RS256);
}); });
} }
...@@ -102,7 +105,11 @@ public class OAuth2ResourceServerAutoConfigurationTests { ...@@ -102,7 +105,11 @@ public class OAuth2ResourceServerAutoConfigurationTests {
"spring.security.oauth2.resourceserver.jwt.jws-algorithm=HS512") "spring.security.oauth2.resourceserver.jwt.jws-algorithm=HS512")
.run((context) -> { .run((context) -> {
JwtDecoder jwtDecoder = context.getBean(JwtDecoder.class); JwtDecoder jwtDecoder = context.getBean(JwtDecoder.class);
assertThat(jwtDecoder).hasFieldOrPropertyWithValue("jwsAlgorithm", Object processor = ReflectionTestUtils.getField(jwtDecoder,
"jwtProcessor");
Object keySelector = ReflectionTestUtils.getField(processor,
"jwsKeySelector");
assertThat(keySelector).hasFieldOrPropertyWithValue("jwsAlg",
JWSAlgorithm.HS512); JWSAlgorithm.HS512);
assertThat(getBearerTokenFilter(context)).isNotNull(); assertThat(getBearerTokenFilter(context)).isNotNull();
}); });
...@@ -121,24 +128,57 @@ public class OAuth2ResourceServerAutoConfigurationTests { ...@@ -121,24 +128,57 @@ public class OAuth2ResourceServerAutoConfigurationTests {
"spring.security.oauth2.resourceserver.jwt.issuer-uri=http://" "spring.security.oauth2.resourceserver.jwt.issuer-uri=http://"
+ this.server.getHostName() + ":" + this.server.getPort()) + this.server.getHostName() + ":" + this.server.getPort())
.run((context) -> { .run((context) -> {
assertThat(context.getBean(JwtDecoder.class)) assertThat(context).hasSingleBean(JwtDecoder.class);
.isInstanceOf(NimbusJwtDecoderJwkSupport.class);
assertThat(getBearerTokenFilter(context)).isNotNull(); assertThat(getBearerTokenFilter(context)).isNotNull();
}); });
} }
@Test @Test
public void autoConfigurationWhenBothSetUriAndIssuerUriPresentShouldUseSetUri() { public void autoConfigurationShouldConfigureResourceServerUsingPublicKeyValue()
throws Exception {
this.server = new MockWebServer();
this.server.start();
String issuer = this.server.url("").toString();
String cleanIssuerPath = cleanIssuerPath(issuer);
setupMockResponse(cleanIssuerPath);
this.contextRunner.withPropertyValues(
"spring.security.oauth2.resourceserver.jwt.public-key-location=classpath:public-key-location")
.run((context) -> {
assertThat(context).hasSingleBean(JwtDecoder.class);
assertThat(getBearerTokenFilter(context)).isNotNull();
});
}
@Test
public void autoConfigurationWhenSetUriKeyLocationAndIssuerUriPresentShouldUseSetUri() {
this.contextRunner.withPropertyValues( this.contextRunner.withPropertyValues(
"spring.security.oauth2.resourceserver.jwt.issuer-uri=https://issuer-uri.com", "spring.security.oauth2.resourceserver.jwt.issuer-uri=https://issuer-uri.com",
"spring.security.oauth2.resourceserver.jwt.public-key-location=classpath:public-key-location",
"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com") "spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com")
.run((context) -> { .run((context) -> {
assertThat(context.getBean(JwtDecoder.class)) assertThat(context).hasSingleBean(JwtDecoder.class);
.isInstanceOf(NimbusJwtDecoderJwkSupport.class);
assertThat(getBearerTokenFilter(context)).isNotNull(); assertThat(getBearerTokenFilter(context)).isNotNull();
assertThat(context.containsBean("jwtDecoderByJwkKeySetUri")).isTrue(); assertThat(context.containsBean("jwtDecoderByJwkKeySetUri")).isTrue();
assertThat(context.containsBean("jwtDecoderByOidcIssuerUri")) assertThat(context.containsBean("jwtDecoderByIssuerUri")).isFalse();
.isFalse(); });
}
@Test
public void autoConfigurationWhenKeyLocationAndIssuerUriPresentShouldUseIssuerUri()
throws Exception {
this.server = new MockWebServer();
this.server.start();
String issuer = this.server.url("").toString();
String cleanIssuerPath = cleanIssuerPath(issuer);
setupMockResponse(cleanIssuerPath);
this.contextRunner.withPropertyValues(
"spring.security.oauth2.resourceserver.jwt.issuer-uri=http://"
+ this.server.getHostName() + ":" + this.server.getPort(),
"spring.security.oauth2.resourceserver.jwt.public-key-location=classpath:public-key-location")
.run((context) -> {
assertThat(context).hasSingleBean(JwtDecoder.class);
assertThat(getBearerTokenFilter(context)).isNotNull();
assertThat(context.containsBean("jwtDecoderByIssuerUri")).isTrue();
}); });
} }
......
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdlatRjRjogo3WojgGHFHYLugd
UWAY9iR3fy4arWNA1KoS8kVw33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQs
HUfQrSDv+MuSUMAe8jzKE4qW+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5D
o2kQ+X5xK9cipRgEKwIDAQAB
-----END PUBLIC KEY-----
\ No newline at end of file
...@@ -190,7 +190,7 @@ ...@@ -190,7 +190,7 @@
<spring-plugin.version>2.0.0.M1</spring-plugin.version> <spring-plugin.version>2.0.0.M1</spring-plugin.version>
<spring-restdocs.version>2.0.3.RELEASE</spring-restdocs.version> <spring-restdocs.version>2.0.3.RELEASE</spring-restdocs.version>
<spring-retry.version>1.2.4.RELEASE</spring-retry.version> <spring-retry.version>1.2.4.RELEASE</spring-retry.version>
<spring-security.version>5.1.5.RELEASE</spring-security.version> <spring-security.version>5.2.0.BUILD-SNAPSHOT</spring-security.version>
<spring-session-bom.version>Bean-SR4</spring-session-bom.version> <spring-session-bom.version>Bean-SR4</spring-session-bom.version>
<spring-ws.version>3.0.7.RELEASE</spring-ws.version> <spring-ws.version>3.0.7.RELEASE</spring-ws.version>
<sqlite-jdbc.version>3.27.2</sqlite-jdbc.version> <sqlite-jdbc.version>3.27.2</sqlite-jdbc.version>
......
...@@ -3657,6 +3657,12 @@ as shown in the following examples: ...@@ -3657,6 +3657,12 @@ as shown in the following examples:
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://dev-123456.oktapreview.com/oauth2/default/ spring.security.oauth2.resourceserver.jwt.issuer-uri=https://dev-123456.oktapreview.com/oauth2/default/
---- ----
NOTE: If the authorization server does not support a JWK Set URI, you can configure the
resource server with the Public Key used for verifying the signature of the JWT. This can
be done using the `spring.security.oauth2.resourceserver.jwt.public-key-location` property,
where the value needs to point to a file containing the public key in the PEM-encoded x509
format.
The same properties are applicable for both servlet and reactive applications. The same properties are applicable for both servlet and reactive applications.
Alternatively, you can define your own `JwtDecoder` bean for servlet applications Alternatively, you can define your own `JwtDecoder` bean for servlet applications
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment