diff --git a/build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/run.adoc b/build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/run.adoc index b06bf52fd78d..aa2eeb4b6a8c 100644 --- a/build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/run.adoc +++ b/build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/run.adoc @@ -26,8 +26,6 @@ include::example$running/devtools-pom.xml[tags=devtools] When `devtools` is running, it detects changes when you recompile your application and automatically refreshes it. This works for not only resources but code as well. -It also provides a LiveReload server so that it can automatically trigger a browser refresh whenever things change. - Devtools can also be configured to only refresh the browser whenever a static resource has changed (and ignore any change in the code). Just include the following property in your project: diff --git a/core/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/ApplicationContextAssert.java b/core/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/ApplicationContextAssert.java index 4b3880e56831..74daba04d384 100644 --- a/core/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/ApplicationContextAssert.java +++ b/core/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/ApplicationContextAssert.java @@ -251,7 +251,7 @@ public AbstractObjectArrayAssert getBeanNames(Class type) { * given type */ @CheckReturnValue - public AbstractObjectAssert getBean(Class type) { + public AbstractObjectAssert getBean(Class type) { return getBean(type, Scope.INCLUDE_ANCESTORS); } @@ -273,7 +273,7 @@ public AbstractObjectAssert getBean(Class type) { * given type */ @CheckReturnValue - public AbstractObjectAssert getBean(Class type, Scope scope) { + public AbstractObjectAssert getBean(Class type, Scope scope) { Assert.notNull(scope, "'scope' must not be null"); if (this.startupFailure != null) { throwAssertionError( @@ -334,7 +334,7 @@ private boolean isPrimary(String name, Scope scope) { * @throws AssertionError if the application context did not start */ @CheckReturnValue - public AbstractObjectAssert getBean(String name) { + public AbstractObjectAssert getBean(String name) { if (this.startupFailure != null) { throwAssertionError( contextFailedToStartWhenExpecting(this.startupFailure, "to contain a bean of name:%n <%s>", name)); @@ -362,7 +362,7 @@ public AbstractObjectAssert getBean(String name) { */ @SuppressWarnings("unchecked") @CheckReturnValue - public AbstractObjectAssert getBean(String name, Class type) { + public AbstractObjectAssert getBean(String name, Class type) { if (this.startupFailure != null) { throwAssertionError(contextFailedToStartWhenExpecting(this.startupFailure, "to contain a bean of name:%n <%s> (%s)", name, type)); diff --git a/documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/info/InfoEndpointDocumentationTests.java b/documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/info/InfoEndpointDocumentationTests.java index 1b517c02b2ce..d71ca9b0b059 100644 --- a/documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/info/InfoEndpointDocumentationTests.java +++ b/documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/info/InfoEndpointDocumentationTests.java @@ -131,7 +131,7 @@ private ResponseFieldsSnippet processInfo() { fieldWithPath("memory.nonHeap.max") .description("Maximum number of bytes that can be used by the JVM (or -1)."), fieldWithPath("memory.garbageCollectors").description("Details for garbage collectors."), - fieldWithPath("memory.garbageCollectors[].name").description("Name of of the garbage collector."), + fieldWithPath("memory.garbageCollectors[].name").description("Name of the garbage collector."), fieldWithPath("memory.garbageCollectors[].collectionCount") .description("Total number of collections that have occurred."), fieldWithPath("virtualThreads") diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/deployment/cloud.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/deployment/cloud.adoc index b6b093a5ecfc..7189b7382d33 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/deployment/cloud.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/deployment/cloud.adoc @@ -24,7 +24,7 @@ In this section, we look at what it takes to get the xref:tutorial:first-applica Support for xref:how-to:webserver.adoc#howto.webserver.use-behind-a-proxy-server[forwarded headers] should only be enabled when the application receives traffic from a trusted HTTP proxy, and is only directly accessible from a trusted network. When running on a cloud platform, forward headers are enabled automatically. This builds on the assumption that the platform will ensure that individual application instances will only be directly accessible from a trusted network. -If that is not the case for your specific platform, set `spring.forward-headers-strategy` to `none`. +If that is not the case for your specific platform, set configprop:server.forward-headers-strategy[] to `none`. [[howto.deployment.cloud.cloud-foundry]] diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/hotswapping.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/hotswapping.adoc index 906e32e2ccb0..ce2e7437e39f 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/hotswapping.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/hotswapping.adoc @@ -10,14 +10,12 @@ This section answers questions about how it works. == Reload Static Content There are several options for hot reloading. -The recommended approach is to use xref:reference:using/devtools.adoc[`spring-boot-devtools`], as it provides additional development-time features, such as support for fast application restarts and LiveReload as well as sensible development-time configuration (such as template caching). +The recommended approach is to use xref:reference:using/devtools.adoc[`spring-boot-devtools`], as it provides additional development-time features, such as support for fast application restarts as well as sensible development-time configuration (such as template caching). Devtools works by monitoring the classpath for changes. This means that static resource changes must be "built" for the change to take effect. By default, this happens automatically in Eclipse when you save your changes. In IntelliJ IDEA, the Make Project command triggers the necessary build. Due to the xref:reference:using/devtools.adoc#using.devtools.restart.excluding-resources[default restart exclusions], changes to static resources do not trigger a restart of your application. -They do, however, trigger a live reload. - Alternatively, running in an IDE (especially with debugging on) is a good way to do development (all modern IDEs allow reloading of static resources and usually also allow hot-swapping of Java class changes). Finally, the xref:build-tool-plugin:index.adoc[Maven and Gradle plugins] can be configured (see the `addResources` property) to support running from the command line with reloading of static files directly from source. diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/data/sql.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/data/sql.adoc index fa8a38f48cf2..4b87a7e1ea40 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/data/sql.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/data/sql.adoc @@ -274,7 +274,7 @@ include-code::CityRepository[] Spring Data JPA repositories support three different modes of bootstrapping: default, deferred, and lazy. To enable deferred or lazy bootstrapping, set the configprop:spring.data.jpa.repositories.bootstrap-mode[] property to `deferred` or `lazy` respectively. -When using deferred or lazy bootstrapping, the auto-configured javadoc:org.springframework.boot.jpa.EntityManagerFactoryBuilder[] will use the context's javadoc:org.springframework.core.task.AsyncTaskExecutor[], if any, as the bootstrap executor. +When using deferred bootstrapping, the auto-configured javadoc:org.springframework.boot.jpa.EntityManagerFactoryBuilder[] requires a bootstrap executor and will use the context's javadoc:org.springframework.core.task.AsyncTaskExecutor[], if one can be determined. If more than one exists, the one named `applicationTaskExecutor` will be used. [NOTE] diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/dev-services.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/dev-services.adoc index f18d9d9f9dec..f06dee89a7a4 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/dev-services.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/dev-services.adoc @@ -129,7 +129,7 @@ The following service connections are currently supported: | Containers named "rabbitmq" with container port 5672 mapped | javadoc:org.springframework.boot.amqp.autoconfigure.RabbitStreamConnectionDetails[] -| Containers named "rabbitmq" with container port 5552 mapped +| Containers named "rabbitmq" with container port 5552 mapped, or port 5551 mapped when SSL is configured | javadoc:org.springframework.boot.data.redis.autoconfigure.DataRedisConnectionDetails[] | Containers named "redis", "redis/redis-stack" or "redis/redis-stack-server" diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/external-config.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/external-config.adoc index 38d348e788c7..9ce3d49f2430 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/external-config.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/external-config.adoc @@ -874,7 +874,7 @@ This will happen automatically if you use Spring Boot's Gradle plugin or if you NOTE: The use of javadoc:java.util.Optional[] with javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] is not recommended as it is primarily intended for use as a return type. As such, it is not well-suited to configuration property injection. -For consistency with properties of other types, if you do declare an javadoc:java.util.Optional[] property and it has no value, `null` rather than an empty javadoc:java.util.Optional[] will be bound. +If you do declare an javadoc:java.util.Optional[] constructor-bound property and it has no value, an empty javadoc:java.util.Optional[] will be bound. TIP: To use a reserved keyword in the name of a property, such as `my.service.import`, use the javadoc:org.springframework.boot.context.properties.bind.Name[format=annotation] annotation on the constructor parameter. diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc index 53760e83f542..64676c943345 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc @@ -215,7 +215,7 @@ As a result, specific configuration keys (such as `logback.configurationFile` fo [[features.logging.file-rotation]] == File Rotation -If you are using Logback of Log4J2, it is possible to fine-tune log rotation settings using your `application.properties` or `application.yaml` file. +If you are using Logback or Log4j2, it is possible to fine-tune log rotation settings using your `application.properties` or `application.yaml` file. For all other logging system, you will need to configure rotation settings directly yourself. The following rotation policy properties are supported for Logback: diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/io/grpc.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/io/grpc.adoc index 1289ead94743..6cc9cc9f0f44 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/io/grpc.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/io/grpc.adoc @@ -59,7 +59,7 @@ Spring Boot supports for both Maven and Gradle protobuf plugins, but you are fre ==== Using the Maven Plugin Spring Boot include dependency management for the `io.github.ascopes:protobuf-maven-plugin` Maven plugin. -If you are using the the `spring-boot-starter-parent` POM, you'll also get sensible out-of-the-box configuration. +If you are using the `spring-boot-starter-parent` POM, you'll also get sensible out-of-the-box configuration. The following shows a typical Maven POM file that uses the plugin: diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/security/oauth2.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/security/oauth2.adoc index 143238d79443..524af65add5e 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/security/oauth2.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/security/oauth2.adoc @@ -124,8 +124,8 @@ For production environments, consider using a javadoc:org.springframework.securi [[security.oauth2.client.common-providers]] === OAuth2 Client Registration for Common Providers -For common OAuth2 and OpenID providers (Google, Github, Facebook, and Okta), we provide a set of provider defaults. -The IDs of these common providers are `google`, `github`, `facebook`, and `okta`, respectively. +For common OAuth2 and OpenID providers (Google, Github, Facebook, X, and Okta), we provide a set of provider defaults. +The IDs of these common providers are `google`, `github`, `facebook`, `x`, and `okta`, respectively. If you do not need to customize these providers, set the registration's `provider` property to the ID of one of the common providers. Alternatively, you can xref:security/oauth2.adoc#security.oauth2.client[use a registration ID that matches the ID of the provider]. diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/spring-boot-applications.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/spring-boot-applications.adoc index 361e9eec4d4d..f5307e6757f6 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/spring-boot-applications.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/spring-boot-applications.adoc @@ -740,11 +740,11 @@ TIP: A list of the auto-configuration settings that are enabled by javadoc:org.s The specific beans that you want to test should be specified by using the `value` or `components` attribute of javadoc:org.springframework.boot.restclient.test.autoconfigure.RestClientTest[format=annotation]. -When using a javadoc:org.springframework.boot.restclient.RestTemplateBuilder[] in the beans under test and `RestTemplateBuilder.rootUri(String rootUri)` has been called when building the javadoc:org.springframework.web.client.RestTemplate[], then the root URI should be omitted from the javadoc:org.springframework.test.web.client.MockRestServiceServer[] expectations as shown in the following example: +When using a javadoc:org.springframework.boot.restclient.RestTemplateBuilder[] in the beans under test and `RestTemplateBuilder.baseUri(String baseUri)` has been called when building the javadoc:org.springframework.web.client.RestTemplate[], then the base URI should be omitted from the javadoc:org.springframework.test.web.client.MockRestServiceServer[] expectations as shown in the following example: include-code::MyRestTemplateServiceTests[] -When using a javadoc:org.springframework.web.client.RestClient$Builder[] in the beans under test, or when using a javadoc:org.springframework.boot.restclient.RestTemplateBuilder[] without calling `rootUri(String rootURI)`, the full URI must be used in the javadoc:org.springframework.test.web.client.MockRestServiceServer[] expectations as shown in the following example: +When using a javadoc:org.springframework.web.client.RestClient$Builder[] in the beans under test, or when using a javadoc:org.springframework.boot.restclient.RestTemplateBuilder[] without calling `baseUri(String baseUri)`, the full URI must be used in the javadoc:org.springframework.test.web.client.MockRestServiceServer[] expectations as shown in the following example: include-code::MyRestClientServiceTests[] diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc index cd517fe18e3c..92bde635fa73 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc @@ -200,7 +200,7 @@ For example, a javadoc:{url-testcontainers-postgresql-javadoc}/org.testcontainer If you want to create only a subset of the applicable types, you can use the `type` attribute of javadoc:org.springframework.boot.testcontainers.service.connection.ServiceConnection[format=annotation]. To create a javadoc:org.springframework.boot.amqp.autoconfigure.RabbitStreamConnectionDetails[] bean from a javadoc:{url-testcontainers-rabbitmq-javadoc}/org.testcontainers.rabbitmq.RabbitMQContainer[], you must opt in using the `type` attribute of javadoc:org.springframework.boot.testcontainers.service.connection.ServiceConnection[format=annotation]. -The container must also expose port 5552, the RabbitMQ streams port. +The container must also expose port 5552, or port 5551 when SSL is configured, for RabbitMQ Streams. ==== By default `Container.getDockerImageName().getRepository()` is used to obtain the name used to find connection details. diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/web/index.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/web/index.adoc index 4e0dc5592c06..552c321215a5 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/web/index.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/web/index.adoc @@ -3,7 +3,7 @@ Spring Boot is well suited for web application development. You can create a self-contained HTTP server by using embedded Tomcat, Jetty, or Netty. -Most web applications use the `spring-boot-starter-web` module to get up and running quickly. +Most web applications use the `spring-boot-starter-webmvc` module to get up and running quickly. You can also choose to build reactive web applications by using the `spring-boot-starter-webflux` module. If you have not yet developed a Spring Boot web application, you can follow the "`Hello World!`" example in the xref:tutorial:first-application/index.adoc[Getting started] section. diff --git a/gradle.properties b/gradle.properties index add296dbf695..d3bf60e1a97b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,7 +19,7 @@ kotlinVersion=2.3.21 mavenVersion=3.9.13 mockitoVersion=5.23.0 nativeBuildToolsVersion=1.1.1 -nullabilityPluginVersion=0.0.11 +nullabilityPluginVersion=0.0.14 snakeYamlVersion=2.6 springGrpcVersion=1.1.0 springFrameworkVersion=7.0.8 diff --git a/module/spring-boot-security-oauth2-client/src/main/java/org/springframework/boot/security/oauth2/client/autoconfigure/OAuth2ClientProperties.java b/module/spring-boot-security-oauth2-client/src/main/java/org/springframework/boot/security/oauth2/client/autoconfigure/OAuth2ClientProperties.java index c87a49c033d6..f57b8a81f74c 100644 --- a/module/spring-boot-security-oauth2-client/src/main/java/org/springframework/boot/security/oauth2/client/autoconfigure/OAuth2ClientProperties.java +++ b/module/spring-boot-security-oauth2-client/src/main/java/org/springframework/boot/security/oauth2/client/autoconfigure/OAuth2ClientProperties.java @@ -79,7 +79,7 @@ public static class Registration { /** * Reference to the OAuth 2.0 provider to use. May reference one of the common - * providers (google, github, facebook, okta) or the ID of a custom provider + * providers (google, github, facebook, x, okta) or the ID of a custom provider * configured using 'spring.security.oauth2.client.provider.<id>.*' * properties. When not set, the ID of this registration is used to identify the * provider. diff --git a/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/ConditionalOnJwkSetUriJwtDecoder.java b/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/ConditionalOnJwkSetUriJwtDecoder.java new file mode 100644 index 000000000000..c6793b353de5 --- /dev/null +++ b/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/ConditionalOnJwkSetUriJwtDecoder.java @@ -0,0 +1,42 @@ +/* + * Copyright 2012-present 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.security.oauth2.server.resource.autoconfigure; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.context.annotation.Conditional; +import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; +import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder; + +/** + * Condition that matches when a JWK Set URI based {@link NimbusJwtDecoder} or + * {@link NimbusReactiveJwtDecoder} should be used. + * + * @author Andy Wilkinson + * @since 4.0.8 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Documented +@Conditional(JwkSetUriCondition.class) +public @interface ConditionalOnJwkSetUriJwtDecoder { + +} diff --git a/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/JwkSetUriCondition.java b/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/JwkSetUriCondition.java new file mode 100644 index 000000000000..589d0b74b89f --- /dev/null +++ b/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/JwkSetUriCondition.java @@ -0,0 +1,45 @@ +/* + * Copyright 2012-present 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.security.oauth2.server.resource.autoconfigure; + +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 JWK Set URI. + * + * @author Vinod Kumar M + */ +class JwkSetUriCondition extends SpringBootCondition { + + @Override + public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { + ConditionMessage.Builder message = ConditionMessage.forCondition("JWK Set URI Condition"); + Environment environment = context.getEnvironment(); + String jwkSetUri = environment.getProperty("spring.security.oauth2.resourceserver.jwt.jwk-set-uri"); + if (!StringUtils.hasText(jwkSetUri)) { + return ConditionOutcome.noMatch(message.didNotFind("jwk-set-uri property").atAll()); + } + return ConditionOutcome.match(message.foundExactly("jwk-set-uri property")); + } + +} diff --git a/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/JwtDecoderConfiguration.java b/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/JwtDecoderConfiguration.java index a1de6887c376..00e85190b26f 100644 --- a/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/JwtDecoderConfiguration.java +++ b/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/JwtDecoderConfiguration.java @@ -30,7 +30,6 @@ import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -115,7 +114,7 @@ private SignatureAlgorithm exactlyOneAlgorithm() { } @Bean - @ConditionalOnProperty(name = "spring.security.oauth2.resourceserver.jwt.jwk-set-uri") + @ConditionalOnJwkSetUriJwtDecoder JwtDecoder jwtDecoderByJwkKeySetUri() { String jwkSetUri = this.properties.getJwkSetUri(); Assert.state(jwkSetUri != null, "No JWK Set URI property specified"); diff --git a/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveJwtDecoderConfiguration.java b/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveJwtDecoderConfiguration.java index 51da5fbc9579..fb68d63f7b2c 100644 --- a/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveJwtDecoderConfiguration.java +++ b/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveJwtDecoderConfiguration.java @@ -33,9 +33,9 @@ import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException; import org.springframework.boot.security.oauth2.server.resource.autoconfigure.ConditionalOnIssuerLocationJwtDecoder; +import org.springframework.boot.security.oauth2.server.resource.autoconfigure.ConditionalOnJwkSetUriJwtDecoder; import org.springframework.boot.security.oauth2.server.resource.autoconfigure.ConditionalOnPublicKeyJwtDecoder; import org.springframework.boot.security.oauth2.server.resource.autoconfigure.OAuth2ResourceServerProperties; import org.springframework.context.annotation.Bean; @@ -122,7 +122,7 @@ private SignatureAlgorithm exactlyOneAlgorithm() { } @Bean - @ConditionalOnProperty(name = "spring.security.oauth2.resourceserver.jwt.jwk-set-uri") + @ConditionalOnJwkSetUriJwtDecoder ReactiveJwtDecoder reactiveJwtDecoderByJwkKeySetUri() { String jwkSetUri = this.properties.getJwkSetUri(); Assert.notNull(jwkSetUri, "No JWK Set URI specified"); diff --git a/module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/OAuth2ResourceServerAutoConfigurationTests.java b/module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/OAuth2ResourceServerAutoConfigurationTests.java index b439800b9f63..a4900f10a348 100644 --- a/module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/OAuth2ResourceServerAutoConfigurationTests.java +++ b/module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/OAuth2ResourceServerAutoConfigurationTests.java @@ -347,6 +347,18 @@ void autoConfigurationWhenSetUriKeyLocationAndIssuerUriPresentShouldUseSetUri() }); } + @Test + void autoConfigurationWhenIssuerUriPresentAndJwkSetUriEmptyShouldUseIssuerUri() { + this.contextRunner + .withPropertyValues("spring.security.oauth2.resourceserver.jwt.issuer-uri=https://issuer-uri.com", + "spring.security.oauth2.resourceserver.jwt.jwk-set-uri=") + .run((context) -> { + assertThat(context).hasSingleBean(JwtDecoder.class); + assertThat(context.containsBean("jwtDecoderByJwkKeySetUri")).isFalse(); + assertThat(context.containsBean("jwtDecoderByIssuerUri")).isTrue(); + }); + } + @Test void autoConfigurationWhenKeyLocationAndIssuerUriPresentShouldUseIssuerUri() throws Exception { this.server = new MockWebServer(); diff --git a/module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java b/module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java index a0d5afaaebda..ef1ab88f7509 100644 --- a/module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java +++ b/module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java @@ -471,6 +471,18 @@ void autoConfigurationWhenJwkSetUriAndIntrospectionUriAvailable() { }); } + @Test + void autoConfigurationWhenIssuerUriPresentAndJwkSetUriEmptyShouldUseIssuerUri() { + this.contextRunner + .withPropertyValues("spring.security.oauth2.resourceserver.jwt.issuer-uri=https://issuer-uri.com", + "spring.security.oauth2.resourceserver.jwt.jwk-set-uri=") + .run((context) -> { + assertThat(context).hasSingleBean(ReactiveJwtDecoder.class); + assertThat(context.containsBean("reactiveJwtDecoderByJwkKeySetUri")).isFalse(); + assertThat(context.containsBean("reactiveJwtDecoderByIssuerUri")).isTrue(); + }); + } + @Test void opaqueTokenIntrospectorIsConditionalOnMissingBean() { this.contextRunner