Remove Direct Runtime Dependency on Access API

Issue gh-17847
This commit is contained in:
Josh Cummings 2025-09-02 18:45:09 -06:00
parent 10935632ee
commit 3a1692f3c3
No known key found for this signature in database
GPG Key ID: 869B37A20E876129
8 changed files with 196 additions and 66 deletions

View File

@ -23,9 +23,7 @@ import java.util.Map;
import jakarta.servlet.Filter; import jakarta.servlet.Filter;
import org.springframework.security.web.access.ExceptionTranslationFilter; import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
import org.springframework.security.web.access.intercept.AuthorizationFilter; import org.springframework.security.web.access.intercept.AuthorizationFilter;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter; import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
import org.springframework.security.web.authentication.AuthenticationFilter; import org.springframework.security.web.authentication.AuthenticationFilter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@ -78,7 +76,7 @@ final class FilterOrderRegistration {
Step order = new Step(INITIAL_ORDER, ORDER_STEP); Step order = new Step(INITIAL_ORDER, ORDER_STEP);
put(DisableEncodeUrlFilter.class, order.next()); put(DisableEncodeUrlFilter.class, order.next());
put(ForceEagerSessionCreationFilter.class, order.next()); put(ForceEagerSessionCreationFilter.class, order.next());
put(ChannelProcessingFilter.class, order.next()); this.filterToOrder.put("org.springframework.security.web.access.channel.ChannelProcessingFilter", order.next());
put(HttpsRedirectFilter.class, order.next()); put(HttpsRedirectFilter.class, order.next());
order.next(); // gh-8105 order.next(); // gh-8105
put(WebAsyncManagerIntegrationFilter.class, order.next()); put(WebAsyncManagerIntegrationFilter.class, order.next());
@ -126,7 +124,8 @@ final class FilterOrderRegistration {
order.next()); order.next());
put(SessionManagementFilter.class, order.next()); put(SessionManagementFilter.class, order.next());
put(ExceptionTranslationFilter.class, order.next()); put(ExceptionTranslationFilter.class, order.next());
put(FilterSecurityInterceptor.class, order.next()); this.filterToOrder.put("org.springframework.security.web.access.intercept.FilterSecurityInterceptor",
order.next());
put(AuthorizationFilter.class, order.next()); put(AuthorizationFilter.class, order.next());
put(SwitchUserFilter.class, order.next()); put(SwitchUserFilter.class, order.next());
} }

View File

@ -18,6 +18,7 @@ package org.springframework.security.config.annotation.web.builders;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Supplier;
import io.micrometer.observation.ObservationRegistry; import io.micrometer.observation.ObservationRegistry;
import jakarta.servlet.Filter; import jakarta.servlet.Filter;
@ -25,6 +26,8 @@ import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.NoSuchBeanDefinitionException;
@ -32,8 +35,11 @@ import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationContextAware;
import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableType;
import org.springframework.expression.EvaluationContext;
import org.springframework.security.access.PermissionEvaluator; import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.access.expression.AbstractSecurityExpressionHandler;
import org.springframework.security.access.expression.SecurityExpressionHandler; import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.access.expression.SecurityExpressionOperations;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy; import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager; import org.springframework.security.authorization.AuthorizationManager;
@ -46,6 +52,7 @@ import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer; import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.web.DefaultSecurityFilterChain; import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.FilterChainProxy; import org.springframework.security.web.FilterChainProxy;
@ -58,7 +65,7 @@ import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEval
import org.springframework.security.web.access.PathPatternRequestTransformer; import org.springframework.security.web.access.PathPatternRequestTransformer;
import org.springframework.security.web.access.RequestMatcherDelegatingWebInvocationPrivilegeEvaluator; import org.springframework.security.web.access.RequestMatcherDelegatingWebInvocationPrivilegeEvaluator;
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator; import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler; import org.springframework.security.web.access.expression.DefaultHttpSecurityExpressionHandler;
import org.springframework.security.web.access.intercept.AuthorizationFilter; import org.springframework.security.web.access.intercept.AuthorizationFilter;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.access.intercept.RequestAuthorizationContext; import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
@ -74,6 +81,7 @@ import org.springframework.security.web.util.matcher.AnyRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcherEntry; import org.springframework.security.web.util.matcher.RequestMatcherEntry;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.web.context.ServletContextAware; import org.springframework.web.context.ServletContextAware;
import org.springframework.web.filter.DelegatingFilterProxy; import org.springframework.web.filter.DelegatingFilterProxy;
@ -99,6 +107,9 @@ import org.springframework.web.filter.DelegatingFilterProxy;
public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter, WebSecurity> public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter, WebSecurity>
implements SecurityBuilder<Filter>, ApplicationContextAware, ServletContextAware { implements SecurityBuilder<Filter>, ApplicationContextAware, ServletContextAware {
private static final boolean USING_ACCESS = ClassUtils
.isPresent("org.springframework.security.access.SecurityConfig", null);
private final Log logger = LogFactory.getLog(getClass()); private final Log logger = LogFactory.getLog(getClass());
private final List<RequestMatcher> ignoredRequests = new ArrayList<>(); private final List<RequestMatcher> ignoredRequests = new ArrayList<>();
@ -122,9 +133,10 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
private HttpServletRequestTransformer privilegeEvaluatorRequestTransformer; private HttpServletRequestTransformer privilegeEvaluatorRequestTransformer;
private DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler(); private DefaultHttpSecurityExpressionHandler defaultExpressionHandler = new DefaultHttpSecurityExpressionHandler();
private SecurityExpressionHandler<FilterInvocation> expressionHandler = this.defaultWebSecurityExpressionHandler; private SecurityExpressionHandler<FilterInvocation> expressionHandler = new SecurityExpressionHandlerAdapter(
this.defaultExpressionHandler);
private Runnable postBuildAction = () -> { private Runnable postBuildAction = () -> {
}; };
@ -240,7 +252,7 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
/** /**
* Set the {@link SecurityExpressionHandler} to be used. If this is not specified, * Set the {@link SecurityExpressionHandler} to be used. If this is not specified,
* then a {@link DefaultWebSecurityExpressionHandler} will be used. * then a {@link DefaultHttpSecurityExpressionHandler} will be used.
* @param expressionHandler the {@link SecurityExpressionHandler} to use * @param expressionHandler the {@link SecurityExpressionHandler} to use
* @return the {@link WebSecurity} for further customizations * @return the {@link WebSecurity} for further customizations
*/ */
@ -361,19 +373,9 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
RequestMatcherDelegatingAuthorizationManager.Builder builder) { RequestMatcherDelegatingAuthorizationManager.Builder builder) {
boolean mappings = false; boolean mappings = false;
for (Filter filter : securityFilterChain.getFilters()) { for (Filter filter : securityFilterChain.getFilters()) {
if (filter instanceof FilterSecurityInterceptor securityInterceptor) { if (USING_ACCESS) {
DefaultWebInvocationPrivilegeEvaluator privilegeEvaluator = new DefaultWebInvocationPrivilegeEvaluator( mappings = AccessComponents.addAuthorizationManager(filter, this.servletContext, builder,
securityInterceptor); securityFilterChain);
privilegeEvaluator.setServletContext(this.servletContext);
AuthorizationManager<RequestAuthorizationContext> authorizationManager = (authentication, context) -> {
HttpServletRequest request = context.getRequest();
boolean result = privilegeEvaluator.isAllowed(request.getContextPath(), request.getRequestURI(),
request.getMethod(), authentication.get());
return new AuthorizationDecision(result);
};
builder.add(securityFilterChain::matches, authorizationManager);
mappings = true;
continue;
} }
if (filter instanceof AuthorizationFilter authorization) { if (filter instanceof AuthorizationFilter authorization) {
AuthorizationManager<HttpServletRequest> authorizationManager = authorization.getAuthorizationManager(); AuthorizationManager<HttpServletRequest> authorizationManager = authorization.getAuthorizationManager();
@ -388,15 +390,14 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
@Override @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.defaultWebSecurityExpressionHandler.setApplicationContext(applicationContext); this.defaultExpressionHandler.setApplicationContext(applicationContext);
try { try {
this.defaultWebSecurityExpressionHandler.setRoleHierarchy(applicationContext.getBean(RoleHierarchy.class)); this.defaultExpressionHandler.setRoleHierarchy(applicationContext.getBean(RoleHierarchy.class));
} }
catch (NoSuchBeanDefinitionException ex) { catch (NoSuchBeanDefinitionException ex) {
} }
try { try {
this.defaultWebSecurityExpressionHandler this.defaultExpressionHandler.setPermissionEvaluator(applicationContext.getBean(PermissionEvaluator.class));
.setPermissionEvaluator(applicationContext.getBean(PermissionEvaluator.class));
} }
catch (NoSuchBeanDefinitionException ex) { catch (NoSuchBeanDefinitionException ex) {
} }
@ -463,4 +464,76 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
} }
@NullMarked
private static final class SecurityExpressionHandlerAdapter
extends AbstractSecurityExpressionHandler<FilterInvocation> {
private final AbstractSecurityExpressionHandler<RequestAuthorizationContext> delegate;
private SecurityExpressionHandlerAdapter(
AbstractSecurityExpressionHandler<RequestAuthorizationContext> delegate) {
this.delegate = delegate;
}
@Override
public EvaluationContext createEvaluationContext(Supplier<? extends @Nullable Authentication> authentication,
FilterInvocation invocation) {
RequestAuthorizationContext context = new RequestAuthorizationContext(invocation.getRequest());
return this.delegate.createEvaluationContext(authentication, context);
}
@Override
protected SecurityExpressionOperations createSecurityExpressionRoot(@Nullable Authentication authentication,
FilterInvocation invocation) {
RequestAuthorizationContext context = new RequestAuthorizationContext(invocation.getRequest());
Object operations = this.delegate.createEvaluationContext(authentication, context)
.getRootObject()
.getValue();
Assert.isInstanceOf(SecurityExpressionOperations.class, operations,
"createEvaluationContext must have a SecurityExpressionOperations instance as its root");
return (SecurityExpressionOperations) operations;
}
@Override
public void setApplicationContext(ApplicationContext context) {
this.delegate.setApplicationContext(context);
super.setApplicationContext(context);
}
@Override
public void setPermissionEvaluator(PermissionEvaluator permissionEvaluator) {
this.delegate.setPermissionEvaluator(permissionEvaluator);
super.setPermissionEvaluator(permissionEvaluator);
}
@Override
public void setRoleHierarchy(@Nullable RoleHierarchy roleHierarchy) {
this.delegate.setRoleHierarchy(roleHierarchy);
super.setRoleHierarchy(roleHierarchy);
}
}
private static final class AccessComponents {
private static boolean addAuthorizationManager(Filter filter, ServletContext servletContext,
RequestMatcherDelegatingAuthorizationManager.Builder builder, SecurityFilterChain securityFilterChain) {
if (filter instanceof FilterSecurityInterceptor securityInterceptor) {
DefaultWebInvocationPrivilegeEvaluator privilegeEvaluator = new DefaultWebInvocationPrivilegeEvaluator(
securityInterceptor);
privilegeEvaluator.setServletContext(servletContext);
AuthorizationManager<RequestAuthorizationContext> authorizationManager = (authentication, context) -> {
HttpServletRequest request = context.getRequest();
boolean result = privilegeEvaluator.isAllowed(request.getContextPath(), request.getRequestURI(),
request.getMethod(), authentication.get());
return new AuthorizationDecision(result);
};
builder.add(securityFilterChain::matches, authorizationManager);
return true;
}
return false;
}
}
} }

View File

@ -29,6 +29,7 @@ import org.springframework.security.web.UnreachableFilterChainException;
import org.springframework.security.web.access.intercept.AuthorizationFilter; import org.springframework.security.web.access.intercept.AuthorizationFilter;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.util.matcher.AnyRequestMatcher; import org.springframework.security.web.util.matcher.AnyRequestMatcher;
import org.springframework.util.ClassUtils;
/** /**
* A filter chain validator for filter chains built by {@link WebSecurity} * A filter chain validator for filter chains built by {@link WebSecurity}
@ -39,6 +40,9 @@ import org.springframework.security.web.util.matcher.AnyRequestMatcher;
*/ */
final class WebSecurityFilterChainValidator implements FilterChainProxy.FilterChainValidator { final class WebSecurityFilterChainValidator implements FilterChainProxy.FilterChainValidator {
private static final boolean USING_ACCESS = ClassUtils
.isPresent("org.springframework.security.access.SecurityConfig", null);
private final Log logger = LogFactory.getLog(getClass()); private final Log logger = LogFactory.getLog(getClass());
@Override @Override
@ -93,7 +97,7 @@ final class WebSecurityFilterChainValidator implements FilterChainProxy.FilterCh
if (filter instanceof AuthorizationFilter) { if (filter instanceof AuthorizationFilter) {
authorizationFilter = filter; authorizationFilter = filter;
} }
if (filter instanceof FilterSecurityInterceptor) { if (USING_ACCESS && AccessComponents.isFilterSecurityInterceptor(filter)) {
filterSecurityInterceptor = filter; filterSecurityInterceptor = filter;
} }
} }
@ -110,4 +114,12 @@ final class WebSecurityFilterChainValidator implements FilterChainProxy.FilterCh
} }
} }
private static final class AccessComponents {
private static boolean isFilterSecurityInterceptor(Filter filter) {
return filter instanceof FilterSecurityInterceptor;
}
}
} }

View File

@ -56,9 +56,13 @@ import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter; import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
import org.springframework.security.web.session.SessionManagementFilter; import org.springframework.security.web.session.SessionManagementFilter;
import org.springframework.security.web.util.matcher.AnyRequestMatcher; import org.springframework.security.web.util.matcher.AnyRequestMatcher;
import org.springframework.util.ClassUtils;
public class DefaultFilterChainValidator implements FilterChainProxy.FilterChainValidator { public class DefaultFilterChainValidator implements FilterChainProxy.FilterChainValidator {
private static final boolean USING_ACCESS = ClassUtils
.isPresent("org.springframework.security.access.SecurityConfig", null);
private static final Authentication TEST = new TestingAuthenticationToken("", "", Collections.emptyList()); private static final Authentication TEST = new TestingAuthenticationToken("", "", Collections.emptyList());
private final Log logger = LogFactory.getLog(getClass()); private final Log logger = LogFactory.getLog(getClass());
@ -120,7 +124,7 @@ public class DefaultFilterChainValidator implements FilterChainProxy.FilterChain
if (filter instanceof AuthorizationFilter) { if (filter instanceof AuthorizationFilter) {
authorizationFilter = filter; authorizationFilter = filter;
} }
if (filter instanceof FilterSecurityInterceptor) { if (USING_ACCESS && AccessComponents.isFilterSecurityInterceptor(filter)) {
filterSecurityInterceptor = filter; filterSecurityInterceptor = filter;
} }
} }
@ -138,7 +142,7 @@ public class DefaultFilterChainValidator implements FilterChainProxy.FilterChain
} }
@SuppressWarnings({ "unchecked" }) @SuppressWarnings({ "unchecked" })
private <F extends Filter> F getFilter(Class<F> type, List<Filter> filters) { private static <F extends Filter> F getFilter(Class<F> type, List<Filter> filters) {
for (Filter f : filters) { for (Filter f : filters) {
if (type.isAssignableFrom(f.getClass())) { if (type.isAssignableFrom(f.getClass())) {
return (F) f; return (F) f;
@ -158,7 +162,9 @@ public class DefaultFilterChainValidator implements FilterChainProxy.FilterChain
checkForDuplicates(SecurityContextHolderAwareRequestFilter.class, filters); checkForDuplicates(SecurityContextHolderAwareRequestFilter.class, filters);
checkForDuplicates(JaasApiIntegrationFilter.class, filters); checkForDuplicates(JaasApiIntegrationFilter.class, filters);
checkForDuplicates(ExceptionTranslationFilter.class, filters); checkForDuplicates(ExceptionTranslationFilter.class, filters);
checkForDuplicates(FilterSecurityInterceptor.class, filters); if (USING_ACCESS) {
checkForDuplicates(AccessComponents.getFilterSecurityInterceptorClass(), filters);
}
checkForDuplicates(AuthorizationFilter.class, filters); checkForDuplicates(AuthorizationFilter.class, filters);
} }
@ -243,19 +249,11 @@ public class DefaultFilterChainValidator implements FilterChainProxy.FilterChain
} }
private boolean checkLoginPageIsPublic(List<Filter> filters, HttpServletRequest loginRequest) { private boolean checkLoginPageIsPublic(List<Filter> filters, HttpServletRequest loginRequest) {
FilterSecurityInterceptor authorizationInterceptor = getFilter(FilterSecurityInterceptor.class, filters); if (USING_ACCESS) {
if (authorizationInterceptor != null) { Boolean isPublic = AccessComponents.checkLoginPageIsPublic(filters, loginRequest);
FilterInvocationSecurityMetadataSource fids = authorizationInterceptor.getSecurityMetadataSource(); if (isPublic != null) {
Collection<ConfigAttribute> attributes = fids.getAttributes(loginRequest); return isPublic;
if (attributes == null) {
this.logger.debug("No access attributes defined for login page URL");
if (authorizationInterceptor.isRejectPublicInvocations()) {
this.logger.warn("FilterSecurityInterceptor is configured to reject public invocations."
+ " Your login page may not be accessible.");
}
return true;
} }
return false;
} }
AuthorizationFilter authorizationFilter = getFilter(AuthorizationFilter.class, filters); AuthorizationFilter authorizationFilter = getFilter(AuthorizationFilter.class, filters);
if (authorizationFilter != null) { if (authorizationFilter != null) {
@ -274,19 +272,11 @@ public class DefaultFilterChainValidator implements FilterChainProxy.FilterChain
private Supplier<Boolean> deriveAnonymousCheck(List<Filter> filters, HttpServletRequest loginRequest, private Supplier<Boolean> deriveAnonymousCheck(List<Filter> filters, HttpServletRequest loginRequest,
AnonymousAuthenticationToken token) { AnonymousAuthenticationToken token) {
FilterSecurityInterceptor authorizationInterceptor = getFilter(FilterSecurityInterceptor.class, filters); if (USING_ACCESS) {
if (authorizationInterceptor != null) { Supplier<Boolean> check = AccessComponents.getAnonymousCheck(filters, loginRequest, token);
return () -> { if (check != null) {
FilterInvocationSecurityMetadataSource source = authorizationInterceptor.getSecurityMetadataSource(); return check;
Collection<ConfigAttribute> attributes = source.getAttributes(loginRequest); }
try {
authorizationInterceptor.getAccessDecisionManager().decide(token, loginRequest, attributes);
return true;
}
catch (AccessDeniedException ex) {
return false;
}
};
} }
AuthorizationFilter authorizationFilter = getFilter(AuthorizationFilter.class, filters); AuthorizationFilter authorizationFilter = getFilter(AuthorizationFilter.class, filters);
if (authorizationFilter != null) { if (authorizationFilter != null) {
@ -300,4 +290,55 @@ public class DefaultFilterChainValidator implements FilterChainProxy.FilterChain
return () -> true; return () -> true;
} }
private static final class AccessComponents {
private static final Log logger = LogFactory.getLog(DefaultFilterChainValidator.class);
private static boolean isFilterSecurityInterceptor(Filter filter) {
return filter instanceof FilterSecurityInterceptor;
}
private static Class<FilterSecurityInterceptor> getFilterSecurityInterceptorClass() {
return FilterSecurityInterceptor.class;
}
private static Boolean checkLoginPageIsPublic(List<Filter> filters, HttpServletRequest loginRequest) {
FilterSecurityInterceptor authorizationInterceptor = getFilter(FilterSecurityInterceptor.class, filters);
if (authorizationInterceptor == null) {
return null;
}
FilterInvocationSecurityMetadataSource fids = authorizationInterceptor.getSecurityMetadataSource();
Collection<ConfigAttribute> attributes = fids.getAttributes(loginRequest);
if (attributes == null) {
logger.debug("No access attributes defined for login page URL");
if (authorizationInterceptor.isRejectPublicInvocations()) {
logger.warn("FilterSecurityInterceptor is configured to reject public invocations."
+ " Your login page may not be accessible.");
}
return true;
}
return false;
}
private static Supplier<Boolean> getAnonymousCheck(List<Filter> filters, HttpServletRequest loginRequest,
AnonymousAuthenticationToken token) {
FilterSecurityInterceptor authorizationInterceptor = getFilter(FilterSecurityInterceptor.class, filters);
if (authorizationInterceptor == null) {
return null;
}
return () -> {
FilterInvocationSecurityMetadataSource source = authorizationInterceptor.getSecurityMetadataSource();
Collection<ConfigAttribute> attributes = source.getAttributes(loginRequest);
try {
authorizationInterceptor.getAccessDecisionManager().decide(token, loginRequest, attributes);
return true;
}
catch (AccessDeniedException ex) {
return false;
}
};
}
}
} }

View File

@ -60,7 +60,6 @@ import org.springframework.security.web.access.AuthorizationManagerWebInvocation
import org.springframework.security.web.access.PathPatternRequestTransformer; import org.springframework.security.web.access.PathPatternRequestTransformer;
import org.springframework.security.web.access.RequestMatcherDelegatingWebInvocationPrivilegeEvaluator; import org.springframework.security.web.access.RequestMatcherDelegatingWebInvocationPrivilegeEvaluator;
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator; import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
import org.springframework.security.web.access.expression.WebExpressionAuthorizationManager; import org.springframework.security.web.access.expression.WebExpressionAuthorizationManager;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
@ -153,7 +152,7 @@ public class WebSecurityConfigurationTests {
public void loadConfigWhenDefaultSecurityExpressionHandlerThenDefaultIsRegistered() { public void loadConfigWhenDefaultSecurityExpressionHandlerThenDefaultIsRegistered() {
this.spring.register(WebSecurityExpressionHandlerDefaultsConfig.class).autowire(); this.spring.register(WebSecurityExpressionHandlerDefaultsConfig.class).autowire();
assertThat(this.spring.getContext().getBean(SecurityExpressionHandler.class)) assertThat(this.spring.getContext().getBean(SecurityExpressionHandler.class))
.isInstanceOf(DefaultWebSecurityExpressionHandler.class); .isInstanceOf(AbstractSecurityExpressionHandler.class);
} }
@Test @Test

View File

@ -23,7 +23,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.test.context.showcase.service.HelloMessageService; import org.springframework.security.test.context.showcase.service.HelloMessageService;
import org.springframework.security.test.context.showcase.service.MessageService; import org.springframework.security.test.context.showcase.service.MessageService;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
@ -48,7 +49,8 @@ public class WithMockUserParentTests extends WithMockUserParent {
} }
@Configuration @Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true) @EnableMethodSecurity
@EnableWebSecurity
@ComponentScan(basePackageClasses = HelloMessageService.class) @ComponentScan(basePackageClasses = HelloMessageService.class)
static class Config { static class Config {

View File

@ -31,7 +31,8 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AliasFor; import org.springframework.core.annotation.AliasFor;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.test.context.showcase.service.HelloMessageService; import org.springframework.security.test.context.showcase.service.HelloMessageService;
import org.springframework.security.test.context.showcase.service.MessageService; import org.springframework.security.test.context.showcase.service.MessageService;
import org.springframework.security.test.context.support.WithMockUser; import org.springframework.security.test.context.support.WithMockUser;
@ -53,8 +54,8 @@ public class WithMockUserTests {
@Test @Test
public void getMessageUnauthenticated() { public void getMessageUnauthenticated() {
assertThatExceptionOfType(AuthenticationCredentialsNotFoundException.class) assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> this.messageService.getMessage())
.isThrownBy(() -> this.messageService.getMessage()); .withRootCauseInstanceOf(AuthenticationCredentialsNotFoundException.class);
} }
@Test @Test
@ -104,7 +105,8 @@ public class WithMockUserTests {
assertThat(message).contains("admin").contains("ADMIN").contains("ROLE_ADMIN"); assertThat(message).contains("admin").contains("ADMIN").contains("ROLE_ADMIN");
} }
@EnableGlobalMethodSecurity(prePostEnabled = true) @EnableMethodSecurity
@EnableWebSecurity
@ComponentScan(basePackageClasses = HelloMessageService.class) @ComponentScan(basePackageClasses = HelloMessageService.class)
static class Config { static class Config {

View File

@ -25,7 +25,8 @@ import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
@ -51,8 +52,8 @@ public class WithUserDetailsTests {
@Test @Test
public void getMessageUnauthenticated() { public void getMessageUnauthenticated() {
assertThatExceptionOfType(AuthenticationCredentialsNotFoundException.class) assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> this.messageService.getMessage())
.isThrownBy(() -> this.messageService.getMessage()); .withRootCauseInstanceOf(AuthenticationCredentialsNotFoundException.class);
} }
@Test @Test
@ -84,7 +85,8 @@ public class WithUserDetailsTests {
} }
@Configuration @Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true) @EnableMethodSecurity
@EnableWebSecurity
@ComponentScan(basePackageClasses = HelloMessageService.class) @ComponentScan(basePackageClasses = HelloMessageService.class)
static class Config { static class Config {