mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-10-22 18:28:51 +00:00
Enable Null checking in spring-security-test via JSpecify
Closes gh-17840
This commit is contained in:
parent
194be8ffb6
commit
6a84f96930
@ -1,3 +1,7 @@
|
|||||||
|
plugins {
|
||||||
|
id 'security-nullability'
|
||||||
|
}
|
||||||
|
|
||||||
apply plugin: 'io.spring.convention.spring-module'
|
apply plugin: 'io.spring.convention.spring-module'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package org.springframework.security.test.aot.hint;
|
package org.springframework.security.test.aot.hint;
|
||||||
|
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
import org.springframework.aot.hint.MemberCategory;
|
import org.springframework.aot.hint.MemberCategory;
|
||||||
import org.springframework.aot.hint.RuntimeHints;
|
import org.springframework.aot.hint.RuntimeHints;
|
||||||
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
||||||
@ -36,7 +38,7 @@ import org.springframework.util.ClassUtils;
|
|||||||
class WebTestUtilsRuntimeHints implements RuntimeHintsRegistrar {
|
class WebTestUtilsRuntimeHints implements RuntimeHintsRegistrar {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
|
||||||
if (!ClassUtils.isPresent("jakarta.servlet.Filter", classLoader)) {
|
if (!ClassUtils.isPresent("jakarta.servlet.Filter", classLoader)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2004-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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AOT Support for Spring Security test.
|
||||||
|
*/
|
||||||
|
@NullMarked
|
||||||
|
package org.springframework.security.test.aot.hint;
|
||||||
|
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2004-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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Support for Framework's Test annotations.
|
||||||
|
*/
|
||||||
|
@NullMarked
|
||||||
|
package org.springframework.security.test.context.annotation;
|
||||||
|
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2004-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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spring Security support managing the
|
||||||
|
* {@link org.springframework.security.core.context.SecurityContext}.
|
||||||
|
*/
|
||||||
|
@NullMarked
|
||||||
|
package org.springframework.security.test.context;
|
||||||
|
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
@ -20,6 +20,9 @@ import java.lang.annotation.Annotation;
|
|||||||
import java.lang.reflect.AnnotatedElement;
|
import java.lang.reflect.AnnotatedElement;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import org.jspecify.annotations.NullUnmarked;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.core.GenericTypeResolver;
|
import org.springframework.core.GenericTypeResolver;
|
||||||
@ -76,6 +79,7 @@ public class WithSecurityContextTestExecutionListener extends AbstractTestExecut
|
|||||||
* {@link WithSecurityContext} on it. If that is not found, the class is inspected. If
|
* {@link WithSecurityContext} on it. If that is not found, the class is inspected. If
|
||||||
* still not found, then no {@link SecurityContext} is populated.
|
* still not found, then no {@link SecurityContext} is populated.
|
||||||
*/
|
*/
|
||||||
|
@NullUnmarked
|
||||||
@Override
|
@Override
|
||||||
public void beforeTestMethod(TestContext testContext) {
|
public void beforeTestMethod(TestContext testContext) {
|
||||||
TestSecurityContext testSecurityContext = createTestSecurityContext(testContext.getTestMethod(), testContext);
|
TestSecurityContext testSecurityContext = createTestSecurityContext(testContext.getTestMethod(), testContext);
|
||||||
@ -98,6 +102,7 @@ public class WithSecurityContextTestExecutionListener extends AbstractTestExecut
|
|||||||
* If configured before test execution sets the SecurityContext
|
* If configured before test execution sets the SecurityContext
|
||||||
* @since 5.1
|
* @since 5.1
|
||||||
*/
|
*/
|
||||||
|
@NullUnmarked
|
||||||
@Override
|
@Override
|
||||||
public void beforeTestExecution(TestContext testContext) {
|
public void beforeTestExecution(TestContext testContext) {
|
||||||
Supplier<SecurityContext> supplier = (Supplier<SecurityContext>) testContext
|
Supplier<SecurityContext> supplier = (Supplier<SecurityContext>) testContext
|
||||||
@ -107,13 +112,13 @@ public class WithSecurityContextTestExecutionListener extends AbstractTestExecut
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private TestSecurityContext createTestSecurityContext(AnnotatedElement annotated, TestContext context) {
|
private @Nullable TestSecurityContext createTestSecurityContext(AnnotatedElement annotated, TestContext context) {
|
||||||
WithSecurityContext withSecurityContext = AnnotatedElementUtils.findMergedAnnotation(annotated,
|
WithSecurityContext withSecurityContext = AnnotatedElementUtils.findMergedAnnotation(annotated,
|
||||||
WithSecurityContext.class);
|
WithSecurityContext.class);
|
||||||
return createTestSecurityContext(annotated, withSecurityContext, context);
|
return createTestSecurityContext(annotated, withSecurityContext, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TestSecurityContext createTestSecurityContext(Class<?> annotated, TestContext context) {
|
private @Nullable TestSecurityContext createTestSecurityContext(Class<?> annotated, TestContext context) {
|
||||||
TestContextAnnotationUtils.AnnotationDescriptor<WithSecurityContext> withSecurityContextDescriptor = TestContextAnnotationUtils
|
TestContextAnnotationUtils.AnnotationDescriptor<WithSecurityContext> withSecurityContextDescriptor = TestContextAnnotationUtils
|
||||||
.findAnnotationDescriptor(annotated, WithSecurityContext.class);
|
.findAnnotationDescriptor(annotated, WithSecurityContext.class);
|
||||||
if (withSecurityContextDescriptor == null) {
|
if (withSecurityContextDescriptor == null) {
|
||||||
@ -124,9 +129,10 @@ public class WithSecurityContextTestExecutionListener extends AbstractTestExecut
|
|||||||
return createTestSecurityContext(rootDeclaringClass, withSecurityContext, context);
|
return createTestSecurityContext(rootDeclaringClass, withSecurityContext, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NullUnmarked
|
||||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
private TestSecurityContext createTestSecurityContext(AnnotatedElement annotated,
|
private @Nullable TestSecurityContext createTestSecurityContext(AnnotatedElement annotated,
|
||||||
WithSecurityContext withSecurityContext, TestContext context) {
|
@Nullable WithSecurityContext withSecurityContext, TestContext context) {
|
||||||
if (withSecurityContext == null) {
|
if (withSecurityContext == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -147,7 +153,9 @@ public class WithSecurityContextTestExecutionListener extends AbstractTestExecut
|
|||||||
return new TestSecurityContext(supplier, initialize);
|
return new TestSecurityContext(supplier, initialize);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Annotation findAnnotation(AnnotatedElement annotated, Class<? extends Annotation> type) {
|
@NullUnmarked
|
||||||
|
private @Nullable Annotation findAnnotation(AnnotatedElement annotated,
|
||||||
|
@Nullable Class<? extends Annotation> type) {
|
||||||
Annotation findAnnotation = AnnotatedElementUtils.findMergedAnnotation(annotated, type);
|
Annotation findAnnotation = AnnotatedElementUtils.findMergedAnnotation(annotated, type);
|
||||||
if (findAnnotation != null) {
|
if (findAnnotation != null) {
|
||||||
return findAnnotation;
|
return findAnnotation;
|
||||||
@ -181,6 +189,7 @@ public class WithSecurityContextTestExecutionListener extends AbstractTestExecut
|
|||||||
* Clears out the {@link TestSecurityContextHolder} and the
|
* Clears out the {@link TestSecurityContextHolder} and the
|
||||||
* {@link SecurityContextHolder} after each test method.
|
* {@link SecurityContextHolder} after each test method.
|
||||||
*/
|
*/
|
||||||
|
@NullUnmarked
|
||||||
@Override
|
@Override
|
||||||
public void afterTestMethod(TestContext testContext) {
|
public void afterTestMethod(TestContext testContext) {
|
||||||
this.securityContextHolderStrategyConverter.convert(testContext).clearContext();
|
this.securityContextHolderStrategyConverter.convert(testContext).clearContext();
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package org.springframework.security.test.context.support;
|
package org.springframework.security.test.context.support;
|
||||||
|
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
import org.springframework.beans.factory.BeanFactory;
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
|
import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||||
@ -89,7 +91,7 @@ final class WithUserDetailsSecurityContextFactory implements WithSecurityContext
|
|||||||
: this.beans.getBean(UserDetailsService.class);
|
: this.beans.getBean(UserDetailsService.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
UserDetailsService findAndAdaptReactiveUserDetailsService(String beanName) {
|
@Nullable UserDetailsService findAndAdaptReactiveUserDetailsService(String beanName) {
|
||||||
try {
|
try {
|
||||||
ReactiveUserDetailsService reactiveUserDetailsService = StringUtils.hasLength(beanName)
|
ReactiveUserDetailsService reactiveUserDetailsService = StringUtils.hasLength(beanName)
|
||||||
? this.beans.getBean(beanName, ReactiveUserDetailsService.class)
|
? this.beans.getBean(beanName, ReactiveUserDetailsService.class)
|
||||||
@ -110,6 +112,7 @@ final class WithUserDetailsSecurityContextFactory implements WithSecurityContext
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("NullAway") // Dataflow analysis limitation
|
||||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||||
return this.userDetailsService.findByUsername(username).block();
|
return this.userDetailsService.findByUsername(username).block();
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2004-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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spring Security support classes for the Spring TestContext Framework.
|
||||||
|
*/
|
||||||
|
@NullMarked
|
||||||
|
package org.springframework.security.test.context.support;
|
||||||
|
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
@ -29,6 +29,7 @@ import java.util.function.Consumer;
|
|||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.jspecify.annotations.NullUnmarked;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
@ -190,6 +191,7 @@ public final class SecurityMockServerConfigurers {
|
|||||||
* @return the {@link OAuth2LoginMutator} to further configure or use
|
* @return the {@link OAuth2LoginMutator} to further configure or use
|
||||||
* @since 5.3
|
* @since 5.3
|
||||||
*/
|
*/
|
||||||
|
@NullUnmarked
|
||||||
public static OAuth2LoginMutator mockOAuth2Login() {
|
public static OAuth2LoginMutator mockOAuth2Login() {
|
||||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, "access-token", null,
|
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, "access-token", null,
|
||||||
null, Collections.singleton("read"));
|
null, Collections.singleton("read"));
|
||||||
@ -203,6 +205,7 @@ public final class SecurityMockServerConfigurers {
|
|||||||
* @return the {@link OidcLoginMutator} to further configure or use
|
* @return the {@link OidcLoginMutator} to further configure or use
|
||||||
* @since 5.3
|
* @since 5.3
|
||||||
*/
|
*/
|
||||||
|
@NullUnmarked
|
||||||
public static OidcLoginMutator mockOidcLogin() {
|
public static OidcLoginMutator mockOidcLogin() {
|
||||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, "access-token", null,
|
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, "access-token", null,
|
||||||
null, Collections.singleton("read"));
|
null, Collections.singleton("read"));
|
||||||
@ -252,6 +255,7 @@ public final class SecurityMockServerConfigurers {
|
|||||||
private CsrfMutator() {
|
private CsrfMutator() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NullUnmarked
|
||||||
@Override
|
@Override
|
||||||
public void afterConfigurerAdded(WebTestClient.Builder builder,
|
public void afterConfigurerAdded(WebTestClient.Builder builder,
|
||||||
@Nullable WebHttpHandlerBuilder httpHandlerBuilder, @Nullable ClientHttpConnector connector) {
|
@Nullable WebHttpHandlerBuilder httpHandlerBuilder, @Nullable ClientHttpConnector connector) {
|
||||||
@ -394,6 +398,7 @@ public final class SecurityMockServerConfigurers {
|
|||||||
builder.filters(addSetupMutatorFilter());
|
builder.filters(addSetupMutatorFilter());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NullUnmarked
|
||||||
@Override
|
@Override
|
||||||
public void afterConfigurerAdded(WebTestClient.Builder builder,
|
public void afterConfigurerAdded(WebTestClient.Builder builder,
|
||||||
@Nullable WebHttpHandlerBuilder webHttpHandlerBuilder,
|
@Nullable WebHttpHandlerBuilder webHttpHandlerBuilder,
|
||||||
@ -537,6 +542,7 @@ public final class SecurityMockServerConfigurers {
|
|||||||
configurer().afterConfigureAdded(serverSpec);
|
configurer().afterConfigureAdded(serverSpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NullUnmarked
|
||||||
@Override
|
@Override
|
||||||
public void afterConfigurerAdded(WebTestClient.Builder builder,
|
public void afterConfigurerAdded(WebTestClient.Builder builder,
|
||||||
@Nullable WebHttpHandlerBuilder httpHandlerBuilder, @Nullable ClientHttpConnector connector) {
|
@Nullable WebHttpHandlerBuilder httpHandlerBuilder, @Nullable ClientHttpConnector connector) {
|
||||||
@ -547,6 +553,7 @@ public final class SecurityMockServerConfigurers {
|
|||||||
configurer().afterConfigurerAdded(builder, httpHandlerBuilder, connector);
|
configurer().afterConfigurerAdded(builder, httpHandlerBuilder, connector);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NullUnmarked
|
||||||
private <T extends WebTestClientConfigurer & MockServerConfigurer> T configurer() {
|
private <T extends WebTestClientConfigurer & MockServerConfigurer> T configurer() {
|
||||||
return mockAuthentication(
|
return mockAuthentication(
|
||||||
new JwtAuthenticationToken(this.jwt, this.authoritiesConverter.convert(this.jwt)));
|
new JwtAuthenticationToken(this.jwt, this.authoritiesConverter.convert(this.jwt)));
|
||||||
@ -631,6 +638,7 @@ public final class SecurityMockServerConfigurers {
|
|||||||
configurer().afterConfigureAdded(serverSpec);
|
configurer().afterConfigureAdded(serverSpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NullUnmarked
|
||||||
@Override
|
@Override
|
||||||
public void afterConfigurerAdded(WebTestClient.Builder builder,
|
public void afterConfigurerAdded(WebTestClient.Builder builder,
|
||||||
@Nullable WebHttpHandlerBuilder httpHandlerBuilder, @Nullable ClientHttpConnector connector) {
|
@Nullable WebHttpHandlerBuilder httpHandlerBuilder, @Nullable ClientHttpConnector connector) {
|
||||||
@ -688,6 +696,7 @@ public final class SecurityMockServerConfigurers {
|
|||||||
return new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, "token", issuedAt, expiresAt);
|
return new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, "token", issuedAt, expiresAt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NullUnmarked
|
||||||
private Instant getInstant(Map<String, Object> attributes, String name) {
|
private Instant getInstant(Map<String, Object> attributes, String name) {
|
||||||
Object value = attributes.get(name);
|
Object value = attributes.get(name);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
@ -865,12 +874,15 @@ public final class SecurityMockServerConfigurers {
|
|||||||
|
|
||||||
private OAuth2AccessToken accessToken;
|
private OAuth2AccessToken accessToken;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
private OidcIdToken idToken;
|
private OidcIdToken idToken;
|
||||||
|
|
||||||
|
@SuppressWarnings("NullAway.Init")
|
||||||
private OidcUserInfo userInfo;
|
private OidcUserInfo userInfo;
|
||||||
|
|
||||||
private Supplier<OidcUser> oidcUser = this::defaultPrincipal;
|
private Supplier<OidcUser> oidcUser = this::defaultPrincipal;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
private Collection<GrantedAuthority> authorities;
|
private Collection<GrantedAuthority> authorities;
|
||||||
|
|
||||||
private OidcLoginMutator(OAuth2AccessToken accessToken) {
|
private OidcLoginMutator(OAuth2AccessToken accessToken) {
|
||||||
@ -1015,6 +1027,7 @@ public final class SecurityMockServerConfigurers {
|
|||||||
return authorities;
|
return authorities;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NullUnmarked
|
||||||
private OidcIdToken getOidcIdToken() {
|
private OidcIdToken getOidcIdToken() {
|
||||||
if (this.idToken != null) {
|
if (this.idToken != null) {
|
||||||
return this.idToken;
|
return this.idToken;
|
||||||
@ -1036,10 +1049,12 @@ public final class SecurityMockServerConfigurers {
|
|||||||
* @author Josh Cummings
|
* @author Josh Cummings
|
||||||
* @since 5.3
|
* @since 5.3
|
||||||
*/
|
*/
|
||||||
|
@NullUnmarked
|
||||||
public static final class OAuth2ClientMutator implements WebTestClientConfigurer, MockServerConfigurer {
|
public static final class OAuth2ClientMutator implements WebTestClientConfigurer, MockServerConfigurer {
|
||||||
|
|
||||||
private String registrationId = "test";
|
private String registrationId = "test";
|
||||||
|
|
||||||
|
@Nullable
|
||||||
private ClientRegistration clientRegistration;
|
private ClientRegistration clientRegistration;
|
||||||
|
|
||||||
private String principalName = "user";
|
private String principalName = "user";
|
||||||
@ -1115,12 +1130,14 @@ public final class SecurityMockServerConfigurers {
|
|||||||
public void afterConfigureAdded(WebTestClient.MockServerSpec<?> serverSpec) {
|
public void afterConfigureAdded(WebTestClient.MockServerSpec<?> serverSpec) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NullUnmarked
|
||||||
@Override
|
@Override
|
||||||
public void afterConfigurerAdded(WebTestClient.Builder builder,
|
public void afterConfigurerAdded(WebTestClient.Builder builder,
|
||||||
@Nullable WebHttpHandlerBuilder httpHandlerBuilder, @Nullable ClientHttpConnector connector) {
|
@Nullable WebHttpHandlerBuilder httpHandlerBuilder, @Nullable ClientHttpConnector connector) {
|
||||||
httpHandlerBuilder.filters(addAuthorizedClientFilter());
|
httpHandlerBuilder.filters(addAuthorizedClientFilter());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NullUnmarked
|
||||||
private Consumer<List<WebFilter>> addAuthorizedClientFilter() {
|
private Consumer<List<WebFilter>> addAuthorizedClientFilter() {
|
||||||
OAuth2AuthorizedClient client = getClient();
|
OAuth2AuthorizedClient client = getClient();
|
||||||
return (filters) -> filters.add(0, (exchange, chain) -> {
|
return (filters) -> filters.add(0, (exchange, chain) -> {
|
||||||
@ -1136,6 +1153,7 @@ public final class SecurityMockServerConfigurers {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NullUnmarked
|
||||||
private OAuth2AuthorizedClient getClient() {
|
private OAuth2AuthorizedClient getClient() {
|
||||||
Assert.notNull(this.clientRegistration,
|
Assert.notNull(this.clientRegistration,
|
||||||
"Please specify a ClientRegistration via one of the clientRegistration methods");
|
"Please specify a ClientRegistration via one of the clientRegistration methods");
|
||||||
@ -1163,12 +1181,14 @@ public final class SecurityMockServerConfigurers {
|
|||||||
|
|
||||||
private final ReactiveOAuth2AuthorizedClientManager delegate;
|
private final ReactiveOAuth2AuthorizedClientManager delegate;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
private ServerOAuth2AuthorizedClientRepository authorizedClientRepository;
|
private ServerOAuth2AuthorizedClientRepository authorizedClientRepository;
|
||||||
|
|
||||||
TestOAuth2AuthorizedClientManager(ReactiveOAuth2AuthorizedClientManager delegate) {
|
TestOAuth2AuthorizedClientManager(ReactiveOAuth2AuthorizedClientManager delegate) {
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NullUnmarked
|
||||||
@Override
|
@Override
|
||||||
public Mono<OAuth2AuthorizedClient> authorize(OAuth2AuthorizeRequest authorizeRequest) {
|
public Mono<OAuth2AuthorizedClient> authorize(OAuth2AuthorizeRequest authorizeRequest) {
|
||||||
ServerWebExchange exchange = authorizeRequest.getAttribute(ServerWebExchange.class.getName());
|
ServerWebExchange exchange = authorizeRequest.getAttribute(ServerWebExchange.class.getName());
|
||||||
@ -1183,7 +1203,8 @@ public final class SecurityMockServerConfigurers {
|
|||||||
exchange.getAttributes().put(ENABLED_ATTR_NAME, Boolean.TRUE);
|
exchange.getAttributes().put(ENABLED_ATTR_NAME, Boolean.TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isEnabled(ServerWebExchange exchange) {
|
@NullUnmarked
|
||||||
|
boolean isEnabled(@Nullable ServerWebExchange exchange) {
|
||||||
return Boolean.TRUE.equals(exchange.getAttribute(ENABLED_ATTR_NAME));
|
return Boolean.TRUE.equals(exchange.getAttribute(ENABLED_ATTR_NAME));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1202,7 +1223,8 @@ public final class SecurityMockServerConfigurers {
|
|||||||
|
|
||||||
private final ServerOAuth2AuthorizedClientRepository delegate;
|
private final ServerOAuth2AuthorizedClientRepository delegate;
|
||||||
|
|
||||||
TestOAuth2AuthorizedClientRepository(ServerOAuth2AuthorizedClientRepository delegate) {
|
@NullUnmarked
|
||||||
|
TestOAuth2AuthorizedClientRepository(@Nullable ServerOAuth2AuthorizedClientRepository delegate) {
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1261,7 +1283,8 @@ public final class SecurityMockServerConfigurers {
|
|||||||
* @return the {@link ReactiveOAuth2AuthorizedClientManager} for the specified
|
* @return the {@link ReactiveOAuth2AuthorizedClientManager} for the specified
|
||||||
* {@link ServerWebExchange}
|
* {@link ServerWebExchange}
|
||||||
*/
|
*/
|
||||||
static ServerOAuth2AuthorizedClientRepository getAuthorizedClientRepository(ServerWebExchange exchange) {
|
static @Nullable ServerOAuth2AuthorizedClientRepository getAuthorizedClientRepository(
|
||||||
|
ServerWebExchange exchange) {
|
||||||
ReactiveOAuth2AuthorizedClientManager manager = getOAuth2AuthorizedClientManager(exchange);
|
ReactiveOAuth2AuthorizedClientManager manager = getOAuth2AuthorizedClientManager(exchange);
|
||||||
if (manager == null) {
|
if (manager == null) {
|
||||||
return DEFAULT_CLIENT_REPO;
|
return DEFAULT_CLIENT_REPO;
|
||||||
@ -1294,7 +1317,8 @@ public final class SecurityMockServerConfigurers {
|
|||||||
((TestOAuth2AuthorizedClientManager) manager).authorizedClientRepository = repository;
|
((TestOAuth2AuthorizedClientManager) manager).authorizedClientRepository = repository;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ReactiveOAuth2AuthorizedClientManager getOAuth2AuthorizedClientManager(ServerWebExchange exchange) {
|
static @Nullable ReactiveOAuth2AuthorizedClientManager getOAuth2AuthorizedClientManager(
|
||||||
|
ServerWebExchange exchange) {
|
||||||
OAuth2AuthorizedClientArgumentResolver resolver = findResolver(exchange,
|
OAuth2AuthorizedClientArgumentResolver resolver = findResolver(exchange,
|
||||||
OAuth2AuthorizedClientArgumentResolver.class);
|
OAuth2AuthorizedClientArgumentResolver.class);
|
||||||
if (resolver == null) {
|
if (resolver == null) {
|
||||||
@ -1323,7 +1347,7 @@ public final class SecurityMockServerConfigurers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
static <T extends HandlerMethodArgumentResolver> T findResolver(ServerWebExchange exchange,
|
static <T extends HandlerMethodArgumentResolver> @Nullable T findResolver(ServerWebExchange exchange,
|
||||||
Class<T> resolverClass) {
|
Class<T> resolverClass) {
|
||||||
if (!ClassUtils.isPresent(
|
if (!ClassUtils.isPresent(
|
||||||
"org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter",
|
"org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter",
|
||||||
@ -1335,7 +1359,7 @@ public final class SecurityMockServerConfigurers {
|
|||||||
|
|
||||||
private static class WebFluxClasspathGuard {
|
private static class WebFluxClasspathGuard {
|
||||||
|
|
||||||
static <T extends HandlerMethodArgumentResolver> T findResolver(ServerWebExchange exchange,
|
static <T extends HandlerMethodArgumentResolver> @Nullable T findResolver(ServerWebExchange exchange,
|
||||||
Class<T> resolverClass) {
|
Class<T> resolverClass) {
|
||||||
RequestMappingHandlerAdapter handlerAdapter = getRequestMappingHandlerAdapter(exchange);
|
RequestMappingHandlerAdapter handlerAdapter = getRequestMappingHandlerAdapter(exchange);
|
||||||
if (handlerAdapter == null) {
|
if (handlerAdapter == null) {
|
||||||
@ -1358,7 +1382,7 @@ public final class SecurityMockServerConfigurers {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static RequestMappingHandlerAdapter getRequestMappingHandlerAdapter(
|
private static @Nullable RequestMappingHandlerAdapter getRequestMappingHandlerAdapter(
|
||||||
ServerWebExchange exchange) {
|
ServerWebExchange exchange) {
|
||||||
ApplicationContext context = exchange.getApplicationContext();
|
ApplicationContext context = exchange.getApplicationContext();
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2004-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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spring Security upport for testing Spring WebFlux server endpoints via WebTestClient.
|
||||||
|
*/
|
||||||
|
@NullMarked
|
||||||
|
package org.springframework.security.test.web.reactive.server;
|
||||||
|
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
@ -17,6 +17,7 @@
|
|||||||
package org.springframework.security.test.web.servlet.request;
|
package org.springframework.security.test.web.servlet.request;
|
||||||
|
|
||||||
import jakarta.servlet.ServletContext;
|
import jakarta.servlet.ServletContext;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
import org.springframework.beans.Mergeable;
|
import org.springframework.beans.Mergeable;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
@ -91,7 +92,7 @@ public final class SecurityMockMvcRequestBuilders {
|
|||||||
|
|
||||||
private RequestPostProcessor postProcessor = csrf();
|
private RequestPostProcessor postProcessor = csrf();
|
||||||
|
|
||||||
private Mergeable parent;
|
private @Nullable Mergeable parent;
|
||||||
|
|
||||||
private LogoutRequestBuilder() {
|
private LogoutRequestBuilder() {
|
||||||
}
|
}
|
||||||
@ -135,7 +136,7 @@ public final class SecurityMockMvcRequestBuilders {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object merge(Object parent) {
|
public Object merge(@Nullable Object parent) {
|
||||||
if (parent == null) {
|
if (parent == null) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -168,7 +169,7 @@ public final class SecurityMockMvcRequestBuilders {
|
|||||||
|
|
||||||
private MediaType acceptMediaType = MediaType.APPLICATION_FORM_URLENCODED;
|
private MediaType acceptMediaType = MediaType.APPLICATION_FORM_URLENCODED;
|
||||||
|
|
||||||
private Mergeable parent;
|
private @Nullable Mergeable parent;
|
||||||
|
|
||||||
private RequestPostProcessor postProcessor = csrf();
|
private RequestPostProcessor postProcessor = csrf();
|
||||||
|
|
||||||
@ -297,7 +298,7 @@ public final class SecurityMockMvcRequestBuilders {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object merge(Object parent) {
|
public Object merge(@Nullable Object parent) {
|
||||||
if (parent == null) {
|
if (parent == null) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,8 @@ import java.util.stream.Collectors;
|
|||||||
import jakarta.servlet.ServletContext;
|
import jakarta.servlet.ServletContext;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import org.jspecify.annotations.NullUnmarked;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
import org.springframework.core.convert.converter.Converter;
|
import org.springframework.core.convert.converter.Converter;
|
||||||
import org.springframework.core.io.DefaultResourceLoader;
|
import org.springframework.core.io.DefaultResourceLoader;
|
||||||
@ -397,6 +399,7 @@ public final class SecurityMockMvcRequestPostProcessors {
|
|||||||
* @return the {@link OidcLoginRequestPostProcessor} for additional customization
|
* @return the {@link OidcLoginRequestPostProcessor} for additional customization
|
||||||
* @since 5.3
|
* @since 5.3
|
||||||
*/
|
*/
|
||||||
|
@NullUnmarked
|
||||||
public static OAuth2LoginRequestPostProcessor oauth2Login() {
|
public static OAuth2LoginRequestPostProcessor oauth2Login() {
|
||||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, "access-token", null,
|
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, "access-token", null,
|
||||||
null, Collections.singleton("read"));
|
null, Collections.singleton("read"));
|
||||||
@ -425,6 +428,7 @@ public final class SecurityMockMvcRequestPostProcessors {
|
|||||||
* @return the {@link OidcLoginRequestPostProcessor} for additional customization
|
* @return the {@link OidcLoginRequestPostProcessor} for additional customization
|
||||||
* @since 5.3
|
* @since 5.3
|
||||||
*/
|
*/
|
||||||
|
@NullUnmarked
|
||||||
public static OidcLoginRequestPostProcessor oidcLogin() {
|
public static OidcLoginRequestPostProcessor oidcLogin() {
|
||||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, "access-token", null,
|
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, "access-token", null,
|
||||||
null, Collections.singleton("read"));
|
null, Collections.singleton("read"));
|
||||||
@ -513,6 +517,7 @@ public final class SecurityMockMvcRequestPostProcessors {
|
|||||||
private CsrfRequestPostProcessor() {
|
private CsrfRequestPostProcessor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NullUnmarked
|
||||||
@Override
|
@Override
|
||||||
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
|
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
|
||||||
CsrfTokenRepository repository = WebTestUtils.getCsrfTokenRepository(request);
|
CsrfTokenRepository repository = WebTestUtils.getCsrfTokenRepository(request);
|
||||||
@ -577,7 +582,7 @@ public final class SecurityMockMvcRequestPostProcessors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveToken(CsrfToken token, HttpServletRequest request, HttpServletResponse response) {
|
public void saveToken(@Nullable CsrfToken token, HttpServletRequest request, HttpServletResponse response) {
|
||||||
if (isEnabled(request)) {
|
if (isEnabled(request)) {
|
||||||
request.setAttribute(TOKEN_ATTR_NAME, token);
|
request.setAttribute(TOKEN_ATTR_NAME, token);
|
||||||
}
|
}
|
||||||
@ -587,7 +592,7 @@ public final class SecurityMockMvcRequestPostProcessors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CsrfToken loadToken(HttpServletRequest request) {
|
public @Nullable CsrfToken loadToken(HttpServletRequest request) {
|
||||||
if (isEnabled(request)) {
|
if (isEnabled(request)) {
|
||||||
return (CsrfToken) request.getAttribute(TOKEN_ATTR_NAME);
|
return (CsrfToken) request.getAttribute(TOKEN_ATTR_NAME);
|
||||||
}
|
}
|
||||||
@ -697,8 +702,9 @@ public final class SecurityMockMvcRequestPostProcessors {
|
|||||||
* @return the MD5 of the digest authentication response, encoded in hex
|
* @return the MD5 of the digest authentication response, encoded in hex
|
||||||
* @throws IllegalArgumentException if the supplied qop value is unsupported.
|
* @throws IllegalArgumentException if the supplied qop value is unsupported.
|
||||||
*/
|
*/
|
||||||
private static String generateDigest(String username, String realm, String password, String httpMethod,
|
private static String generateDigest(String username, String realm, String password,
|
||||||
String uri, String qop, String nonce, String nc, String cnonce) throws IllegalArgumentException {
|
@Nullable String httpMethod, @Nullable String uri, String qop, String nonce, String nc, String cnonce)
|
||||||
|
throws IllegalArgumentException {
|
||||||
String a1Md5 = encodePasswordInA1Format(username, realm, password);
|
String a1Md5 = encodePasswordInA1Format(username, realm, password);
|
||||||
String a2 = httpMethod + ":" + uri;
|
String a2 = httpMethod + ":" + uri;
|
||||||
String a2Md5 = md5Hex(a2);
|
String a2Md5 = md5Hex(a2);
|
||||||
@ -1129,6 +1135,7 @@ public final class SecurityMockMvcRequestPostProcessors {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NullUnmarked
|
||||||
@Override
|
@Override
|
||||||
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
|
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
|
||||||
CsrfFilter.skipRequest(request);
|
CsrfFilter.skipRequest(request);
|
||||||
@ -1255,6 +1262,7 @@ public final class SecurityMockMvcRequestPostProcessors {
|
|||||||
return new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, "token", issuedAt, expiresAt);
|
return new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, "token", issuedAt, expiresAt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NullUnmarked
|
||||||
private Instant getInstant(Map<String, Object> attributes, String name) {
|
private Instant getInstant(Map<String, Object> attributes, String name) {
|
||||||
Object value = attributes.get(name);
|
Object value = attributes.get(name);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
@ -1407,13 +1415,14 @@ public final class SecurityMockMvcRequestPostProcessors {
|
|||||||
|
|
||||||
private OAuth2AccessToken accessToken;
|
private OAuth2AccessToken accessToken;
|
||||||
|
|
||||||
private OidcIdToken idToken;
|
private @Nullable OidcIdToken idToken;
|
||||||
|
|
||||||
|
@SuppressWarnings("NullAway.Init")
|
||||||
private OidcUserInfo userInfo;
|
private OidcUserInfo userInfo;
|
||||||
|
|
||||||
private Supplier<OidcUser> oidcUser = this::defaultPrincipal;
|
private Supplier<OidcUser> oidcUser = this::defaultPrincipal;
|
||||||
|
|
||||||
private Collection<GrantedAuthority> authorities;
|
private @Nullable Collection<GrantedAuthority> authorities;
|
||||||
|
|
||||||
private OidcLoginRequestPostProcessor(OAuth2AccessToken accessToken) {
|
private OidcLoginRequestPostProcessor(OAuth2AccessToken accessToken) {
|
||||||
this.accessToken = accessToken;
|
this.accessToken = accessToken;
|
||||||
@ -1525,6 +1534,7 @@ public final class SecurityMockMvcRequestPostProcessors {
|
|||||||
return authorities;
|
return authorities;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NullUnmarked
|
||||||
private OidcIdToken getOidcIdToken() {
|
private OidcIdToken getOidcIdToken() {
|
||||||
if (this.idToken != null) {
|
if (this.idToken != null) {
|
||||||
return this.idToken;
|
return this.idToken;
|
||||||
@ -1546,11 +1556,12 @@ public final class SecurityMockMvcRequestPostProcessors {
|
|||||||
* @author Josh Cummings
|
* @author Josh Cummings
|
||||||
* @since 5.3
|
* @since 5.3
|
||||||
*/
|
*/
|
||||||
|
@NullUnmarked
|
||||||
public static final class OAuth2ClientRequestPostProcessor implements RequestPostProcessor {
|
public static final class OAuth2ClientRequestPostProcessor implements RequestPostProcessor {
|
||||||
|
|
||||||
private String registrationId = "test";
|
private String registrationId = "test";
|
||||||
|
|
||||||
private ClientRegistration clientRegistration;
|
private @Nullable ClientRegistration clientRegistration;
|
||||||
|
|
||||||
private String principalName = "user";
|
private String principalName = "user";
|
||||||
|
|
||||||
@ -1610,6 +1621,7 @@ public final class SecurityMockMvcRequestPostProcessors {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NullUnmarked
|
||||||
@Override
|
@Override
|
||||||
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
|
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
|
||||||
if (this.clientRegistration == null) {
|
if (this.clientRegistration == null) {
|
||||||
@ -1650,14 +1662,15 @@ public final class SecurityMockMvcRequestPostProcessors {
|
|||||||
|
|
||||||
private final OAuth2AuthorizedClientManager delegate;
|
private final OAuth2AuthorizedClientManager delegate;
|
||||||
|
|
||||||
private OAuth2AuthorizedClientRepository authorizedClientRepository;
|
private @Nullable OAuth2AuthorizedClientRepository authorizedClientRepository;
|
||||||
|
|
||||||
TestOAuth2AuthorizedClientManager(OAuth2AuthorizedClientManager delegate) {
|
TestOAuth2AuthorizedClientManager(OAuth2AuthorizedClientManager delegate) {
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NullUnmarked
|
||||||
@Override
|
@Override
|
||||||
public OAuth2AuthorizedClient authorize(OAuth2AuthorizeRequest authorizeRequest) {
|
public @Nullable OAuth2AuthorizedClient authorize(OAuth2AuthorizeRequest authorizeRequest) {
|
||||||
HttpServletRequest request = authorizeRequest.getAttribute(HttpServletRequest.class.getName());
|
HttpServletRequest request = authorizeRequest.getAttribute(HttpServletRequest.class.getName());
|
||||||
if (isEnabled(request)) {
|
if (isEnabled(request)) {
|
||||||
return this.authorizedClientRepository.loadAuthorizedClient(
|
return this.authorizedClientRepository.loadAuthorizedClient(
|
||||||
@ -1670,7 +1683,8 @@ public final class SecurityMockMvcRequestPostProcessors {
|
|||||||
request.setAttribute(ENABLED_ATTR_NAME, Boolean.TRUE);
|
request.setAttribute(ENABLED_ATTR_NAME, Boolean.TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isEnabled(HttpServletRequest request) {
|
@NullUnmarked
|
||||||
|
boolean isEnabled(@Nullable HttpServletRequest request) {
|
||||||
return Boolean.TRUE.equals(request.getAttribute(ENABLED_ATTR_NAME));
|
return Boolean.TRUE.equals(request.getAttribute(ENABLED_ATTR_NAME));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1689,7 +1703,8 @@ public final class SecurityMockMvcRequestPostProcessors {
|
|||||||
|
|
||||||
private final OAuth2AuthorizedClientRepository delegate;
|
private final OAuth2AuthorizedClientRepository delegate;
|
||||||
|
|
||||||
TestOAuth2AuthorizedClientRepository(OAuth2AuthorizedClientRepository delegate) {
|
@NullUnmarked
|
||||||
|
TestOAuth2AuthorizedClientRepository(@Nullable OAuth2AuthorizedClientRepository delegate) {
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1748,7 +1763,8 @@ public final class SecurityMockMvcRequestPostProcessors {
|
|||||||
* @return the {@link OAuth2AuthorizedClientManager} for the specified
|
* @return the {@link OAuth2AuthorizedClientManager} for the specified
|
||||||
* {@link HttpServletRequest}
|
* {@link HttpServletRequest}
|
||||||
*/
|
*/
|
||||||
static OAuth2AuthorizedClientRepository getAuthorizedClientRepository(HttpServletRequest request) {
|
static @Nullable OAuth2AuthorizedClientRepository getAuthorizedClientRepository(
|
||||||
|
HttpServletRequest request) {
|
||||||
OAuth2AuthorizedClientManager manager = getOAuth2AuthorizedClientManager(request);
|
OAuth2AuthorizedClientManager manager = getOAuth2AuthorizedClientManager(request);
|
||||||
if (manager == null) {
|
if (manager == null) {
|
||||||
return DEFAULT_CLIENT_REPO;
|
return DEFAULT_CLIENT_REPO;
|
||||||
@ -1781,7 +1797,8 @@ public final class SecurityMockMvcRequestPostProcessors {
|
|||||||
((TestOAuth2AuthorizedClientManager) manager).authorizedClientRepository = repository;
|
((TestOAuth2AuthorizedClientManager) manager).authorizedClientRepository = repository;
|
||||||
}
|
}
|
||||||
|
|
||||||
static OAuth2AuthorizedClientManager getOAuth2AuthorizedClientManager(HttpServletRequest request) {
|
static @Nullable OAuth2AuthorizedClientManager getOAuth2AuthorizedClientManager(
|
||||||
|
HttpServletRequest request) {
|
||||||
OAuth2AuthorizedClientArgumentResolver resolver = findResolver(request,
|
OAuth2AuthorizedClientArgumentResolver resolver = findResolver(request,
|
||||||
OAuth2AuthorizedClientArgumentResolver.class);
|
OAuth2AuthorizedClientArgumentResolver.class);
|
||||||
if (resolver == null) {
|
if (resolver == null) {
|
||||||
@ -1809,7 +1826,7 @@ public final class SecurityMockMvcRequestPostProcessors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
static <T extends HandlerMethodArgumentResolver> T findResolver(HttpServletRequest request,
|
static <T extends HandlerMethodArgumentResolver> @Nullable T findResolver(HttpServletRequest request,
|
||||||
Class<T> resolverClass) {
|
Class<T> resolverClass) {
|
||||||
if (!ClassUtils.isPresent(
|
if (!ClassUtils.isPresent(
|
||||||
"org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter", null)) {
|
"org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter", null)) {
|
||||||
@ -1820,7 +1837,7 @@ public final class SecurityMockMvcRequestPostProcessors {
|
|||||||
|
|
||||||
private static class WebMvcClasspathGuard {
|
private static class WebMvcClasspathGuard {
|
||||||
|
|
||||||
static <T extends HandlerMethodArgumentResolver> T findResolver(HttpServletRequest request,
|
static <T extends HandlerMethodArgumentResolver> @Nullable T findResolver(HttpServletRequest request,
|
||||||
Class<T> resolverClass) {
|
Class<T> resolverClass) {
|
||||||
ServletContext servletContext = request.getServletContext();
|
ServletContext servletContext = request.getServletContext();
|
||||||
RequestMappingHandlerAdapter mapping = getRequestMappingHandlerAdapter(servletContext);
|
RequestMappingHandlerAdapter mapping = getRequestMappingHandlerAdapter(servletContext);
|
||||||
@ -1839,7 +1856,7 @@ public final class SecurityMockMvcRequestPostProcessors {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static RequestMappingHandlerAdapter getRequestMappingHandlerAdapter(
|
private static @Nullable RequestMappingHandlerAdapter getRequestMappingHandlerAdapter(
|
||||||
ServletContext servletContext) {
|
ServletContext servletContext) {
|
||||||
WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);
|
WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2004-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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spring Security built-in org.springframework.test.web.servlet.RequestBuilder
|
||||||
|
* implementations.
|
||||||
|
*/
|
||||||
|
@NullMarked
|
||||||
|
package org.springframework.security.test.web.servlet.request;
|
||||||
|
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
@ -20,6 +20,9 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.jspecify.annotations.NullUnmarked;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
||||||
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
|
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
@ -81,21 +84,22 @@ public final class SecurityMockMvcResultMatchers {
|
|||||||
*/
|
*/
|
||||||
public static final class AuthenticatedMatcher extends AuthenticationMatcher<AuthenticatedMatcher> {
|
public static final class AuthenticatedMatcher extends AuthenticationMatcher<AuthenticatedMatcher> {
|
||||||
|
|
||||||
private SecurityContext expectedContext;
|
private @Nullable SecurityContext expectedContext;
|
||||||
|
|
||||||
private Authentication expectedAuthentication;
|
private @Nullable Authentication expectedAuthentication;
|
||||||
|
|
||||||
private Object expectedAuthenticationPrincipal;
|
private @Nullable Object expectedAuthenticationPrincipal;
|
||||||
|
|
||||||
private String expectedAuthenticationName;
|
private @Nullable String expectedAuthenticationName;
|
||||||
|
|
||||||
private Collection<? extends GrantedAuthority> expectedGrantedAuthorities;
|
private @Nullable Collection<? extends GrantedAuthority> expectedGrantedAuthorities;
|
||||||
|
|
||||||
private Consumer<Authentication> assertAuthentication;
|
private @Nullable Consumer<Authentication> assertAuthentication;
|
||||||
|
|
||||||
AuthenticatedMatcher() {
|
AuthenticatedMatcher() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NullUnmarked
|
||||||
@Override
|
@Override
|
||||||
public void match(MvcResult result) {
|
public void match(MvcResult result) {
|
||||||
SecurityContext context = load(result);
|
SecurityContext context = load(result);
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2004-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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spring Security server-side support for testing Spring MVC applications.
|
||||||
|
*/
|
||||||
|
@NullMarked
|
||||||
|
package org.springframework.security.test.web.servlet.response;
|
||||||
|
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
@ -24,6 +24,7 @@ import jakarta.servlet.FilterConfig;
|
|||||||
import jakarta.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import jakarta.servlet.ServletRequest;
|
import jakarta.servlet.ServletRequest;
|
||||||
import jakarta.servlet.ServletResponse;
|
import jakarta.servlet.ServletResponse;
|
||||||
|
import org.jspecify.annotations.NullUnmarked;
|
||||||
|
|
||||||
import org.springframework.security.config.BeanIds;
|
import org.springframework.security.config.BeanIds;
|
||||||
import org.springframework.test.web.servlet.request.RequestPostProcessor;
|
import org.springframework.test.web.servlet.request.RequestPostProcessor;
|
||||||
@ -66,6 +67,7 @@ final class SecurityMockMvcConfigurer extends MockMvcConfigurerAdapter {
|
|||||||
builder.addFilters(this.delegateFilter);
|
builder.addFilters(this.delegateFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NullUnmarked
|
||||||
@Override
|
@Override
|
||||||
public RequestPostProcessor beforeMockMvcCreated(ConfigurableMockMvcBuilder<?> builder,
|
public RequestPostProcessor beforeMockMvcCreated(ConfigurableMockMvcBuilder<?> builder,
|
||||||
WebApplicationContext context) {
|
WebApplicationContext context) {
|
||||||
@ -100,6 +102,7 @@ final class SecurityMockMvcConfigurer extends MockMvcConfigurerAdapter {
|
|||||||
*/
|
*/
|
||||||
static class DelegateFilter implements Filter {
|
static class DelegateFilter implements Filter {
|
||||||
|
|
||||||
|
@SuppressWarnings("NullAway.Init")
|
||||||
private Filter delegate;
|
private Filter delegate;
|
||||||
|
|
||||||
DelegateFilter() {
|
DelegateFilter() {
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2004-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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spring Security built-in MockMvcBuilder implementations.
|
||||||
|
*/
|
||||||
|
@NullMarked
|
||||||
|
package org.springframework.security.test.web.servlet.setup;
|
||||||
|
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
@ -21,6 +21,8 @@ import java.util.List;
|
|||||||
import jakarta.servlet.Filter;
|
import jakarta.servlet.Filter;
|
||||||
import jakarta.servlet.ServletContext;
|
import jakarta.servlet.ServletContext;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import org.jspecify.annotations.NullUnmarked;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||||
import org.springframework.security.config.BeanIds;
|
import org.springframework.security.config.BeanIds;
|
||||||
@ -64,6 +66,7 @@ public abstract class WebTestUtils {
|
|||||||
* @return the {@link SecurityContextRepository} for the specified
|
* @return the {@link SecurityContextRepository} for the specified
|
||||||
* {@link HttpServletRequest}
|
* {@link HttpServletRequest}
|
||||||
*/
|
*/
|
||||||
|
@NullUnmarked
|
||||||
public static SecurityContextRepository getSecurityContextRepository(HttpServletRequest request) {
|
public static SecurityContextRepository getSecurityContextRepository(HttpServletRequest request) {
|
||||||
SecurityContextPersistenceFilter filter = findFilter(request, SecurityContextPersistenceFilter.class);
|
SecurityContextPersistenceFilter filter = findFilter(request, SecurityContextPersistenceFilter.class);
|
||||||
if (filter != null) {
|
if (filter != null) {
|
||||||
@ -103,7 +106,7 @@ public abstract class WebTestUtils {
|
|||||||
* @return the {@link CsrfTokenRepository} for the specified
|
* @return the {@link CsrfTokenRepository} for the specified
|
||||||
* {@link HttpServletRequest}
|
* {@link HttpServletRequest}
|
||||||
*/
|
*/
|
||||||
public static CsrfTokenRepository getCsrfTokenRepository(HttpServletRequest request) {
|
public static @Nullable CsrfTokenRepository getCsrfTokenRepository(HttpServletRequest request) {
|
||||||
CsrfFilter filter = findFilter(request, CsrfFilter.class);
|
CsrfFilter filter = findFilter(request, CsrfFilter.class);
|
||||||
if (filter == null) {
|
if (filter == null) {
|
||||||
return DEFAULT_TOKEN_REPO;
|
return DEFAULT_TOKEN_REPO;
|
||||||
@ -120,7 +123,7 @@ public abstract class WebTestUtils {
|
|||||||
* @return the {@link CsrfTokenRequestHandler} for the specified
|
* @return the {@link CsrfTokenRequestHandler} for the specified
|
||||||
* {@link HttpServletRequest}
|
* {@link HttpServletRequest}
|
||||||
*/
|
*/
|
||||||
public static CsrfTokenRequestHandler getCsrfTokenRequestHandler(HttpServletRequest request) {
|
public static @Nullable CsrfTokenRequestHandler getCsrfTokenRequestHandler(HttpServletRequest request) {
|
||||||
CsrfFilter filter = findFilter(request, CsrfFilter.class);
|
CsrfFilter filter = findFilter(request, CsrfFilter.class);
|
||||||
if (filter == null) {
|
if (filter == null) {
|
||||||
return DEFAULT_CSRF_HANDLER;
|
return DEFAULT_CSRF_HANDLER;
|
||||||
@ -142,7 +145,7 @@ public abstract class WebTestUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
static <T extends Filter> T findFilter(HttpServletRequest request, Class<T> filterClass) {
|
static <T extends Filter> @Nullable T findFilter(HttpServletRequest request, Class<T> filterClass) {
|
||||||
ServletContext servletContext = request.getServletContext();
|
ServletContext servletContext = request.getServletContext();
|
||||||
Filter springSecurityFilterChain = getSpringSecurityFilterChain(servletContext);
|
Filter springSecurityFilterChain = getSpringSecurityFilterChain(servletContext);
|
||||||
if (springSecurityFilterChain == null) {
|
if (springSecurityFilterChain == null) {
|
||||||
@ -160,7 +163,7 @@ public abstract class WebTestUtils {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Filter getSpringSecurityFilterChain(ServletContext servletContext) {
|
private static @Nullable Filter getSpringSecurityFilterChain(ServletContext servletContext) {
|
||||||
Filter result = (Filter) servletContext.getAttribute(BeanIds.SPRING_SECURITY_FILTER_CHAIN);
|
Filter result = (Filter) servletContext.getAttribute(BeanIds.SPRING_SECURITY_FILTER_CHAIN);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
return result;
|
return result;
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2004-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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spring Security supporting the org.springframework.web.context package, such as
|
||||||
|
* WebApplicationContext implementations and various utility classes.
|
||||||
|
*/
|
||||||
|
@NullMarked
|
||||||
|
package org.springframework.security.test.web.support;
|
||||||
|
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
Loading…
x
Reference in New Issue
Block a user