Enable Null checking in spring-security-web via JSpecify

Closes gh-17535
This commit is contained in:
Rob Winch 2025-08-21 14:02:17 -05:00
parent 49f308adb0
commit c2ba662b91
No known key found for this signature in database
261 changed files with 1782 additions and 537 deletions

View File

@ -367,7 +367,7 @@ class HttpSecurityDslTests {
this.spring.register(CustomFilterConfig::class.java).autowire()
val filterChain = spring.context.getBean(FilterChainProxy::class.java)
val filters: List<Filter> = filterChain.getFilters("/")
val filters: List<Filter>? = filterChain.getFilters("/")
assertThat(filters).anyMatch { it is CustomFilter }
}
@ -390,7 +390,7 @@ class HttpSecurityDslTests {
this.spring.register(CustomFilterConfigReified::class.java).autowire()
val filterChain = spring.context.getBean(FilterChainProxy::class.java)
val filters: List<Filter> = filterChain.getFilters("/")
val filters: List<Filter>? = filterChain.getFilters("/")
assertThat(filters).anyMatch { it is CustomFilter }
}
@ -413,7 +413,7 @@ class HttpSecurityDslTests {
this.spring.register(CustomFilterAfterConfig::class.java).autowire()
val filterChain = spring.context.getBean(FilterChainProxy::class.java)
val filters: List<Class<out Filter>> = filterChain.getFilters("/").map { it.javaClass }
val filters: List<Class<out Filter>> = filterChain.getFilters("/")!!.map { it.javaClass }
assertThat(filters).containsSubsequence(
UsernamePasswordAuthenticationFilter::class.java,
@ -440,7 +440,7 @@ class HttpSecurityDslTests {
this.spring.register(CustomFilterAfterConfigReified::class.java).autowire()
val filterChain = spring.context.getBean(FilterChainProxy::class.java)
val filterClasses: List<Class<out Filter>> = filterChain.getFilters("/").map { it.javaClass }
val filterClasses: List<Class<out Filter>> = filterChain.getFilters("/")!!.map { it.javaClass }
assertThat(filterClasses).containsSubsequence(
UsernamePasswordAuthenticationFilter::class.java,
@ -467,7 +467,7 @@ class HttpSecurityDslTests {
this.spring.register(CustomFilterBeforeConfig::class.java).autowire()
val filterChain = spring.context.getBean(FilterChainProxy::class.java)
val filters: List<Class<out Filter>> = filterChain.getFilters("/").map { it.javaClass }
val filters: List<Class<out Filter>> = filterChain.getFilters("/")!!.map { it.javaClass }
assertThat(filters).containsSubsequence(
CustomFilter::class.java,
@ -494,7 +494,7 @@ class HttpSecurityDslTests {
this.spring.register(CustomFilterBeforeConfigReified::class.java).autowire()
val filterChain = spring.context.getBean(FilterChainProxy::class.java)
val filterClasses: List<Class<out Filter>> = filterChain.getFilters("/").map { it.javaClass }
val filterClasses: List<Class<out Filter>> = filterChain.getFilters("/")!!.map { it.javaClass }
assertThat(filterClasses).containsSubsequence(
CustomFilter::class.java,
@ -523,7 +523,7 @@ class HttpSecurityDslTests {
this.spring.register(CustomSecurityConfigurerConfig::class.java).autowire()
val filterChain = spring.context.getBean(FilterChainProxy::class.java)
val filterClasses: List<Class<out Filter>> = filterChain.getFilters("/").map { it.javaClass }
val filterClasses: List<Class<out Filter>> = filterChain.getFilters("/")!!.map { it.javaClass }
assertThat(filterClasses).contains(
CustomFilter::class.java
@ -535,7 +535,7 @@ class HttpSecurityDslTests {
this.spring.register(CustomSecurityConfigurerConfig::class.java).autowire()
val filterChain = spring.context.getBean(FilterChainProxy::class.java)
val filterClasses: List<Class<out Filter>> = filterChain.getFilters("/").map { it.javaClass }
val filterClasses: List<Class<out Filter>> = filterChain.getFilters("/")!!.map { it.javaClass }
assertThat(filterClasses).contains(
CustomFilter::class.java
@ -588,7 +588,7 @@ class HttpSecurityDslTests {
this.spring.register(CustomDslUsingWithConfig::class.java).autowire()
val filterChain = spring.context.getBean(FilterChainProxy::class.java)
val filterClasses: List<Class<out Filter>> = filterChain.getFilters("/").map { it.javaClass }
val filterClasses: List<Class<out Filter>> = filterChain.getFilters("/")!!.map { it.javaClass }
assertThat(filterClasses).contains(
UsernamePasswordAuthenticationFilter::class.java

View File

@ -350,8 +350,8 @@ class LogoutDslTests {
class NoopLogoutHandler: LogoutHandler {
override fun logout(
request: HttpServletRequest?,
response: HttpServletResponse?,
request: HttpServletRequest,
response: HttpServletResponse,
authentication: Authentication?
) { }

View File

@ -132,8 +132,8 @@ class RequiresChannelDslTests {
companion object {
val CHANNEL_PROCESSOR: ChannelProcessor = object : ChannelProcessor {
override fun decide(invocation: FilterInvocation?, config: MutableCollection<ConfigAttribute>?) {}
override fun supports(attribute: ConfigAttribute?): Boolean = true
override fun decide(invocation: FilterInvocation, config: MutableCollection<ConfigAttribute>) {}
override fun supports(attribute: ConfigAttribute): Boolean = true
}
}

View File

@ -93,7 +93,7 @@ class SecurityContextDslTests {
testContext.autowire()
val filterChainProxy = testContext.context.getBean(FilterChainProxy::class.java)
// @formatter:off
val filterTypes = filterChainProxy.getFilters("/").toList()
val filterTypes = filterChainProxy.getFilters("/")!!.toList()
assertThat(filterTypes)
.anyMatch { it is SecurityContextHolderFilter }

View File

@ -270,8 +270,8 @@ class ServerHttpBasicDslTests {
open class MockServerAuthenticationFailureHandler: ServerAuthenticationFailureHandler {
override fun onAuthenticationFailure(
webFilterExchange: WebFilterExchange?,
exception: AuthenticationException?
webFilterExchange: WebFilterExchange,
exception: AuthenticationException
): Mono<Void> {
return Mono.empty()
}

View File

@ -18,6 +18,8 @@ package org.springframework.security.access;
import java.io.Serializable;
import org.jspecify.annotations.NullUnmarked;
import org.springframework.security.access.intercept.RunAsManager;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.annotation.SecurityAnnotationScanner;
@ -45,6 +47,7 @@ import org.springframework.security.core.annotation.SecurityAnnotationScanner;
* {@link AuthorizationManager}.
*/
@Deprecated
@NullUnmarked
public interface ConfigAttribute extends Serializable {
/**

View File

@ -177,7 +177,7 @@ public abstract class SecurityExpressionRoot implements SecurityExpressionOperat
this.trustResolver = trustResolver;
}
public void setRoleHierarchy(RoleHierarchy roleHierarchy) {
public void setRoleHierarchy(@Nullable RoleHierarchy roleHierarchy) {
this.roleHierarchy = roleHierarchy;
}

View File

@ -85,6 +85,7 @@ public class DefaultMethodSecurityExpressionHandler extends AbstractSecurityExpr
}
@Override
@SuppressWarnings("NullAway") // FIXME: Dataflow analysis limitation
public EvaluationContext createEvaluationContext(Supplier<? extends @Nullable Authentication> authentication,
MethodInvocation mi) {
MethodSecurityExpressionOperations root = createSecurityExpressionRoot(authentication, mi);

View File

@ -18,6 +18,8 @@ package org.springframework.security.access.vote;
import java.util.Collection;
import org.jspecify.annotations.NullUnmarked;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.core.Authentication;
@ -53,6 +55,7 @@ import org.springframework.security.core.GrantedAuthority;
* instead
*/
@Deprecated
@NullUnmarked
public class RoleVoter implements AccessDecisionVoter<Object> {
private String rolePrefix = "ROLE_";

View File

@ -18,6 +18,7 @@ package org.springframework.security.authentication;
import org.jspecify.annotations.Nullable;
import org.springframework.lang.Contract;
import org.springframework.security.core.Authentication;
/**
@ -80,6 +81,7 @@ public interface AuthenticationTrustResolver {
* {@link Authentication#isAuthenticated()} is true.
* @since 6.1.7
*/
@Contract("null -> false")
default boolean isAuthenticated(@Nullable Authentication authentication) {
return authentication != null && authentication.isAuthenticated() && !isAnonymous(authentication);
}

View File

@ -39,7 +39,7 @@ public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationT
private static final long serialVersionUID = 620L;
private final Object principal;
private final @Nullable Object principal;
private @Nullable Object credentials;
@ -49,7 +49,7 @@ public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationT
* will return <code>false</code>.
*
*/
public UsernamePasswordAuthenticationToken(Object principal, @Nullable Object credentials) {
public UsernamePasswordAuthenticationToken(@Nullable Object principal, @Nullable Object credentials) {
super(null);
this.principal = principal;
this.credentials = credentials;
@ -82,7 +82,8 @@ public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationT
*
* @since 5.7
*/
public static UsernamePasswordAuthenticationToken unauthenticated(Object principal, @Nullable Object credentials) {
public static UsernamePasswordAuthenticationToken unauthenticated(@Nullable Object principal,
@Nullable Object credentials) {
return new UsernamePasswordAuthenticationToken(principal, credentials);
}
@ -106,7 +107,7 @@ public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationT
}
@Override
public Object getPrincipal() {
public @Nullable Object getPrincipal() {
return this.principal;
}

View File

@ -178,8 +178,10 @@ public abstract class AbstractJaasAuthenticationProvider implements Authenticati
// applied.
authorities = getAuthorities(principals);
// Convert the authorities set back to an array and apply it to the token.
JaasAuthenticationToken result = new JaasAuthenticationToken(request.getPrincipal(),
request.getCredentials(), new ArrayList<>(authorities), loginContext);
Object principal = request.getPrincipal();
Assert.notNull(principal, "The principal cannot be null");
JaasAuthenticationToken result = new JaasAuthenticationToken(principal, request.getCredentials(),
new ArrayList<>(authorities), loginContext);
// Publish the success event
publishSuccessEvent(result);
// we're done, return the token.

View File

@ -71,8 +71,8 @@ public class OneTimeTokenAuthenticationToken extends AbstractAuthenticationToken
* @deprecated Please use constructor that takes a {@link String} instead
*/
@Deprecated(forRemoval = true, since = "7.0")
public static OneTimeTokenAuthenticationToken unauthenticated(String tokenValue) {
return new OneTimeTokenAuthenticationToken(null, tokenValue);
public static OneTimeTokenAuthenticationToken unauthenticated(@Nullable String tokenValue) {
return new OneTimeTokenAuthenticationToken(null, (tokenValue != null) ? tokenValue : "");
}
/**

View File

@ -18,6 +18,8 @@ package org.springframework.security.authorization;
import java.util.function.Supplier;
import org.jspecify.annotations.Nullable;
import org.springframework.security.authorization.event.AuthorizationDeniedEvent;
import org.springframework.security.authorization.event.AuthorizationGrantedEvent;
import org.springframework.security.core.Authentication;
@ -46,6 +48,7 @@ public interface AuthorizationEventPublisher {
* @param <T> the secured object's type
* @since 6.4
*/
<T> void publishAuthorizationEvent(Supplier<Authentication> authentication, T object, AuthorizationResult result);
<T> void publishAuthorizationEvent(Supplier<Authentication> authentication, T object,
@Nullable AuthorizationResult result);
}

View File

@ -19,6 +19,8 @@ package org.springframework.security.authorization;
import java.util.function.Predicate;
import java.util.function.Supplier;
import org.jspecify.annotations.Nullable;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.security.authorization.event.AuthorizationDeniedEvent;
import org.springframework.security.authorization.event.AuthorizationGrantedEvent;
@ -57,7 +59,7 @@ public final class SpringAuthorizationEventPublisher implements AuthorizationEve
*/
@Override
public <T> void publishAuthorizationEvent(Supplier<Authentication> authentication, T object,
AuthorizationResult result) {
@Nullable AuthorizationResult result) {
if (result == null) {
return;
}

View File

@ -74,6 +74,7 @@ public final class MethodExpressionAuthorizationManager implements Authorization
* expression
*/
@Override
@SuppressWarnings("NullAway") // FIXME: Dataflow analysis limitation
public AuthorizationResult authorize(Supplier<? extends @Nullable Authentication> authentication,
MethodInvocation context) {
EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication, context);

View File

@ -18,6 +18,8 @@ package org.springframework.security.authorization.method;
import java.util.function.Supplier;
import org.jspecify.annotations.Nullable;
import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationResult;
import org.springframework.security.core.Authentication;
@ -32,7 +34,7 @@ final class NoOpAuthorizationEventPublisher implements AuthorizationEventPublish
@Override
public <T> void publishAuthorizationEvent(Supplier<Authentication> authentication, T object,
AuthorizationResult result) {
@Nullable AuthorizationResult result) {
}

View File

@ -76,7 +76,7 @@ public abstract class AuthenticationException extends RuntimeException {
* authentication attempt
* @since 6.5
*/
public void setAuthenticationRequest(Authentication authenticationRequest) {
public void setAuthenticationRequest(@Nullable Authentication authenticationRequest) {
Assert.notNull(authenticationRequest, "authenticationRequest cannot be null");
this.authenticationRequest = authenticationRequest;
}

View File

@ -1,3 +1,7 @@
plugins {
id 'security-nullability'
}
apply plugin: 'io.spring.convention.spring-module'
configurations {

View File

@ -24,6 +24,7 @@ import jakarta.servlet.Filter;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
@ -51,9 +52,9 @@ public final class DefaultSecurityFilterChain implements SecurityFilterChain, Be
private final List<Filter> filters;
private String beanName;
private @Nullable String beanName;
private ConfigurableListableBeanFactory beanFactory;
private @Nullable ConfigurableListableBeanFactory beanFactory;
public DefaultSecurityFilterChain(RequestMatcher requestMatcher, Filter... filters) {
this(requestMatcher, Arrays.asList(filters));

View File

@ -30,6 +30,7 @@ import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.core.log.LogMessage;
import org.springframework.security.core.context.SecurityContextHolder;
@ -164,6 +165,7 @@ public class FilterChainProxy extends GenericFilterBean {
private FilterChainDecorator filterChainDecorator = new VirtualFilterChainDecorator();
public FilterChainProxy() {
this(Collections.emptyList());
}
public FilterChainProxy(SecurityFilterChain chain) {
@ -171,6 +173,7 @@ public class FilterChainProxy extends GenericFilterBean {
}
public FilterChainProxy(List<SecurityFilterChain> filterChains) {
Assert.notNull(filterChains, "filterChains cannot be null");
this.filterChains = filterChains;
}
@ -239,7 +242,7 @@ public class FilterChainProxy extends GenericFilterBean {
* @param request the request to match
* @return an ordered array of Filters defining the filter chain
*/
private List<Filter> getFilters(HttpServletRequest request) {
private @Nullable List<Filter> getFilters(HttpServletRequest request) {
int count = 0;
for (SecurityFilterChain chain : this.filterChains) {
if (logger.isTraceEnabled()) {
@ -258,7 +261,7 @@ public class FilterChainProxy extends GenericFilterBean {
* @param url the URL
* @return matching filter list
*/
public List<Filter> getFilters(String url) {
public @Nullable List<Filter> getFilters(String url) {
PathPatternRequestTransformer requestTransformer = new PathPatternRequestTransformer();
HttpServletRequest transformed = requestTransformer.transform(new FilterInvocation(url, "GET").getRequest());
return getFilters(this.firewall.getFirewalledRequest(transformed));

View File

@ -36,6 +36,7 @@ import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.http.HttpHeaders;
import org.springframework.security.web.util.UrlUtils;
@ -62,11 +63,11 @@ public class FilterInvocation {
throw new UnsupportedOperationException("Dummy filter chain");
};
private FilterChain chain;
private final FilterChain chain;
private HttpServletRequest request;
private HttpServletResponse response;
private @Nullable HttpServletResponse response;
public FilterInvocation(ServletRequest request, ServletResponse response, FilterChain chain) {
Assert.isTrue(request != null && response != null && chain != null, "Cannot pass null values to constructor");
@ -79,11 +80,12 @@ public class FilterInvocation {
this(null, servletPath, method);
}
public FilterInvocation(String contextPath, String servletPath, String method) {
public FilterInvocation(@Nullable String contextPath, String servletPath, String method) {
this(contextPath, servletPath, method, null);
}
public FilterInvocation(String contextPath, String servletPath, String method, ServletContext servletContext) {
public FilterInvocation(@Nullable String contextPath, String servletPath, @Nullable String method,
@Nullable ServletContext servletContext) {
this(contextPath, servletPath, null, null, method, servletContext);
}
@ -91,8 +93,8 @@ public class FilterInvocation {
this(contextPath, servletPath, pathInfo, query, method, null);
}
public FilterInvocation(String contextPath, String servletPath, String pathInfo, String query, String method,
ServletContext servletContext) {
public FilterInvocation(@Nullable String contextPath, String servletPath, @Nullable String pathInfo,
@Nullable String query, @Nullable String method, @Nullable ServletContext servletContext) {
DummyRequest request = new DummyRequest();
contextPath = (contextPath != null) ? contextPath : "/cp";
request.setContextPath(contextPath);
@ -103,6 +105,7 @@ public class FilterInvocation {
request.setMethod(method);
request.setServletContext(servletContext);
this.request = request;
this.chain = DUMMY_CHAIN;
}
public FilterChain getChain() {
@ -124,7 +127,7 @@ public class FilterInvocation {
return this.request;
}
public HttpServletResponse getHttpResponse() {
public @Nullable HttpServletResponse getHttpResponse() {
return this.response;
}
@ -140,7 +143,7 @@ public class FilterInvocation {
return getHttpRequest();
}
public HttpServletResponse getResponse() {
public @Nullable HttpServletResponse getResponse() {
return getHttpResponse();
}
@ -160,19 +163,19 @@ public class FilterInvocation {
DummyRequest.class.getClassLoader(), new Class[] { HttpServletRequest.class },
new UnsupportedOperationExceptionInvocationHandler());
private String requestURI;
private @Nullable String requestURI;
private String contextPath = "";
private String servletPath;
private @Nullable String servletPath;
private String pathInfo;
private @Nullable String pathInfo;
private String queryString;
private @Nullable String queryString;
private String method;
private @Nullable String method;
private ServletContext servletContext;
private @Nullable ServletContext servletContext;
private final HttpHeaders headers = new HttpHeaders();
@ -188,7 +191,7 @@ public class FilterInvocation {
}
@Override
public Object getAttribute(String attributeName) {
public @Nullable Object getAttribute(String attributeName) {
return null;
}
@ -196,12 +199,12 @@ public class FilterInvocation {
this.requestURI = requestURI;
}
void setPathInfo(String pathInfo) {
void setPathInfo(@Nullable String pathInfo) {
this.pathInfo = pathInfo;
}
@Override
public String getRequestURI() {
public @Nullable String getRequestURI() {
return this.requestURI;
}
@ -219,40 +222,40 @@ public class FilterInvocation {
}
@Override
public String getServletPath() {
public @Nullable String getServletPath() {
return this.servletPath;
}
void setMethod(String method) {
void setMethod(@Nullable String method) {
this.method = method;
}
@Override
public String getMethod() {
public @Nullable String getMethod() {
return this.method;
}
@Override
public String getPathInfo() {
public @Nullable String getPathInfo() {
return this.pathInfo;
}
@Override
public String getQueryString() {
public @Nullable String getQueryString() {
return this.queryString;
}
void setQueryString(String queryString) {
void setQueryString(@Nullable String queryString) {
this.queryString = queryString;
}
@Override
public String getServerName() {
public @Nullable String getServerName() {
return null;
}
@Override
public String getHeader(String name) {
public @Nullable String getHeader(String name) {
return this.headers.getFirst(name);
}
@ -284,7 +287,7 @@ public class FilterInvocation {
}
@Override
public String getParameter(String name) {
public @Nullable String getParameter(String name) {
String[] array = this.parameters.get(name);
return (array != null && array.length > 0) ? array[0] : null;
}
@ -300,7 +303,7 @@ public class FilterInvocation {
}
@Override
public String[] getParameterValues(String name) {
public String @Nullable [] getParameterValues(String name) {
return this.parameters.get(name);
}
@ -309,11 +312,11 @@ public class FilterInvocation {
}
@Override
public ServletContext getServletContext() {
public @Nullable ServletContext getServletContext() {
return this.servletContext;
}
void setServletContext(ServletContext servletContext) {
void setServletContext(@Nullable ServletContext servletContext) {
this.servletContext = servletContext;
}

View File

@ -37,6 +37,8 @@ import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import org.springframework.core.log.LogMessage;
import org.springframework.util.StringUtils;
@ -49,6 +51,7 @@ import org.springframework.util.StringUtils;
* @author Nikita Konev
* @since 6.0
*/
@NullUnmarked // https://github.com/spring-projects/spring-security/issues/17815
public final class ObservationFilterChainDecorator implements FilterChainProxy.FilterChainDecorator {
private static final Log logger = LogFactory.getLog(FilterChainProxy.class);
@ -507,7 +510,7 @@ public final class ObservationFilterChainDecorator implements FilterChainProxy.F
private final String filterSection;
private String filterName;
private @Nullable String filterName;
private int chainPosition;
@ -530,7 +533,7 @@ public final class ObservationFilterChainDecorator implements FilterChainProxy.F
return this.filterSection;
}
String getFilterName() {
@Nullable String getFilterName() {
return this.filterName;
}

View File

@ -16,6 +16,8 @@
package org.springframework.security.web;
import org.jspecify.annotations.Nullable;
/**
* <code>PortMapper</code> implementations provide callers with information about which
* HTTP ports are associated with which HTTPS ports on the system, and vice versa.
@ -32,7 +34,7 @@ public interface PortMapper {
* @param httpsPort
* @return the HTTP port or <code>null</code> if unknown
*/
Integer lookupHttpPort(Integer httpsPort);
@Nullable Integer lookupHttpPort(Integer httpsPort);
/**
* Locates the HTTPS port associated with the specified HTTP port.
@ -42,6 +44,6 @@ public interface PortMapper {
* @param httpPort
* @return the HTTPS port or <code>null</code> if unknown
*/
Integer lookupHttpsPort(Integer httpPort);
@Nullable Integer lookupHttpsPort(Integer httpPort);
}

View File

@ -19,6 +19,8 @@ package org.springframework.security.web;
import java.util.HashMap;
import java.util.Map;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
/**
@ -50,7 +52,7 @@ public class PortMapperImpl implements PortMapper {
}
@Override
public Integer lookupHttpPort(Integer httpsPort) {
public @Nullable Integer lookupHttpPort(Integer httpsPort) {
for (Integer httpPort : this.httpsPortMappings.keySet()) {
if (this.httpsPortMappings.get(httpPort).equals(httpsPort)) {
return httpPort;
@ -60,7 +62,7 @@ public class PortMapperImpl implements PortMapper {
}
@Override
public Integer lookupHttpsPort(Integer httpPort) {
public @Nullable Integer lookupHttpsPort(Integer httpPort) {
return this.httpsPortMappings.get(httpPort);
}

View File

@ -19,6 +19,7 @@ package org.springframework.security.web;
import java.util.Locale;
import jakarta.servlet.ServletRequest;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
@ -54,7 +55,7 @@ public class PortResolverImpl implements PortResolver {
return (mappedPort != null) ? mappedPort : serverPort;
}
private Integer getMappedPort(int serverPort, String scheme) {
private @Nullable Integer getMappedPort(int serverPort, String scheme) {
if ("http".equals(scheme)) {
return this.portMapper.lookupHttpPort(serverPort);
}

View File

@ -23,6 +23,7 @@ import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.core.log.LogMessage;
import org.springframework.http.HttpStatus;
@ -47,7 +48,7 @@ public class AccessDeniedHandlerImpl implements AccessDeniedHandler {
protected static final Log logger = LogFactory.getLog(AccessDeniedHandlerImpl.class);
private String errorPage;
private @Nullable String errorPage;
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,

View File

@ -18,6 +18,7 @@ package org.springframework.security.web.access;
import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpServletRequest;
import org.jspecify.annotations.Nullable;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.AuthorizationResult;
@ -38,7 +39,7 @@ public final class AuthorizationManagerWebInvocationPrivilegeEvaluator
private final AuthorizationManager<HttpServletRequest> authorizationManager;
private ServletContext servletContext;
private @Nullable ServletContext servletContext;
private HttpServletRequestTransformer requestTransformer = HttpServletRequestTransformer.IDENTITY;
@ -54,7 +55,8 @@ public final class AuthorizationManagerWebInvocationPrivilegeEvaluator
}
@Override
public boolean isAllowed(String contextPath, String uri, String method, Authentication authentication) {
public boolean isAllowed(@Nullable String contextPath, String uri, @Nullable String method,
Authentication authentication) {
FilterInvocation filterInvocation = new FilterInvocation(contextPath, uri, method, this.servletContext);
HttpServletRequest httpRequest = this.requestTransformer.transform(filterInvocation.getHttpRequest());
AuthorizationResult result = this.authorizationManager.authorize(() -> authentication, httpRequest);

View File

@ -21,6 +21,7 @@ import java.util.Collection;
import jakarta.servlet.ServletContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.core.log.LogMessage;
import org.springframework.security.access.AccessDeniedException;
@ -46,7 +47,7 @@ public class DefaultWebInvocationPrivilegeEvaluator implements WebInvocationPriv
private final AbstractSecurityInterceptor securityInterceptor;
private ServletContext servletContext;
private @Nullable ServletContext servletContext;
public DefaultWebInvocationPrivilegeEvaluator(AbstractSecurityInterceptor securityInterceptor) {
Assert.notNull(securityInterceptor, "SecurityInterceptor cannot be null");
@ -86,7 +87,8 @@ public class DefaultWebInvocationPrivilegeEvaluator implements WebInvocationPriv
* @return true if access is allowed, false if denied
*/
@Override
public boolean isAllowed(String contextPath, String uri, String method, Authentication authentication) {
public boolean isAllowed(@Nullable String contextPath, String uri, @Nullable String method,
Authentication authentication) {
Assert.notNull(uri, "uri parameter is required");
FilterInvocation filterInvocation = new FilterInvocation(contextPath, uri, method, this.servletContext);
Collection<ConfigAttribute> attributes = this.securityInterceptor.obtainSecurityMetadataSource()

View File

@ -24,6 +24,7 @@ import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
@ -169,7 +170,7 @@ public class ExceptionTranslationFilter extends GenericFilterBean implements Mes
}
private void handleSpringSecurityException(HttpServletRequest request, HttpServletResponse response,
FilterChain chain, RuntimeException exception) throws IOException, ServletException {
FilterChain chain, @Nullable RuntimeException exception) throws IOException, ServletException {
if (exception instanceof AuthenticationException) {
handleAuthenticationException(request, response, chain, (AuthenticationException) exception);
}

View File

@ -21,6 +21,7 @@ import java.util.Map;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import org.jspecify.annotations.Nullable;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.web.util.ServletRequestPathUtils;
@ -51,7 +52,7 @@ public final class PathPatternRequestTransformer
}
@Override
public Object getAttribute(String name) {
public @Nullable Object getAttribute(String name) {
return this.attributes.get(name);
}

View File

@ -21,6 +21,7 @@ import java.util.List;
import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpServletRequest;
import org.jspecify.annotations.Nullable;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
@ -46,7 +47,7 @@ public final class RequestMatcherDelegatingWebInvocationPrivilegeEvaluator
private final List<RequestMatcherEntry<List<WebInvocationPrivilegeEvaluator>>> delegates;
private ServletContext servletContext;
private @Nullable ServletContext servletContext;
public RequestMatcherDelegatingWebInvocationPrivilegeEvaluator(
List<RequestMatcherEntry<List<WebInvocationPrivilegeEvaluator>>> requestMatcherPrivilegeEvaluatorsEntries) {
@ -119,7 +120,8 @@ public final class RequestMatcherDelegatingWebInvocationPrivilegeEvaluator
return true;
}
private List<WebInvocationPrivilegeEvaluator> getDelegate(String contextPath, String uri, String method) {
private List<WebInvocationPrivilegeEvaluator> getDelegate(@Nullable String contextPath, String uri,
@Nullable String method) {
FilterInvocation filterInvocation = new FilterInvocation(contextPath, uri, method, this.servletContext);
HttpServletRequest request = filterInvocation.getHttpRequest();
for (RequestMatcherEntry<List<WebInvocationPrivilegeEvaluator>> delegate : this.delegates) {

View File

@ -22,6 +22,7 @@ import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.core.log.LogMessage;
import org.springframework.security.web.DefaultRedirectStrategy;
@ -79,7 +80,7 @@ public abstract class AbstractRetryEntryPoint implements ChannelEntryPoint {
this.redirectStrategy.sendRedirect(request, response, redirectUrl);
}
protected abstract Integer getMappedPort(Integer mapFromPort);
protected abstract @Nullable Integer getMappedPort(Integer mapFromPort);
protected final PortMapper getPortMapper() {
return this.portMapper;

View File

@ -22,6 +22,8 @@ import java.util.Collection;
import java.util.List;
import jakarta.servlet.ServletException;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.access.ConfigAttribute;
@ -49,6 +51,7 @@ import org.springframework.util.Assert;
* {@link RequestMatcher} for any sophisticated decision-making
*/
@Deprecated
@NullUnmarked
public class ChannelDecisionManagerImpl implements ChannelDecisionManager, InitializingBean {
public static final String ANY_CHANNEL = "ANY_CHANNEL";
@ -76,7 +79,7 @@ public class ChannelDecisionManagerImpl implements ChannelDecisionManager, Initi
}
}
protected List<ChannelProcessor> getChannelProcessors() {
protected @Nullable List<ChannelProcessor> getChannelProcessors() {
return this.channelProcessors;
}

View File

@ -27,6 +27,7 @@ import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.core.log.LogMessage;
import org.springframework.security.access.ConfigAttribute;
@ -88,8 +89,10 @@ import org.springframework.web.filter.GenericFilterBean;
@Deprecated
public class ChannelProcessingFilter extends GenericFilterBean {
@SuppressWarnings("NullAway.Init")
private ChannelDecisionManager channelDecisionManager;
@SuppressWarnings("NullAway.Init")
private FilterInvocationSecurityMetadataSource securityMetadataSource;
@Override
@ -128,14 +131,16 @@ public class ChannelProcessingFilter extends GenericFilterBean {
if (attributes != null) {
this.logger.debug(LogMessage.format("Request: %s; ConfigAttributes: %s", filterInvocation, attributes));
this.channelDecisionManager.decide(filterInvocation, attributes);
if (filterInvocation.getResponse().isCommitted()) {
@Nullable HttpServletResponse channelResponse = filterInvocation.getResponse();
Assert.notNull(channelResponse, "HttpServletResponse is required");
if (channelResponse.isCommitted()) {
return;
}
}
chain.doFilter(request, response);
}
protected ChannelDecisionManager getChannelDecisionManager() {
protected @Nullable ChannelDecisionManager getChannelDecisionManager() {
return this.channelDecisionManager;
}

View File

@ -20,6 +20,8 @@ import java.io.IOException;
import java.util.Collection;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.access.ConfigAttribute;
@ -63,7 +65,9 @@ public class InsecureChannelProcessor implements InitializingBean, ChannelProces
for (ConfigAttribute attribute : config) {
if (supports(attribute)) {
if (invocation.getHttpRequest().isSecure()) {
this.entryPoint.commence(invocation.getRequest(), invocation.getResponse());
@Nullable HttpServletResponse response = invocation.getResponse();
Assert.notNull(response, "HttpServletResponse required");
this.entryPoint.commence(invocation.getRequest(), response);
}
}
}

View File

@ -16,6 +16,8 @@
package org.springframework.security.web.access.channel;
import org.jspecify.annotations.Nullable;
import org.springframework.security.web.PortMapper;
/**
@ -38,7 +40,7 @@ public class RetryWithHttpEntryPoint extends AbstractRetryEntryPoint {
}
@Override
protected Integer getMappedPort(Integer mapFromPort) {
protected @Nullable Integer getMappedPort(Integer mapFromPort) {
return getPortMapper().lookupHttpPort(mapFromPort);
}

View File

@ -16,6 +16,8 @@
package org.springframework.security.web.access.channel;
import org.jspecify.annotations.Nullable;
import org.springframework.security.web.PortMapper;
/**
@ -39,7 +41,7 @@ public class RetryWithHttpsEntryPoint extends AbstractRetryEntryPoint {
}
@Override
protected Integer getMappedPort(Integer mapFromPort) {
protected @Nullable Integer getMappedPort(Integer mapFromPort) {
return getPortMapper().lookupHttpsPort(mapFromPort);
}

View File

@ -20,6 +20,7 @@ import java.io.IOException;
import java.util.Collection;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.access.ConfigAttribute;
@ -63,7 +64,9 @@ public class SecureChannelProcessor implements InitializingBean, ChannelProcesso
for (ConfigAttribute attribute : config) {
if (supports(attribute)) {
if (!invocation.getHttpRequest().isSecure()) {
this.entryPoint.commence(invocation.getRequest(), invocation.getResponse());
HttpServletResponse response = invocation.getResponse();
Assert.notNull(response, "HttpServletResponse is required");
this.entryPoint.commence(invocation.getRequest(), response);
}
}
}

View File

@ -19,4 +19,7 @@
* <p>
* Most commonly used to enforce that requests are submitted over HTTP or HTTPS.
*/
@NullMarked
package org.springframework.security.web.access.channel;
import org.jspecify.annotations.NullMarked;

View File

@ -19,6 +19,7 @@ package org.springframework.security.web.access.expression;
import java.util.Map;
import jakarta.servlet.http.HttpServletRequest;
import org.jspecify.annotations.Nullable;
import org.springframework.expression.EvaluationContext;
import org.springframework.security.web.FilterInvocation;
@ -53,7 +54,7 @@ abstract class AbstractVariableEvaluationContextPostProcessor
private final HttpServletRequest request;
private Map<String, String> variables;
private @Nullable Map<String, String> variables;
VariableEvaluationContext(EvaluationContext delegate, HttpServletRequest request) {
super(delegate);
@ -61,7 +62,7 @@ abstract class AbstractVariableEvaluationContextPostProcessor
}
@Override
public Object lookupVariable(String name) {
public @Nullable Object lookupVariable(String name) {
Object result = super.lookupVariable(name);
if (result != null) {
return result;

View File

@ -46,6 +46,7 @@ public class DefaultHttpSecurityExpressionHandler extends AbstractSecurityExpres
private String defaultRolePrefix = "ROLE_";
@Override
@SuppressWarnings("NullAway") // https://github.com/spring-projects/spring-framework/issues/35371
public EvaluationContext createEvaluationContext(Supplier<? extends @Nullable Authentication> authentication,
RequestAuthorizationContext context) {
WebSecurityExpressionRoot root = createSecurityExpressionRoot(authentication, context);
@ -56,13 +57,13 @@ public class DefaultHttpSecurityExpressionHandler extends AbstractSecurityExpres
}
@Override
protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,
protected SecurityExpressionOperations createSecurityExpressionRoot(@Nullable Authentication authentication,
RequestAuthorizationContext context) {
return createSecurityExpressionRoot(() -> authentication, context);
}
private WebSecurityExpressionRoot createSecurityExpressionRoot(Supplier<? extends Authentication> authentication,
RequestAuthorizationContext context) {
private WebSecurityExpressionRoot createSecurityExpressionRoot(
Supplier<? extends @Nullable Authentication> authentication, RequestAuthorizationContext context) {
WebSecurityExpressionRoot root = new WebSecurityExpressionRoot(authentication, context.getRequest());
root.setRoleHierarchy(getRoleHierarchy());
root.setPermissionEvaluator(getPermissionEvaluator());

View File

@ -16,6 +16,8 @@
package org.springframework.security.web.access.expression;
import org.jspecify.annotations.Nullable;
import org.springframework.security.access.expression.AbstractSecurityExpressionHandler;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.access.expression.SecurityExpressionOperations;
@ -38,7 +40,7 @@ public class DefaultWebSecurityExpressionHandler extends AbstractSecurityExpress
private String defaultRolePrefix = "ROLE_";
@Override
protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,
protected SecurityExpressionOperations createSecurityExpressionRoot(@Nullable Authentication authentication,
FilterInvocation fi) {
WebSecurityExpressionRoot root = new WebSecurityExpressionRoot(authentication, fi);
root.setPermissionEvaluator(getPermissionEvaluator());

View File

@ -18,6 +18,8 @@ package org.springframework.security.web.access.expression;
import java.util.List;
import org.jspecify.annotations.Nullable;
import org.springframework.expression.BeanResolver;
import org.springframework.expression.ConstructorResolver;
import org.springframework.expression.EvaluationContext;
@ -84,17 +86,17 @@ class DelegatingEvaluationContext implements EvaluationContext {
}
@Override
public BeanResolver getBeanResolver() {
public @Nullable BeanResolver getBeanResolver() {
return this.delegate.getBeanResolver();
}
@Override
public void setVariable(String name, Object value) {
public void setVariable(String name, @Nullable Object value) {
this.delegate.setVariable(name, value);
}
@Override
public Object lookupVariable(String name) {
public @Nullable Object lookupVariable(String name) {
return this.delegate.lookupVariable(name);
}

View File

@ -16,6 +16,8 @@
package org.springframework.security.web.access.expression;
import org.jspecify.annotations.NullUnmarked;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.security.access.ConfigAttribute;
@ -32,6 +34,7 @@ import org.springframework.security.web.FilterInvocation;
* {@link AuthorizationManager}.
*/
@Deprecated
@NullUnmarked
class WebExpressionConfigAttribute implements ConfigAttribute, EvaluationContextPostProcessor<FilterInvocation> {
private final Expression authorizeExpression;

View File

@ -20,6 +20,7 @@ import java.util.Collection;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.expression.EvaluationContext;
import org.springframework.security.access.AccessDecisionVoter;
@ -66,7 +67,7 @@ public class WebExpressionVoter implements AccessDecisionVoter<FilterInvocation>
return ACCESS_DENIED;
}
private WebExpressionConfigAttribute findConfigAttribute(Collection<ConfigAttribute> attributes) {
private @Nullable WebExpressionConfigAttribute findConfigAttribute(Collection<ConfigAttribute> attributes) {
for (ConfigAttribute attribute : attributes) {
if (attribute instanceof WebExpressionConfigAttribute) {
return (WebExpressionConfigAttribute) attribute;

View File

@ -19,6 +19,7 @@ package org.springframework.security.web.access.expression;
import java.util.function.Supplier;
import jakarta.servlet.http.HttpServletRequest;
import org.jspecify.annotations.Nullable;
import org.springframework.security.access.expression.SecurityExpressionRoot;
import org.springframework.security.core.Authentication;
@ -37,7 +38,7 @@ public class WebSecurityExpressionRoot extends SecurityExpressionRoot {
*/
public final HttpServletRequest request;
public WebSecurityExpressionRoot(Authentication a, FilterInvocation fi) {
public WebSecurityExpressionRoot(@Nullable Authentication a, FilterInvocation fi) {
this(() -> a, fi.getRequest());
}
@ -48,7 +49,9 @@ public class WebSecurityExpressionRoot extends SecurityExpressionRoot {
* @param request the {@link HttpServletRequest} to use
* @since 5.8
*/
public WebSecurityExpressionRoot(Supplier<? extends Authentication> authentication, HttpServletRequest request) {
@SuppressWarnings("NullAway") // https://github.com/uber/NullAway/issues/1246
public WebSecurityExpressionRoot(Supplier<? extends @Nullable Authentication> authentication,
HttpServletRequest request) {
super(authentication);
this.request = request;
}

View File

@ -17,4 +17,7 @@
/**
* Implementation of web security expressions.
*/
@NullMarked
package org.springframework.security.web.access.expression;
import org.jspecify.annotations.NullMarked;

View File

@ -26,6 +26,7 @@ import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
@ -202,7 +203,7 @@ public class AuthorizationFilter extends GenericFilterBean {
@Override
public <T> void publishAuthorizationEvent(Supplier<Authentication> authentication, T object,
AuthorizationResult result) {
@Nullable AuthorizationResult result) {
}
}

View File

@ -17,6 +17,7 @@
package org.springframework.security.web.access.intercept;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
@ -99,7 +100,7 @@ public class DefaultFilterInvocationSecurityMetadataSource implements FilterInvo
}
}
}
return null;
return Collections.emptyList();
}
@Override

View File

@ -24,6 +24,7 @@ import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
@ -48,7 +49,7 @@ public class FilterSecurityInterceptor extends AbstractSecurityInterceptor imple
private static final String FILTER_APPLIED = "__spring_security_filterSecurityInterceptor_filterApplied";
private FilterInvocationSecurityMetadataSource securityMetadataSource;
private @Nullable FilterInvocationSecurityMetadataSource securityMetadataSource;
private boolean observeOncePerRequest = false;
@ -83,12 +84,12 @@ public class FilterSecurityInterceptor extends AbstractSecurityInterceptor imple
invoke(new FilterInvocation(request, response, chain));
}
public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
public @Nullable FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
return this.securityMetadataSource;
}
@Override
public SecurityMetadataSource obtainSecurityMetadataSource() {
public @Nullable SecurityMetadataSource obtainSecurityMetadataSource() {
return this.securityMetadataSource;
}

View File

@ -16,6 +16,8 @@
package org.springframework.security.web.access.intercept;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
/**
@ -26,13 +28,13 @@ public class RequestKey {
private final String url;
private final String method;
private final @Nullable String method;
public RequestKey(String url) {
this(url, null);
}
public RequestKey(String url, String method) {
public RequestKey(String url, @Nullable String method) {
Assert.notNull(url, "url cannot be null");
this.url = url;
this.method = method;
@ -42,7 +44,7 @@ public class RequestKey {
return this.url;
}
String getMethod() {
@Nullable String getMethod() {
return this.method;
}

View File

@ -64,7 +64,7 @@ public final class RequestMatcherDelegatingAuthorizationManager implements Autho
}
@Override
public AuthorizationResult authorize(Supplier<? extends @Nullable Authentication> authentication,
public @Nullable AuthorizationResult authorize(Supplier<? extends @Nullable Authentication> authentication,
HttpServletRequest request) {
if (this.logger.isTraceEnabled()) {
this.logger.trace(LogMessage.format("Authorizing %s", requestLine(request)));

View File

@ -17,4 +17,7 @@
/**
* Enforcement of security for HTTP requests, typically by the URL requested.
*/
@NullMarked
package org.springframework.security.web.access.intercept;
import org.jspecify.annotations.NullMarked;

View File

@ -17,4 +17,7 @@
/**
* Access-control related classes and packages.
*/
@NullMarked
package org.springframework.security.web.access;
import org.jspecify.annotations.NullMarked;

View File

@ -16,6 +16,8 @@
package org.springframework.security.web.aot.hint;
import org.jspecify.annotations.Nullable;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
@ -33,7 +35,7 @@ import org.springframework.security.web.access.expression.WebSecurityExpressionR
class WebMvcSecurityRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
hints.reflection()
.registerType(WebSecurityExpressionRoot.class, (builder) -> builder
.withMembers(MemberCategory.INVOKE_DECLARED_METHODS, MemberCategory.ACCESS_DECLARED_FIELDS));

View File

@ -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.
*/
/**
* Runtime hints for AOT web package.
*/
@NullMarked
package org.springframework.security.web.aot.hint;
import org.jspecify.annotations.NullMarked;

View File

@ -24,6 +24,7 @@ import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
@ -120,7 +121,7 @@ public abstract class AbstractAuthenticationProcessingFilter extends GenericFilt
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
.getContextHolderStrategy();
protected ApplicationEventPublisher eventPublisher;
@Nullable protected ApplicationEventPublisher eventPublisher;
protected AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
@ -129,6 +130,7 @@ public abstract class AbstractAuthenticationProcessingFilter extends GenericFilt
"Please either configure an AuthenticationConverter or override attemptAuthentication when extending AbstractAuthenticationProcessingFilter");
};
@SuppressWarnings("NullAway.Init")
private AuthenticationManager authenticationManager;
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
@ -155,7 +157,7 @@ public abstract class AbstractAuthenticationProcessingFilter extends GenericFilt
* @param defaultFilterProcessesUrl the default value for <tt>filterProcessesUrl</tt>.
*/
protected AbstractAuthenticationProcessingFilter(String defaultFilterProcessesUrl) {
setFilterProcessesUrl(defaultFilterProcessesUrl);
this(pathPattern(defaultFilterProcessesUrl));
}
/**
@ -177,7 +179,7 @@ public abstract class AbstractAuthenticationProcessingFilter extends GenericFilt
*/
protected AbstractAuthenticationProcessingFilter(String defaultFilterProcessesUrl,
AuthenticationManager authenticationManager) {
setFilterProcessesUrl(defaultFilterProcessesUrl);
this(pathPattern(defaultFilterProcessesUrl));
setAuthenticationManager(authenticationManager);
}
@ -305,7 +307,7 @@ public abstract class AbstractAuthenticationProcessingFilter extends GenericFilt
* @return the authenticated user token, or null if authentication is incomplete.
* @throws AuthenticationException if authentication fails.
*/
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
public @Nullable Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException {
Authentication authentication = this.authenticationConverter.convert(request);
if (authentication == null) {

View File

@ -23,6 +23,7 @@ import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.core.log.LogMessage;
import org.springframework.security.core.Authentication;
@ -62,7 +63,7 @@ public abstract class AbstractAuthenticationTargetUrlRequestHandler {
protected final Log logger = LogFactory.getLog(this.getClass());
private String targetUrlParameter = null;
private @Nullable String targetUrlParameter = null;
private String defaultTargetUrl = "/";
@ -81,8 +82,8 @@ public abstract class AbstractAuthenticationTargetUrlRequestHandler {
* <p>
* The redirect will not be performed if the response has already been committed.
*/
protected void handle(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
protected void handle(HttpServletRequest request, HttpServletResponse response,
@Nullable Authentication authentication) throws IOException, ServletException {
String targetUrl = determineTargetUrl(request, response, authentication);
if (response.isCommitted()) {
this.logger.debug(LogMessage.format("Did not redirect to %s since response already committed.", targetUrl));
@ -96,7 +97,7 @@ public abstract class AbstractAuthenticationTargetUrlRequestHandler {
* @since 5.2
*/
protected String determineTargetUrl(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) {
@Nullable Authentication authentication) {
return determineTargetUrl(request, response);
}
@ -119,7 +120,7 @@ public abstract class AbstractAuthenticationTargetUrlRequestHandler {
return this.defaultTargetUrl;
}
private String getTargetUrlParameterValue(HttpServletRequest request) {
private @Nullable String getTargetUrlParameterValue(HttpServletRequest request) {
if (this.targetUrlParameter == null) {
return null;
}
@ -133,7 +134,7 @@ public abstract class AbstractAuthenticationTargetUrlRequestHandler {
return this.defaultTargetUrl;
}
private void trace(String msg, String... msgParts) {
private void trace(String msg, @Nullable String... msgParts) {
if (this.logger.isTraceEnabled()) {
this.logger.trace(LogMessage.format(msg, msgParts));
}
@ -189,7 +190,7 @@ public abstract class AbstractAuthenticationTargetUrlRequestHandler {
this.targetUrlParameter = targetUrlParameter;
}
protected String getTargetUrlParameter() {
protected @Nullable String getTargetUrlParameter() {
return this.targetUrlParameter;
}

View File

@ -17,6 +17,7 @@
package org.springframework.security.web.authentication;
import jakarta.servlet.http.HttpServletRequest;
import org.jspecify.annotations.Nullable;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
@ -35,6 +36,6 @@ import org.springframework.security.core.AuthenticationException;
*/
public interface AuthenticationConverter {
Authentication convert(HttpServletRequest request);
@Nullable Authentication convert(HttpServletRequest request);
}

View File

@ -24,6 +24,7 @@ import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.jspecify.annotations.Nullable;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
@ -218,7 +219,7 @@ public class AuthenticationFilter extends OncePerRequestFilter {
this.successHandler.onAuthenticationSuccess(request, response, chain, authentication);
}
private Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
private @Nullable Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, ServletException {
Authentication authentication = this.authenticationConverter.convert(request);
if (authentication == null) {

View File

@ -19,6 +19,7 @@ package org.springframework.security.web.authentication;
import java.util.List;
import jakarta.servlet.http.HttpServletRequest;
import org.jspecify.annotations.Nullable;
import org.springframework.security.core.Authentication;
import org.springframework.util.Assert;
@ -46,7 +47,7 @@ public final class DelegatingAuthenticationConverter implements AuthenticationCo
}
@Override
public Authentication convert(HttpServletRequest request) {
public @Nullable Authentication convert(HttpServletRequest request) {
for (AuthenticationConverter delegate : this.delegates) {
Authentication authentication = delegate.convert(request);
if (authentication != null) {

View File

@ -66,6 +66,7 @@ public class DelegatingAuthenticationEntryPoint implements AuthenticationEntryPo
private final LinkedHashMap<RequestMatcher, AuthenticationEntryPoint> entryPoints;
@SuppressWarnings("NullAway.Init")
private AuthenticationEntryPoint defaultEntryPoint;
public DelegatingAuthenticationEntryPoint(LinkedHashMap<RequestMatcher, AuthenticationEntryPoint> entryPoints) {

View File

@ -24,6 +24,7 @@ import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.log.LogMessage;
@ -187,7 +188,8 @@ public class LoginUrlAuthenticationEntryPoint implements AuthenticationEntryPoin
* Builds a URL to redirect the supplied request to HTTPS. Used to redirect the
* current request to HTTPS, before doing a forward to the login page.
*/
protected String buildHttpsRedirectUrlForRequest(HttpServletRequest request) throws IOException, ServletException {
protected @Nullable String buildHttpsRedirectUrlForRequest(HttpServletRequest request)
throws IOException, ServletException {
int serverPort = this.portResolver.getServerPort(request);
Integer httpsPort = this.portMapper.lookupHttpsPort(serverPort);
if (httpsPort != null) {

View File

@ -18,6 +18,7 @@ package org.springframework.security.web.authentication;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.security.core.Authentication;
@ -32,7 +33,7 @@ import org.springframework.security.core.Authentication;
public class NullRememberMeServices implements RememberMeServices {
@Override
public Authentication autoLogin(HttpServletRequest request, HttpServletResponse response) {
public @Nullable Authentication autoLogin(HttpServletRequest request, HttpServletResponse response) {
return null;
}

View File

@ -18,6 +18,7 @@ package org.springframework.security.web.authentication;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.security.core.Authentication;
@ -69,7 +70,7 @@ public interface RememberMeServices {
* @return a valid authentication object, or <code>null</code> if the request should
* not be authenticated
*/
Authentication autoLogin(HttpServletRequest request, HttpServletResponse response);
@Nullable Authentication autoLogin(HttpServletRequest request, HttpServletResponse response);
/**
* Called whenever an interactive authentication attempt was made, but the credentials

View File

@ -24,6 +24,7 @@ import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
@ -50,7 +51,7 @@ public class SimpleUrlAuthenticationFailureHandler implements AuthenticationFail
protected final Log logger = LogFactory.getLog(getClass());
private String defaultFailureUrl;
private @Nullable String defaultFailureUrl;
private boolean forwardToDestination = false;

View File

@ -21,6 +21,7 @@ import java.util.Objects;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import org.jspecify.annotations.Nullable;
/**
* A holder of selected HTTP details related to a web authentication request.
@ -34,7 +35,7 @@ public class WebAuthenticationDetails implements Serializable {
private final String remoteAddress;
private final String sessionId;
private final @Nullable String sessionId;
/**
* Records the remote address and will also set the session Id if a session already
@ -51,12 +52,12 @@ public class WebAuthenticationDetails implements Serializable {
* @param sessionId session id
* @since 5.7
*/
public WebAuthenticationDetails(String remoteAddress, String sessionId) {
public WebAuthenticationDetails(String remoteAddress, @Nullable String sessionId) {
this.remoteAddress = remoteAddress;
this.sessionId = sessionId;
}
private static String extractSessionId(HttpServletRequest request) {
private static @Nullable String extractSessionId(HttpServletRequest request) {
HttpSession session = request.getSession(false);
return (session != null) ? session.getId() : null;
}
@ -74,7 +75,7 @@ public class WebAuthenticationDetails implements Serializable {
* from.
* @return the session ID
*/
public String getSessionId() {
public @Nullable String getSessionId() {
return this.sessionId;
}

View File

@ -21,6 +21,7 @@ import java.util.List;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.security.core.Authentication;
import org.springframework.util.Assert;
@ -49,7 +50,8 @@ public final class CompositeLogoutHandler implements LogoutHandler {
}
@Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
public void logout(HttpServletRequest request, HttpServletResponse response,
@Nullable Authentication authentication) {
for (LogoutHandler handler : this.logoutHandlers) {
handler.logout(request, response, authentication);
}

View File

@ -23,6 +23,7 @@ import java.util.function.Function;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.security.core.Authentication;
import org.springframework.util.Assert;
@ -72,7 +73,8 @@ public final class CookieClearingLogoutHandler implements LogoutHandler {
}
@Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
public void logout(HttpServletRequest request, HttpServletResponse response,
@Nullable Authentication authentication) {
this.cookiesToClear.forEach((f) -> response.addCookie(f.apply(request)));
}

View File

@ -23,6 +23,7 @@ import java.util.Map;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.util.matcher.RequestMatcher;
@ -39,7 +40,7 @@ public class DelegatingLogoutSuccessHandler implements LogoutSuccessHandler {
private final LinkedHashMap<RequestMatcher, LogoutSuccessHandler> matcherToHandler;
private LogoutSuccessHandler defaultLogoutSuccessHandler;
private @Nullable LogoutSuccessHandler defaultLogoutSuccessHandler;
public DelegatingLogoutSuccessHandler(LinkedHashMap<RequestMatcher, LogoutSuccessHandler> matcherToHandler) {
Assert.notEmpty(matcherToHandler, "matcherToHandler cannot be null");
@ -47,8 +48,8 @@ public class DelegatingLogoutSuccessHandler implements LogoutSuccessHandler {
}
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
@Nullable Authentication authentication) throws IOException, ServletException {
for (Map.Entry<RequestMatcher, LogoutSuccessHandler> entry : this.matcherToHandler.entrySet()) {
RequestMatcher matcher = entry.getKey();
if (matcher.matches(request)) {

View File

@ -21,6 +21,7 @@ import java.io.IOException;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.util.UrlUtils;
@ -47,8 +48,8 @@ public class ForwardLogoutSuccessHandler implements LogoutSuccessHandler {
}
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
@Nullable Authentication authentication) throws IOException, ServletException {
request.getRequestDispatcher(this.targetUrl).forward(request, response);
}

View File

@ -18,6 +18,7 @@ package org.springframework.security.web.authentication.logout;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.header.HeaderWriter;
@ -42,7 +43,8 @@ public final class HeaderWriterLogoutHandler implements LogoutHandler {
}
@Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
public void logout(HttpServletRequest request, HttpServletResponse response,
@Nullable Authentication authentication) {
this.headerWriter.writeHeaders(request, response);
}

View File

@ -20,6 +20,7 @@ import java.io.IOException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
@ -61,8 +62,8 @@ public class HttpStatusReturningLogoutSuccessHandler implements LogoutSuccessHan
* . Sets the status on the {@link HttpServletResponse}.
*/
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException {
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
@Nullable Authentication authentication) throws IOException {
response.setStatus(this.httpStatusToReturn.value());
response.getWriter().flush();
}

View File

@ -69,6 +69,7 @@ public class LogoutFilter extends GenericFilterBean {
* intended to perform the actual logout functionality (such as clearing the security
* context, invalidating the session, etc.).
*/
@SuppressWarnings("NullAway") // Dataflow analysis limitation
public LogoutFilter(LogoutSuccessHandler logoutSuccessHandler, LogoutHandler... handlers) {
this.handler = new CompositeLogoutHandler(handlers);
Assert.notNull(logoutSuccessHandler, "logoutSuccessHandler cannot be null");
@ -76,6 +77,7 @@ public class LogoutFilter extends GenericFilterBean {
setFilterProcessesUrl("/logout");
}
@SuppressWarnings("NullAway") // Dataflow analysis limitation
public LogoutFilter(String logoutSuccessUrl, LogoutHandler... handlers) {
this.handler = new CompositeLogoutHandler(handlers);
Assert.isTrue(!StringUtils.hasLength(logoutSuccessUrl) || UrlUtils.isValidRedirectUrl(logoutSuccessUrl),

View File

@ -18,6 +18,7 @@ package org.springframework.security.web.authentication.logout;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.security.core.Authentication;
@ -37,6 +38,6 @@ public interface LogoutHandler {
* @param response the HTTP response
* @param authentication the current principal details
*/
void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication);
void logout(HttpServletRequest request, HttpServletResponse response, @Nullable Authentication authentication);
}

View File

@ -18,6 +18,7 @@ package org.springframework.security.web.authentication.logout;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
@ -32,10 +33,11 @@ import org.springframework.security.core.Authentication;
*/
public final class LogoutSuccessEventPublishingLogoutHandler implements LogoutHandler, ApplicationEventPublisherAware {
private ApplicationEventPublisher eventPublisher;
private @Nullable ApplicationEventPublisher eventPublisher;
@Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
public void logout(HttpServletRequest request, HttpServletResponse response,
@Nullable Authentication authentication) {
if (this.eventPublisher == null) {
return;
}

View File

@ -21,6 +21,7 @@ import java.io.IOException;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.security.core.Authentication;
@ -37,7 +38,7 @@ import org.springframework.security.core.Authentication;
*/
public interface LogoutSuccessHandler {
void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException;
void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
@Nullable Authentication authentication) throws IOException, ServletException;
}

View File

@ -21,6 +21,7 @@ import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.core.log.LogMessage;
import org.springframework.security.core.Authentication;
@ -64,7 +65,8 @@ public class SecurityContextLogoutHandler implements LogoutHandler {
* @param authentication not used (can be <code>null</code>)
*/
@Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
public void logout(HttpServletRequest request, HttpServletResponse response,
@Nullable Authentication authentication) {
Assert.notNull(request, "HttpServletRequest required");
if (this.invalidateHttpSession) {
HttpSession session = request.getSession(false);

View File

@ -21,6 +21,7 @@ import java.io.IOException;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AbstractAuthenticationTargetUrlRequestHandler;
@ -36,8 +37,8 @@ public class SimpleUrlLogoutSuccessHandler extends AbstractAuthenticationTargetU
implements LogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
@Nullable Authentication authentication) throws IOException, ServletException {
super.handle(request, response, authentication);
}

View File

@ -17,4 +17,7 @@
/**
* Logout functionality based around a filter which handles a specific logout URL.
*/
@NullMarked
package org.springframework.security.web.authentication.logout;
import org.jspecify.annotations.NullMarked;

View File

@ -19,6 +19,7 @@ package org.springframework.security.web.authentication.ott;
import java.time.Duration;
import jakarta.servlet.http.HttpServletRequest;
import org.jspecify.annotations.Nullable;
import org.springframework.security.authentication.ott.GenerateOneTimeTokenRequest;
import org.springframework.util.Assert;
@ -38,7 +39,7 @@ public final class DefaultGenerateOneTimeTokenRequestResolver implements Generat
private Duration expiresIn = DEFAULT_EXPIRES_IN;
@Override
public GenerateOneTimeTokenRequest resolve(HttpServletRequest request) {
public @Nullable GenerateOneTimeTokenRequest resolve(HttpServletRequest request) {
String username = request.getParameter("username");
if (!StringUtils.hasText(username)) {
return null;

View File

@ -74,11 +74,11 @@ public final class GenerateOneTimeTokenFilter extends OncePerRequestFilter {
return;
}
GenerateOneTimeTokenRequest generateRequest = this.requestResolver.resolve(request);
OneTimeToken ott = this.tokenService.generate(generateRequest);
if (generateRequest == null) {
filterChain.doFilter(request, response);
return;
}
OneTimeToken ott = this.tokenService.generate(generateRequest);
this.tokenGenerationSuccessHandler.handle(request, response, ott);
}

View File

@ -19,6 +19,7 @@ package org.springframework.security.web.authentication.ott;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.security.authentication.ott.OneTimeTokenAuthenticationToken;
import org.springframework.security.core.Authentication;
@ -39,7 +40,7 @@ public class OneTimeTokenAuthenticationConverter implements AuthenticationConver
private final Log logger = LogFactory.getLog(getClass());
@Override
public Authentication convert(HttpServletRequest request) {
public @Nullable Authentication convert(HttpServletRequest request) {
String token = request.getParameter("token");
if (!StringUtils.hasText(token)) {
this.logger.debug("No token found in request");

View File

@ -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.
*/
/**
* Package for One Time Token usage.
*/
@NullMarked
package org.springframework.security.web.authentication.ott;
import org.jspecify.annotations.NullMarked;

View File

@ -18,4 +18,7 @@
* Authentication processing mechanisms, which respond to the submission of authentication
* credentials using various protocols (eg BASIC, CAS, form login etc).
*/
@NullMarked
package org.springframework.security.web.authentication;
import org.jspecify.annotations.NullMarked;

View File

@ -25,6 +25,7 @@ import java.util.Locale;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.security.authentication.password.CompromisedPasswordChecker;
import org.springframework.security.authentication.password.CompromisedPasswordDecision;
@ -60,7 +61,7 @@ public final class HaveIBeenPwnedRestApiPasswordChecker implements CompromisedPa
}
@Override
public CompromisedPasswordDecision check(String password) {
public CompromisedPasswordDecision check(@Nullable String password) {
if (password == null) {
return new CompromisedPasswordDecision(false);
}

View File

@ -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.
*/
/**
* Classes for Password APIs.
*/
@NullMarked
package org.springframework.security.web.authentication.password;
import org.jspecify.annotations.NullMarked;

View File

@ -25,6 +25,7 @@ import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.jspecify.annotations.Nullable;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
@ -96,11 +97,12 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
.getContextHolderStrategy();
private ApplicationEventPublisher eventPublisher = null;
private @Nullable ApplicationEventPublisher eventPublisher = null;
private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
private AuthenticationManager authenticationManager = null;
@SuppressWarnings("NullAway.Init")
private AuthenticationManager authenticationManager;
private boolean continueFilterChainOnUnsuccessfulAuthentication = true;
@ -108,9 +110,9 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
private boolean invalidateSessionOnPrincipalChange = true;
private AuthenticationSuccessHandler authenticationSuccessHandler = null;
private @Nullable AuthenticationSuccessHandler authenticationSuccessHandler = null;
private AuthenticationFailureHandler authenticationFailureHandler = null;
private @Nullable AuthenticationFailureHandler authenticationFailureHandler = null;
private RequestMatcher requiresAuthenticationRequestMatcher = new PreAuthenticatedProcessingRequestMatcher();
@ -357,14 +359,14 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
/**
* Override to extract the principal information from the current request
*/
protected abstract Object getPreAuthenticatedPrincipal(HttpServletRequest request);
protected abstract @Nullable Object getPreAuthenticatedPrincipal(HttpServletRequest request);
/**
* Override to extract the credentials (if applicable) from the current request.
* Should not return null for a valid principal, though some implementations may
* return a dummy value.
*/
protected abstract Object getPreAuthenticatedCredentials(HttpServletRequest request);
protected abstract @Nullable Object getPreAuthenticatedCredentials(HttpServletRequest request);
/**
* Request matcher for default auth check logic

View File

@ -18,6 +18,7 @@ package org.springframework.security.web.authentication.preauth;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.Ordered;
@ -51,6 +52,7 @@ public class PreAuthenticatedAuthenticationProvider implements AuthenticationPro
private static final Log logger = LogFactory.getLog(PreAuthenticatedAuthenticationProvider.class);
@SuppressWarnings("NullAway.Init")
private AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> preAuthenticatedUserDetailsService;
private UserDetailsChecker userDetailsChecker = new AccountStatusUserDetailsChecker();
@ -74,7 +76,7 @@ public class PreAuthenticatedAuthenticationProvider implements AuthenticationPro
* be ignored to allow other providers to authenticate it.
*/
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
public @Nullable Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (!supports(authentication.getClass())) {
return null;
}

View File

@ -18,6 +18,8 @@ package org.springframework.security.web.authentication.preauth;
import java.util.Collection;
import org.jspecify.annotations.Nullable;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
@ -34,7 +36,7 @@ public class PreAuthenticatedAuthenticationToken extends AbstractAuthenticationT
private final Object principal;
private final Object credentials;
private final @Nullable Object credentials;
/**
* Constructor used for an authentication request. The
@ -43,7 +45,7 @@ public class PreAuthenticatedAuthenticationToken extends AbstractAuthenticationT
* @param aPrincipal The pre-authenticated principal
* @param aCredentials The pre-authenticated credentials
*/
public PreAuthenticatedAuthenticationToken(Object aPrincipal, Object aCredentials) {
public PreAuthenticatedAuthenticationToken(Object aPrincipal, @Nullable Object aCredentials) {
super(null);
this.principal = aPrincipal;
this.credentials = aCredentials;
@ -56,7 +58,7 @@ public class PreAuthenticatedAuthenticationToken extends AbstractAuthenticationT
* @param aPrincipal The authenticated principal
* @param anAuthorities The granted authorities
*/
public PreAuthenticatedAuthenticationToken(Object aPrincipal, Object aCredentials,
public PreAuthenticatedAuthenticationToken(Object aPrincipal, @Nullable Object aCredentials,
Collection<? extends GrantedAuthority> anAuthorities) {
super(anAuthorities);
this.principal = aPrincipal;
@ -68,7 +70,7 @@ public class PreAuthenticatedAuthenticationToken extends AbstractAuthenticationT
* Get the credentials
*/
@Override
public Object getCredentials() {
public @Nullable Object getCredentials() {
return this.credentials;
}

View File

@ -17,6 +17,7 @@
package org.springframework.security.web.authentication.preauth;
import jakarta.servlet.http.HttpServletRequest;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
@ -46,7 +47,7 @@ public class RequestAttributeAuthenticationFilter extends AbstractPreAuthenticat
private String principalEnvironmentVariable = "REMOTE_USER";
private String credentialsEnvironmentVariable;
private @Nullable String credentialsEnvironmentVariable;
private boolean exceptionIfVariableMissing = true;

View File

@ -17,6 +17,7 @@
package org.springframework.security.web.authentication.preauth;
import jakarta.servlet.http.HttpServletRequest;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
@ -47,7 +48,7 @@ public class RequestHeaderAuthenticationFilter extends AbstractPreAuthenticatedP
private String principalRequestHeader = "SM_USER";
private String credentialsRequestHeader;
private @Nullable String credentialsRequestHeader;
private boolean exceptionIfHeaderMissing = true;

View File

@ -52,6 +52,7 @@ public class J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource implements
/**
* The role attributes returned by the configured {@code MappableAttributesRetriever}
*/
@SuppressWarnings("NullAway.Init")
protected Set<String> j2eeMappableRoles;
protected Attributes2GrantedAuthoritiesMapper j2eeUserRoles2GrantedAuthoritiesMapper = new SimpleAttributes2GrantedAuthoritiesMapper();

View File

@ -17,6 +17,7 @@
package org.springframework.security.web.authentication.preauth.j2ee;
import jakarta.servlet.http.HttpServletRequest;
import org.jspecify.annotations.Nullable;
import org.springframework.core.log.LogMessage;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
@ -35,7 +36,7 @@ public class J2eePreAuthenticatedProcessingFilter extends AbstractPreAuthenticat
* Return the J2EE user name.
*/
@Override
protected Object getPreAuthenticatedPrincipal(HttpServletRequest httpRequest) {
protected @Nullable Object getPreAuthenticatedPrincipal(HttpServletRequest httpRequest) {
Object principal = (httpRequest.getUserPrincipal() != null) ? httpRequest.getUserPrincipal().getName() : null;
this.logger.debug(LogMessage.format("PreAuthenticated J2EE principal: %s", principal));
return principal;

View File

@ -32,6 +32,7 @@ import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
@ -60,9 +61,9 @@ public class WebXmlMappableAttributesRetriever
protected final Log logger = LogFactory.getLog(getClass());
private ResourceLoader resourceLoader;
private @Nullable ResourceLoader resourceLoader;
private Set<String> mappableAttributes;
private Set<String> mappableAttributes = new HashSet<>();
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
@ -81,6 +82,7 @@ public class WebXmlMappableAttributesRetriever
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(this.resourceLoader, "resourceLoader cannot be null");
Resource webXml = this.resourceLoader.getResource("/WEB-INF/web.xml");
Document doc = getDocument(webXml.getInputStream());
NodeList webApp = doc.getElementsByTagName("web-app");

View File

@ -21,4 +21,7 @@
* into the security methods exposed by {@code HttpServletRequest} to build
* {@code Authentication} object for the user.
*/
@NullMarked
package org.springframework.security.web.authentication.preauth.j2ee;
import org.jspecify.annotations.NullMarked;

View File

@ -18,4 +18,7 @@
* Support for "pre-authenticated" scenarios, where Spring Security assumes the incoming
* request has already been authenticated by some externally configured system.
*/
@NullMarked
package org.springframework.security.web.authentication.preauth;
import org.jspecify.annotations.NullMarked;

View File

@ -30,6 +30,7 @@ import javax.security.auth.Subject;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.core.log.LogMessage;
@ -50,16 +51,16 @@ final class DefaultWASUsernameAndGroupsExtractor implements WASUsernameAndGroups
private static final String USER_REGISTRY = "UserRegistry";
private static Method getRunAsSubject = null;
private static @Nullable Method getRunAsSubject = null;
private static Method getGroupsForUser = null;
private static @Nullable Method getGroupsForUser = null;
private static Method getSecurityName = null;
private static @Nullable Method getSecurityName = null;
private static Method narrow = null;
private static @Nullable Method narrow = null;
// SEC-803
private static Class<?> wsCredentialClass = null;
private static @Nullable Class<?> wsCredentialClass = null;
@Override
public List<String> getGroupsForCurrentUser() {
@ -67,7 +68,7 @@ final class DefaultWASUsernameAndGroupsExtractor implements WASUsernameAndGroups
}
@Override
public String getCurrentUserName() {
public @Nullable String getCurrentUserName() {
return getSecurityName(getRunAsSubject());
}
@ -76,7 +77,7 @@ final class DefaultWASUsernameAndGroupsExtractor implements WASUsernameAndGroups
* @param subject The subject for which to retrieve the security name
* @return String the security name for the given subject
*/
private static String getSecurityName(final Subject subject) {
private static @Nullable String getSecurityName(final Subject subject) {
logger.debug(LogMessage.format("Determining Websphere security name for subject %s", subject));
String userSecurityName = null;
if (subject != null) {
@ -116,7 +117,7 @@ final class DefaultWASUsernameAndGroupsExtractor implements WASUsernameAndGroups
* @return the WebSphere group names for the given security name
*/
@SuppressWarnings("unchecked")
private static List<String> getWebSphereGroups(final String securityName) {
private static List<String> getWebSphereGroups(final @Nullable String securityName) {
Context context = null;
try {
// TODO: Cache UserRegistry object
@ -140,7 +141,7 @@ final class DefaultWASUsernameAndGroupsExtractor implements WASUsernameAndGroups
}
}
private static void closeContext(Context context) {
private static void closeContext(@Nullable Context context) {
try {
if (context != null) {
context.close();
@ -151,7 +152,7 @@ final class DefaultWASUsernameAndGroupsExtractor implements WASUsernameAndGroups
}
}
private static Object invokeMethod(Method method, Object instance, Object... args) {
private static Object invokeMethod(Method method, @Nullable Object instance, Object... args) {
try {
return method.invoke(instance, args);
}

View File

@ -18,6 +18,8 @@ package org.springframework.security.web.authentication.preauth.websphere;
import java.util.List;
import org.jspecify.annotations.Nullable;
/**
* Provides indirection between classes using websphere and the actual container
* interaction, allowing for easier unit testing.
@ -31,6 +33,6 @@ interface WASUsernameAndGroupsExtractor {
List<String> getGroupsForCurrentUser();
String getCurrentUserName();
@Nullable String getCurrentUserName();
}

Some files were not shown because too many files have changed in this diff Show More