1818
1919import java .util .ArrayList ;
2020import java .util .List ;
21+ import java .util .function .Supplier ;
2122
2223import io .micrometer .observation .ObservationRegistry ;
2324import jakarta .servlet .Filter ;
2425import jakarta .servlet .ServletContext ;
2526import jakarta .servlet .http .HttpServletRequest ;
2627import org .apache .commons .logging .Log ;
2728import org .apache .commons .logging .LogFactory ;
29+ import org .jspecify .annotations .NullMarked ;
30+ import org .jspecify .annotations .Nullable ;
2831
2932import org .springframework .beans .BeansException ;
3033import org .springframework .beans .factory .NoSuchBeanDefinitionException ;
3134import org .springframework .beans .factory .ObjectProvider ;
3235import org .springframework .context .ApplicationContext ;
3336import org .springframework .context .ApplicationContextAware ;
3437import org .springframework .core .ResolvableType ;
38+ import org .springframework .expression .EvaluationContext ;
3539import org .springframework .security .access .PermissionEvaluator ;
40+ import org .springframework .security .access .expression .AbstractSecurityExpressionHandler ;
3641import org .springframework .security .access .expression .SecurityExpressionHandler ;
42+ import org .springframework .security .access .expression .SecurityExpressionOperations ;
3743import org .springframework .security .access .hierarchicalroles .RoleHierarchy ;
3844import org .springframework .security .authorization .AuthorizationDecision ;
3945import org .springframework .security .authorization .AuthorizationManager ;
4652import org .springframework .security .config .annotation .web .configuration .EnableWebSecurity ;
4753import org .springframework .security .config .annotation .web .configuration .WebSecurityConfiguration ;
4854import org .springframework .security .config .annotation .web .configuration .WebSecurityCustomizer ;
55+ import org .springframework .security .core .Authentication ;
4956import org .springframework .security .core .context .SecurityContext ;
5057import org .springframework .security .web .DefaultSecurityFilterChain ;
5158import org .springframework .security .web .FilterChainProxy ;
5865import org .springframework .security .web .access .PathPatternRequestTransformer ;
5966import org .springframework .security .web .access .RequestMatcherDelegatingWebInvocationPrivilegeEvaluator ;
6067import org .springframework .security .web .access .WebInvocationPrivilegeEvaluator ;
61- import org .springframework .security .web .access .expression .DefaultWebSecurityExpressionHandler ;
68+ import org .springframework .security .web .access .expression .DefaultHttpSecurityExpressionHandler ;
6269import org .springframework .security .web .access .intercept .AuthorizationFilter ;
6370import org .springframework .security .web .access .intercept .FilterSecurityInterceptor ;
6471import org .springframework .security .web .access .intercept .RequestAuthorizationContext ;
7481import org .springframework .security .web .util .matcher .RequestMatcher ;
7582import org .springframework .security .web .util .matcher .RequestMatcherEntry ;
7683import org .springframework .util .Assert ;
84+ import org .springframework .util .ClassUtils ;
7785import org .springframework .web .context .ServletContextAware ;
7886import org .springframework .web .filter .DelegatingFilterProxy ;
7987
99107public final class WebSecurity extends AbstractConfiguredSecurityBuilder <Filter , WebSecurity >
100108 implements SecurityBuilder <Filter >, ApplicationContextAware , ServletContextAware {
101109
110+ private static final boolean USING_ACCESS = ClassUtils
111+ .isPresent ("org.springframework.security.access.SecurityConfig" , null );
112+
102113 private final Log logger = LogFactory .getLog (getClass ());
103114
104115 private final List <RequestMatcher > ignoredRequests = new ArrayList <>();
@@ -122,9 +133,10 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
122133
123134 private HttpServletRequestTransformer privilegeEvaluatorRequestTransformer ;
124135
125- private DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler ();
136+ private DefaultHttpSecurityExpressionHandler defaultExpressionHandler = new DefaultHttpSecurityExpressionHandler ();
126137
127- private SecurityExpressionHandler <FilterInvocation > expressionHandler = this .defaultWebSecurityExpressionHandler ;
138+ private SecurityExpressionHandler <FilterInvocation > expressionHandler = new SecurityExpressionHandlerAdapter (
139+ this .defaultExpressionHandler );
128140
129141 private Runnable postBuildAction = () -> {
130142 };
@@ -240,7 +252,7 @@ public WebSecurity privilegeEvaluator(WebInvocationPrivilegeEvaluator privilegeE
240252
241253 /**
242254 * Set the {@link SecurityExpressionHandler} to be used. If this is not specified,
243- * then a {@link DefaultWebSecurityExpressionHandler } will be used.
255+ * then a {@link DefaultHttpSecurityExpressionHandler } will be used.
244256 * @param expressionHandler the {@link SecurityExpressionHandler} to use
245257 * @return the {@link WebSecurity} for further customizations
246258 */
@@ -361,19 +373,9 @@ private boolean addAuthorizationManager(SecurityFilterChain securityFilterChain,
361373 RequestMatcherDelegatingAuthorizationManager .Builder builder ) {
362374 boolean mappings = false ;
363375 for (Filter filter : securityFilterChain .getFilters ()) {
364- if (filter instanceof FilterSecurityInterceptor securityInterceptor ) {
365- DefaultWebInvocationPrivilegeEvaluator privilegeEvaluator = new DefaultWebInvocationPrivilegeEvaluator (
366- securityInterceptor );
367- privilegeEvaluator .setServletContext (this .servletContext );
368- AuthorizationManager <RequestAuthorizationContext > authorizationManager = (authentication , context ) -> {
369- HttpServletRequest request = context .getRequest ();
370- boolean result = privilegeEvaluator .isAllowed (request .getContextPath (), request .getRequestURI (),
371- request .getMethod (), authentication .get ());
372- return new AuthorizationDecision (result );
373- };
374- builder .add (securityFilterChain ::matches , authorizationManager );
375- mappings = true ;
376- continue ;
376+ if (USING_ACCESS ) {
377+ mappings = AccessComponents .addAuthorizationManager (filter , this .servletContext , builder ,
378+ securityFilterChain );
377379 }
378380 if (filter instanceof AuthorizationFilter authorization ) {
379381 AuthorizationManager <HttpServletRequest > authorizationManager = authorization .getAuthorizationManager ();
@@ -388,15 +390,14 @@ private boolean addAuthorizationManager(SecurityFilterChain securityFilterChain,
388390
389391 @ Override
390392 public void setApplicationContext (ApplicationContext applicationContext ) throws BeansException {
391- this .defaultWebSecurityExpressionHandler .setApplicationContext (applicationContext );
393+ this .defaultExpressionHandler .setApplicationContext (applicationContext );
392394 try {
393- this .defaultWebSecurityExpressionHandler .setRoleHierarchy (applicationContext .getBean (RoleHierarchy .class ));
395+ this .defaultExpressionHandler .setRoleHierarchy (applicationContext .getBean (RoleHierarchy .class ));
394396 }
395397 catch (NoSuchBeanDefinitionException ex ) {
396398 }
397399 try {
398- this .defaultWebSecurityExpressionHandler
399- .setPermissionEvaluator (applicationContext .getBean (PermissionEvaluator .class ));
400+ this .defaultExpressionHandler .setPermissionEvaluator (applicationContext .getBean (PermissionEvaluator .class ));
400401 }
401402 catch (NoSuchBeanDefinitionException ex ) {
402403 }
@@ -463,4 +464,76 @@ public WebSecurity and() {
463464
464465 }
465466
467+ @ NullMarked
468+ private static final class SecurityExpressionHandlerAdapter
469+ extends AbstractSecurityExpressionHandler <FilterInvocation > {
470+
471+ private final AbstractSecurityExpressionHandler <RequestAuthorizationContext > delegate ;
472+
473+ private SecurityExpressionHandlerAdapter (
474+ AbstractSecurityExpressionHandler <RequestAuthorizationContext > delegate ) {
475+ this .delegate = delegate ;
476+ }
477+
478+ @ Override
479+ public EvaluationContext createEvaluationContext (Supplier <? extends @ Nullable Authentication > authentication ,
480+ FilterInvocation invocation ) {
481+ RequestAuthorizationContext context = new RequestAuthorizationContext (invocation .getRequest ());
482+ return this .delegate .createEvaluationContext (authentication , context );
483+ }
484+
485+ @ Override
486+ protected SecurityExpressionOperations createSecurityExpressionRoot (@ Nullable Authentication authentication ,
487+ FilterInvocation invocation ) {
488+ RequestAuthorizationContext context = new RequestAuthorizationContext (invocation .getRequest ());
489+ Object operations = this .delegate .createEvaluationContext (authentication , context )
490+ .getRootObject ()
491+ .getValue ();
492+ Assert .isInstanceOf (SecurityExpressionOperations .class , operations ,
493+ "createEvaluationContext must have a SecurityExpressionOperations instance as its root" );
494+ return (SecurityExpressionOperations ) operations ;
495+ }
496+
497+ @ Override
498+ public void setApplicationContext (ApplicationContext context ) {
499+ this .delegate .setApplicationContext (context );
500+ super .setApplicationContext (context );
501+ }
502+
503+ @ Override
504+ public void setPermissionEvaluator (PermissionEvaluator permissionEvaluator ) {
505+ this .delegate .setPermissionEvaluator (permissionEvaluator );
506+ super .setPermissionEvaluator (permissionEvaluator );
507+ }
508+
509+ @ Override
510+ public void setRoleHierarchy (@ Nullable RoleHierarchy roleHierarchy ) {
511+ this .delegate .setRoleHierarchy (roleHierarchy );
512+ super .setRoleHierarchy (roleHierarchy );
513+ }
514+
515+ }
516+
517+ private static final class AccessComponents {
518+
519+ private static boolean addAuthorizationManager (Filter filter , ServletContext servletContext ,
520+ RequestMatcherDelegatingAuthorizationManager .Builder builder , SecurityFilterChain securityFilterChain ) {
521+ if (filter instanceof FilterSecurityInterceptor securityInterceptor ) {
522+ DefaultWebInvocationPrivilegeEvaluator privilegeEvaluator = new DefaultWebInvocationPrivilegeEvaluator (
523+ securityInterceptor );
524+ privilegeEvaluator .setServletContext (servletContext );
525+ AuthorizationManager <RequestAuthorizationContext > authorizationManager = (authentication , context ) -> {
526+ HttpServletRequest request = context .getRequest ();
527+ boolean result = privilegeEvaluator .isAllowed (request .getContextPath (), request .getRequestURI (),
528+ request .getMethod (), authentication .get ());
529+ return new AuthorizationDecision (result );
530+ };
531+ builder .add (securityFilterChain ::matches , authorizationManager );
532+ return true ;
533+ }
534+ return false ;
535+ }
536+
537+ }
538+
466539}
0 commit comments