Add nullability annotations to tests in module/spring-boot-security-oauth2-resource-server

See gh-47263
This commit is contained in:
Moritz Halbritter
2025-10-13 15:15:51 +02:00
parent b0b5b1b463
commit c03b71ea4e
3 changed files with 43 additions and 7 deletions
@@ -47,6 +47,12 @@ dependencies {
testImplementation(testFixtures(project(":core:spring-boot-autoconfigure")))
testImplementation("com.squareup.okhttp3:mockwebserver")
testCompileOnly("com.google.code.findbugs:jsr305")
testRuntimeOnly("ch.qos.logback:logback-classic")
testRuntimeOnly("org.springframework:spring-webflux")
}
tasks.named("compileTestJava") {
options.nullability.checking = "tests"
}
@@ -39,6 +39,7 @@ import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.assertj.core.api.ThrowingConsumer;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
@@ -87,6 +88,7 @@ import org.springframework.security.web.server.MatcherSecurityWebFilterChain;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.authentication.AuthenticationWebFilter;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import static org.assertj.core.api.Assertions.assertThat;
@@ -112,7 +114,7 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests {
.withConfiguration(AutoConfigurations.of(ReactiveOAuth2ResourceServerAutoConfiguration.class))
.withUserConfiguration(TestConfig.class);
private MockWebServer server;
private @Nullable MockWebServer server;
private static final Duration TIMEOUT = Duration.ofSeconds(5000000);
@@ -236,6 +238,7 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests {
SupplierReactiveJwtDecoder supplierReactiveJwtDecoder = context.getBean(SupplierReactiveJwtDecoder.class);
Mono<ReactiveJwtDecoder> reactiveJwtDecoderSupplier = (Mono<ReactiveJwtDecoder>) ReflectionTestUtils
.getField(supplierReactiveJwtDecoder, "jwtDecoderMono");
assertThat(reactiveJwtDecoderSupplier).isNotNull();
try {
reactiveJwtDecoderSupplier.flatMap((decoder) -> decoder.decode("eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9."
+ "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0."
@@ -538,7 +541,9 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests {
SupplierReactiveJwtDecoder supplierJwtDecoderBean = context.getBean(SupplierReactiveJwtDecoder.class);
Mono<ReactiveJwtDecoder> jwtDecoderSupplier = (Mono<ReactiveJwtDecoder>) ReflectionTestUtils
.getField(supplierJwtDecoderBean, "jwtDecoderMono");
assertThat(jwtDecoderSupplier).isNotNull();
ReactiveJwtDecoder jwtDecoder = jwtDecoderSupplier.block();
assertThat(jwtDecoder).isNotNull();
validate(
jwt().claim("iss", URI.create(issuerUri).toURL())
.claim("aud", List.of("https://test-audience.com")),
@@ -612,6 +617,7 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests {
ReactiveJwtDecoder jwtDecoder = context.getBean(ReactiveJwtDecoder.class);
DelegatingOAuth2TokenValidator<Jwt> jwtValidator = (DelegatingOAuth2TokenValidator<Jwt>) ReflectionTestUtils
.getField(jwtDecoder, "jwtValidator");
assertThat(jwtValidator).isNotNull();
Jwt jwt = jwt().claim("iss", new URL(issuerUri))
.claim("aud", Collections.singletonList("https://other-audience.com"))
.build();
@@ -638,6 +644,7 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests {
ReactiveJwtDecoder jwtDecoder = context.getBean(ReactiveJwtDecoder.class);
DelegatingOAuth2TokenValidator<Jwt> jwtValidator = (DelegatingOAuth2TokenValidator<Jwt>) ReflectionTestUtils
.getField(jwtDecoder, "jwtValidator");
assertThat(jwtValidator).isNotNull();
Jwt jwt = jwt().claim("iss", new URL(issuerUri)).claim("custom_claim", "invalid_value").build();
assertThat(jwtValidator.validate(jwt).hasErrors()).isTrue();
});
@@ -720,6 +727,7 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests {
.doesNotHaveBean(ReactiveManagementWebSecurityAutoConfiguration.class));
}
@SuppressWarnings("unchecked")
private void assertFilterConfiguredWithJwtAuthenticationManager(AssertableReactiveWebApplicationContext context) {
MatcherSecurityWebFilterChain filterChain = (MatcherSecurityWebFilterChain) context
.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN);
@@ -728,12 +736,16 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests {
.filter((f) -> f instanceof AuthenticationWebFilter)
.findFirst()
.orElse(null);
ReactiveAuthenticationManagerResolver<?> authenticationManagerResolver = (ReactiveAuthenticationManagerResolver<?>) ReflectionTestUtils
assertThat(webFilter).isNotNull();
ReactiveAuthenticationManagerResolver<ServerWebExchange> authenticationManagerResolver = (ReactiveAuthenticationManagerResolver<ServerWebExchange>) ReflectionTestUtils
.getField(webFilter, "authenticationManagerResolver");
Object authenticationManager = authenticationManagerResolver.resolve(null).block(TIMEOUT);
assertThat(authenticationManagerResolver).isNotNull();
Object authenticationManager = authenticationManagerResolver.resolve(mock(ServerWebExchange.class))
.block(TIMEOUT);
assertThat(authenticationManager).isInstanceOf(JwtReactiveAuthenticationManager.class);
}
@SuppressWarnings("unchecked")
private void assertFilterConfiguredWithOpaqueTokenAuthenticationManager(
AssertableReactiveWebApplicationContext context) {
MatcherSecurityWebFilterChain filterChain = (MatcherSecurityWebFilterChain) context
@@ -743,9 +755,12 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests {
.filter((f) -> f instanceof AuthenticationWebFilter)
.findFirst()
.orElse(null);
ReactiveAuthenticationManagerResolver<?> authenticationManagerResolver = (ReactiveAuthenticationManagerResolver<?>) ReflectionTestUtils
assertThat(webFilter).isNotNull();
ReactiveAuthenticationManagerResolver<ServerWebExchange> authenticationManagerResolver = (ReactiveAuthenticationManagerResolver<ServerWebExchange>) ReflectionTestUtils
.getField(webFilter, "authenticationManagerResolver");
Object authenticationManager = authenticationManagerResolver.resolve(null).block(TIMEOUT);
assertThat(authenticationManagerResolver).isNotNull();
Object authenticationManager = authenticationManagerResolver.resolve(mock(ServerWebExchange.class))
.block(TIMEOUT);
assertThat(authenticationManager).isInstanceOf(OpaqueTokenReactiveAuthenticationManager.class);
}
@@ -760,12 +775,14 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests {
MockResponse mockResponse = new MockResponse().setResponseCode(HttpStatus.OK.value())
.setBody(new ObjectMapper().writeValueAsString(getResponse(issuer)))
.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
assertThat(this.server).isNotNull();
this.server.enqueue(mockResponse);
this.server.enqueue(
new MockResponse().setResponseCode(200).setHeader("Content-Type", "application/json").setBody(JWK_SET));
}
private void setupMockResponsesWithErrors(String issuer, int errorResponseCount) {
assertThat(this.server).isNotNull();
for (int i = 0; i < errorResponseCount; i++) {
MockResponse emptyResponse = new MockResponse().setResponseCode(HttpStatus.NOT_FOUND.value());
this.server.enqueue(emptyResponse);
@@ -808,6 +825,7 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests {
ThrowingConsumer<List<OAuth2TokenValidator<Jwt>>> validatorsConsumer) {
DelegatingOAuth2TokenValidator<Jwt> jwtValidator = (DelegatingOAuth2TokenValidator<Jwt>) ReflectionTestUtils
.getField(jwtDecoder, "jwtValidator");
assertThat(jwtValidator).isNotNull();
assertThat(jwtValidator.validate(builder.build()).hasErrors()).isFalse();
validatorsConsumer.accept(extractValidators(jwtValidator));
}
@@ -816,6 +834,7 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests {
private List<OAuth2TokenValidator<Jwt>> extractValidators(DelegatingOAuth2TokenValidator<Jwt> delegatingValidator) {
Collection<OAuth2TokenValidator<Jwt>> delegates = (Collection<OAuth2TokenValidator<Jwt>>) ReflectionTestUtils
.getField(delegatingValidator, "tokenValidators");
assertThat(delegates).isNotNull();
List<OAuth2TokenValidator<Jwt>> extracted = new ArrayList<>();
for (OAuth2TokenValidator<Jwt> delegate : delegates) {
if (delegate instanceof DelegatingOAuth2TokenValidator<Jwt> delegatingDelegate) {
@@ -38,6 +38,7 @@ import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.assertj.core.api.ThrowingConsumer;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
@@ -105,7 +106,7 @@ class OAuth2ResourceServerAutoConfigurationTests {
.withConfiguration(AutoConfigurations.of(OAuth2ResourceServerAutoConfiguration.class))
.withUserConfiguration(TestConfig.class);
private MockWebServer server;
private @Nullable MockWebServer server;
private static final String JWK_SET = "{\"keys\":[{\"kty\":\"RSA\",\"e\":\"AQAB\",\"use\":\"sig\","
+ "\"kid\":\"one\",\"n\":\"oXJ8OyOv_eRnce4akdanR4KYRfnC2zLV4uYNQpcFn6oHL0dj7D6kxQmsXoYgJV8ZVDn71KGm"
@@ -228,6 +229,7 @@ class OAuth2ResourceServerAutoConfigurationTests {
SupplierJwtDecoder supplierJwtDecoderBean = context.getBean(SupplierJwtDecoder.class);
Supplier<JwtDecoder> jwtDecoderSupplier = (Supplier<JwtDecoder>) ReflectionTestUtils
.getField(supplierJwtDecoderBean, "delegate");
assertThat(jwtDecoderSupplier).isNotNull();
jwtDecoderSupplier.get();
assertJwkSetUriJwtDecoderBuilderCustomization(context);
});
@@ -253,6 +255,7 @@ class OAuth2ResourceServerAutoConfigurationTests {
SupplierJwtDecoder supplierJwtDecoderBean = context.getBean(SupplierJwtDecoder.class);
Supplier<JwtDecoder> jwtDecoderSupplier = (Supplier<JwtDecoder>) ReflectionTestUtils
.getField(supplierJwtDecoderBean, "delegate");
assertThat(jwtDecoderSupplier).isNotNull();
jwtDecoderSupplier.get();
assertJwkSetUriJwtDecoderBuilderCustomization(context);
});
@@ -279,6 +282,7 @@ class OAuth2ResourceServerAutoConfigurationTests {
SupplierJwtDecoder supplierJwtDecoderBean = context.getBean(SupplierJwtDecoder.class);
Supplier<JwtDecoder> jwtDecoderSupplier = (Supplier<JwtDecoder>) ReflectionTestUtils
.getField(supplierJwtDecoderBean, "delegate");
assertThat(jwtDecoderSupplier).isNotNull();
jwtDecoderSupplier.get();
assertJwkSetUriJwtDecoderBuilderCustomization(context);
});
@@ -558,6 +562,7 @@ class OAuth2ResourceServerAutoConfigurationTests {
SupplierJwtDecoder supplierJwtDecoderBean = context.getBean(SupplierJwtDecoder.class);
Supplier<JwtDecoder> jwtDecoderSupplier = (Supplier<JwtDecoder>) ReflectionTestUtils
.getField(supplierJwtDecoderBean, "delegate");
assertThat(jwtDecoderSupplier).isNotNull();
JwtDecoder jwtDecoder = jwtDecoderSupplier.get();
validate(
jwt().claim("iss", URI.create(issuerUri).toURL())
@@ -584,6 +589,7 @@ class OAuth2ResourceServerAutoConfigurationTests {
SupplierJwtDecoder supplierJwtDecoderBean = context.getBean(SupplierJwtDecoder.class);
Supplier<JwtDecoder> jwtDecoderSupplier = (Supplier<JwtDecoder>) ReflectionTestUtils
.getField(supplierJwtDecoderBean, "delegate");
assertThat(jwtDecoderSupplier).isNotNull();
JwtDecoder jwtDecoder = jwtDecoderSupplier.get();
assertThat(context).hasBean("customJwtClaimValidator");
OAuth2TokenValidator<Jwt> customValidator = (OAuth2TokenValidator<Jwt>) context
@@ -633,6 +639,7 @@ class OAuth2ResourceServerAutoConfigurationTests {
JwtDecoder jwtDecoder = context.getBean(JwtDecoder.class);
DelegatingOAuth2TokenValidator<Jwt> jwtValidator = (DelegatingOAuth2TokenValidator<Jwt>) ReflectionTestUtils
.getField(jwtDecoder, "jwtValidator");
assertThat(jwtValidator).isNotNull();
Jwt jwt = jwt().claim("iss", new URL(issuerUri))
.claim("aud", Collections.singletonList("https://other-audience.com"))
.build();
@@ -733,7 +740,7 @@ class OAuth2ResourceServerAutoConfigurationTests {
.doesNotHaveBean(MANAGEMENT_SECURITY_FILTER_CHAIN_BEAN));
}
private Filter getBearerTokenFilter(AssertableWebApplicationContext context) {
private @Nullable Filter getBearerTokenFilter(AssertableWebApplicationContext context) {
FilterChainProxy filterChain = (FilterChainProxy) context.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN);
List<SecurityFilterChain> filterChains = filterChain.getFilterChains();
List<Filter> filters = filterChains.get(0).getFilters();
@@ -751,12 +758,14 @@ class OAuth2ResourceServerAutoConfigurationTests {
MockResponse mockResponse = new MockResponse().setResponseCode(HttpStatus.OK.value())
.setBody(new ObjectMapper().writeValueAsString(getResponse(issuer)))
.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
assertThat(this.server).isNotNull();
this.server.enqueue(mockResponse);
this.server.enqueue(
new MockResponse().setResponseCode(200).setHeader("Content-Type", "application/json").setBody(JWK_SET));
}
private void setupMockResponsesWithErrors(String issuer, int errorResponseCount) {
assertThat(this.server).isNotNull();
for (int i = 0; i < errorResponseCount; i++) {
MockResponse emptyResponse = new MockResponse().setResponseCode(HttpStatus.NOT_FOUND.value());
this.server.enqueue(emptyResponse);
@@ -799,6 +808,7 @@ class OAuth2ResourceServerAutoConfigurationTests {
ThrowingConsumer<List<OAuth2TokenValidator<Jwt>>> validatorsConsumer) {
DelegatingOAuth2TokenValidator<Jwt> jwtValidator = (DelegatingOAuth2TokenValidator<Jwt>) ReflectionTestUtils
.getField(jwtDecoder, "jwtValidator");
assertThat(jwtValidator).isNotNull();
assertThat(jwtValidator.validate(builder.build()).hasErrors()).isFalse();
validatorsConsumer.accept(extractValidators(jwtValidator));
}
@@ -807,6 +817,7 @@ class OAuth2ResourceServerAutoConfigurationTests {
private List<OAuth2TokenValidator<Jwt>> extractValidators(DelegatingOAuth2TokenValidator<Jwt> delegatingValidator) {
Collection<OAuth2TokenValidator<Jwt>> delegates = (Collection<OAuth2TokenValidator<Jwt>>) ReflectionTestUtils
.getField(delegatingValidator, "tokenValidators");
assertThat(delegates).isNotNull();
List<OAuth2TokenValidator<Jwt>> extracted = new ArrayList<>();
for (OAuth2TokenValidator<Jwt> delegate : delegates) {
if (delegate instanceof DelegatingOAuth2TokenValidator<Jwt> delegatingDelegate) {