From f68f477b66608a7ad928806f733b7aa0bd844c6c Mon Sep 17 00:00:00 2001
From: Luca Bassi <luca@argoware.com>
Date: Fri, 8 Nov 2024 18:58:18 +0100
Subject: [PATCH] Upgrade to Spring Security 5.8

---
 pom.xml                                       |   1 +
 .../StormMethodSecurityExpressionHandler.java |  10 +-
 .../authz/managers/ConsensusBasedManager.java |  75 ++++++++++
 .../FineGrainedAuthzManager.java}             |  26 ++--
 .../FineGrainedCopyMoveAuthzManager.java}     |  45 +++---
 .../LocalAuthzManager.java}                   |  47 +++---
 .../authz/managers/MacaroonAuthzManager.java  |  41 +++++
 .../PathAuthzPdpManagerSupport.java}          |  36 ++---
 .../managers/UnanimousDelegatedManager.java   |  81 ++++++++++
 .../WlcgScopeAuthzCopyMoveManager.java}       |  48 +++---
 .../WlcgScopeAuthzManager.java}               |  32 ++--
 .../authz/voters/MacaroonAuthzVoter.java      |  51 -------
 .../authz/voters/UnanimousDelegatedVoter.java | 104 -------------
 .../webdav/spring/web/SecurityConfig.java     | 141 ++++++++++--------
 ...ecurityExpressionHandlerConfiguration.java |  33 ----
 15 files changed, 404 insertions(+), 367 deletions(-)
 create mode 100644 src/main/java/org/italiangrid/storm/webdav/authz/managers/ConsensusBasedManager.java
 rename src/main/java/org/italiangrid/storm/webdav/authz/{voters/FineGrainedAuthzVoter.java => managers/FineGrainedAuthzManager.java} (64%)
 rename src/main/java/org/italiangrid/storm/webdav/authz/{voters/FineGrainedCopyMoveAuthzVoter.java => managers/FineGrainedCopyMoveAuthzManager.java} (59%)
 rename src/main/java/org/italiangrid/storm/webdav/authz/{voters/LocalAuthzVoter.java => managers/LocalAuthzManager.java} (61%)
 create mode 100644 src/main/java/org/italiangrid/storm/webdav/authz/managers/MacaroonAuthzManager.java
 rename src/main/java/org/italiangrid/storm/webdav/authz/{voters/PathAuthzPdpVoterSupport.java => managers/PathAuthzPdpManagerSupport.java} (75%)
 create mode 100644 src/main/java/org/italiangrid/storm/webdav/authz/managers/UnanimousDelegatedManager.java
 rename src/main/java/org/italiangrid/storm/webdav/authz/{voters/WlcgScopeAuthzCopyMoveVoter.java => managers/WlcgScopeAuthzCopyMoveManager.java} (61%)
 rename src/main/java/org/italiangrid/storm/webdav/authz/{voters/WlcgScopeAuthzVoter.java => managers/WlcgScopeAuthzManager.java} (63%)
 delete mode 100644 src/main/java/org/italiangrid/storm/webdav/authz/voters/MacaroonAuthzVoter.java
 delete mode 100644 src/main/java/org/italiangrid/storm/webdav/authz/voters/UnanimousDelegatedVoter.java
 delete mode 100644 src/main/java/org/italiangrid/storm/webdav/spring/web/SecurityExpressionHandlerConfiguration.java

diff --git a/pom.xml b/pom.xml
index 2a9d9925..7216044f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -32,6 +32,7 @@
 
     <!-- Keep this aligned with the parent project version! -->
     <spring-boot.version>2.7.18</spring-boot.version>
+    <spring-security.version>5.8.15</spring-security.version>
 
     <!-- Sonarcloud.io properties -->
     <sonar.projectKey>italiangrid_storm-webdav</sonar.projectKey>
diff --git a/src/main/java/org/italiangrid/storm/webdav/authz/expression/StormMethodSecurityExpressionHandler.java b/src/main/java/org/italiangrid/storm/webdav/authz/expression/StormMethodSecurityExpressionHandler.java
index 44997ee2..b5196ee0 100644
--- a/src/main/java/org/italiangrid/storm/webdav/authz/expression/StormMethodSecurityExpressionHandler.java
+++ b/src/main/java/org/italiangrid/storm/webdav/authz/expression/StormMethodSecurityExpressionHandler.java
@@ -15,8 +15,10 @@
  */
 package org.italiangrid.storm.webdav.authz.expression;
 
+import java.util.function.Supplier;
+
 import org.aopalliance.intercept.MethodInvocation;
-import org.springframework.expression.spel.support.StandardEvaluationContext;
+import org.springframework.expression.EvaluationContext;
 import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
 import org.springframework.security.core.Authentication;
 import org.springframework.stereotype.Component;
@@ -26,11 +28,11 @@ public class StormMethodSecurityExpressionHandler extends DefaultMethodSecurityE
 
 
   @Override
-  public StandardEvaluationContext createEvaluationContextInternal(Authentication authentication,
+  public EvaluationContext createEvaluationContext(Supplier<Authentication> authentication,
       MethodInvocation mi) {
 
-    StandardEvaluationContext ec = super.createEvaluationContextInternal(authentication, mi);
-    ec.setVariable("storm", new StormSecurityExpressionMethods(authentication));
+    EvaluationContext ec = super.createEvaluationContext(authentication, mi);
+    ec.setVariable("storm", new StormSecurityExpressionMethods(authentication.get()));
 
     return ec;
   }
diff --git a/src/main/java/org/italiangrid/storm/webdav/authz/managers/ConsensusBasedManager.java b/src/main/java/org/italiangrid/storm/webdav/authz/managers/ConsensusBasedManager.java
new file mode 100644
index 00000000..4533da30
--- /dev/null
+++ b/src/main/java/org/italiangrid/storm/webdav/authz/managers/ConsensusBasedManager.java
@@ -0,0 +1,75 @@
+/**
+ * Copyright (c) Istituto Nazionale di Fisica Nucleare, 2014-2023.
+ *
+ * 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
+ *
+ *     http://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 org.italiangrid.storm.webdav.authz.managers;
+
+import java.util.List;
+import java.util.function.Supplier;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.authorization.AuthorizationDecision;
+import org.springframework.security.authorization.AuthorizationManager;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
+
+public class ConsensusBasedManager implements AuthorizationManager<RequestAuthorizationContext> {
+
+  public static final Logger LOG = LoggerFactory.getLogger(ConsensusBasedManager.class);
+
+  private final List<AuthorizationManager<RequestAuthorizationContext>> managers;
+
+  private final String name;
+
+  public ConsensusBasedManager(String name,
+      List<AuthorizationManager<RequestAuthorizationContext>> managers) {
+    this.name = name;
+    this.managers = managers;
+  }
+
+  @Override
+  public AuthorizationDecision check(Supplier<Authentication> authentication,
+      RequestAuthorizationContext requestAuthorizationContext) {
+    int grant = 0;
+    int notGrant = 0;
+
+    for (AuthorizationManager<RequestAuthorizationContext> manager : managers) {
+      AuthorizationDecision result = manager.check(authentication, requestAuthorizationContext);
+
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Voter: {}, returned: {}", manager, result);
+      }
+
+      if (result != null) {
+        if (result.isGranted()) {
+          grant++;
+        } else {
+          notGrant++;
+        }
+      }
+    }
+
+    if (grant == 0 && notGrant == 0) {
+      return new AuthorizationDecision(true);
+    } else {
+      return new AuthorizationDecision(grant >= notGrant);
+    }
+  }
+
+  @Override
+  public String toString() {
+    return name;
+  }
+}
diff --git a/src/main/java/org/italiangrid/storm/webdav/authz/voters/FineGrainedAuthzVoter.java b/src/main/java/org/italiangrid/storm/webdav/authz/managers/FineGrainedAuthzManager.java
similarity index 64%
rename from src/main/java/org/italiangrid/storm/webdav/authz/voters/FineGrainedAuthzVoter.java
rename to src/main/java/org/italiangrid/storm/webdav/authz/managers/FineGrainedAuthzManager.java
index 3b66ce2a..68039afa 100644
--- a/src/main/java/org/italiangrid/storm/webdav/authz/voters/FineGrainedAuthzVoter.java
+++ b/src/main/java/org/italiangrid/storm/webdav/authz/managers/FineGrainedAuthzManager.java
@@ -13,11 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.italiangrid.storm.webdav.authz.voters;
+package org.italiangrid.storm.webdav.authz.managers;
 
 import static org.italiangrid.storm.webdav.authz.pdp.PathAuthorizationRequest.newAuthorizationRequest;
 
-import java.util.Collection;
+import java.util.function.Supplier;
 
 import org.italiangrid.storm.webdav.authz.pdp.PathAuthorizationPdp;
 import org.italiangrid.storm.webdav.config.ServiceConfigurationProperties;
@@ -26,32 +26,34 @@
 import org.italiangrid.storm.webdav.tpc.LocalURLService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.security.access.ConfigAttribute;
+import org.springframework.security.authorization.AuthorizationDecision;
 import org.springframework.security.core.Authentication;
-import org.springframework.security.web.FilterInvocation;
+import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
 
 
-public class FineGrainedAuthzVoter extends PathAuthzPdpVoterSupport {
+public class FineGrainedAuthzManager extends PathAuthzPdpManagerSupport {
 
-  public static final Logger LOG = LoggerFactory.getLogger(FineGrainedAuthzVoter.class);
+  public static final Logger LOG = LoggerFactory.getLogger(FineGrainedAuthzManager.class);
 
-  public FineGrainedAuthzVoter(ServiceConfigurationProperties config, PathResolver resolver,
+  public FineGrainedAuthzManager(ServiceConfigurationProperties config, PathResolver resolver,
       PathAuthorizationPdp pdp, LocalURLService localUrlService) {
     super(config, resolver, pdp, localUrlService, true);
   }
 
   @Override
-  public int vote(Authentication authentication, FilterInvocation filter,
-      Collection<ConfigAttribute> attributes) {
+  public AuthorizationDecision check(Supplier<Authentication> authentication,
+      RequestAuthorizationContext requestAuthorizationContext) {
 
-    final String requestPath = getRequestPath(filter.getHttpRequest());
+    final String requestPath = getRequestPath(requestAuthorizationContext.getRequest());
     StorageAreaInfo sa = resolver.resolveStorageArea(requestPath);
 
     if (sa == null || !sa.fineGrainedAuthzEnabled()) {
-      return ACCESS_ABSTAIN;
+      return null;
     }
 
-    return renderDecision(newAuthorizationRequest(filter.getHttpRequest(), authentication), LOG);
+    return renderDecision(
+        newAuthorizationRequest(requestAuthorizationContext.getRequest(), authentication.get()),
+        LOG);
 
   }
 
diff --git a/src/main/java/org/italiangrid/storm/webdav/authz/voters/FineGrainedCopyMoveAuthzVoter.java b/src/main/java/org/italiangrid/storm/webdav/authz/managers/FineGrainedCopyMoveAuthzManager.java
similarity index 59%
rename from src/main/java/org/italiangrid/storm/webdav/authz/voters/FineGrainedCopyMoveAuthzVoter.java
rename to src/main/java/org/italiangrid/storm/webdav/authz/managers/FineGrainedCopyMoveAuthzManager.java
index 1de3c859..6e5d4d38 100644
--- a/src/main/java/org/italiangrid/storm/webdav/authz/voters/FineGrainedCopyMoveAuthzVoter.java
+++ b/src/main/java/org/italiangrid/storm/webdav/authz/managers/FineGrainedCopyMoveAuthzManager.java
@@ -13,13 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.italiangrid.storm.webdav.authz.voters;
+package org.italiangrid.storm.webdav.authz.managers;
 
 import static org.italiangrid.storm.webdav.server.servlet.WebDAVMethod.COPY;
 import static org.italiangrid.storm.webdav.server.servlet.WebDAVMethod.PUT;
 
 import java.net.MalformedURLException;
-import java.util.Collection;
+import java.util.function.Supplier;
 
 import org.italiangrid.storm.webdav.authz.pdp.PathAuthorizationPdp;
 import org.italiangrid.storm.webdav.authz.pdp.PathAuthorizationRequest;
@@ -31,36 +31,38 @@
 import org.italiangrid.storm.webdav.tpc.TransferConstants;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.security.access.ConfigAttribute;
+import org.springframework.security.authorization.AuthorizationDecision;
 import org.springframework.security.core.Authentication;
-import org.springframework.security.web.FilterInvocation;
+import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
 
-public class FineGrainedCopyMoveAuthzVoter extends PathAuthzPdpVoterSupport {
+public class FineGrainedCopyMoveAuthzManager extends PathAuthzPdpManagerSupport {
 
-  public static final Logger LOG = LoggerFactory.getLogger(FineGrainedCopyMoveAuthzVoter.class);
+  public static final Logger LOG = LoggerFactory.getLogger(FineGrainedCopyMoveAuthzManager.class);
 
-  public FineGrainedCopyMoveAuthzVoter(ServiceConfigurationProperties config, PathResolver resolver,
-      PathAuthorizationPdp pdp, LocalURLService localUrlService) {
+  public FineGrainedCopyMoveAuthzManager(ServiceConfigurationProperties config,
+      PathResolver resolver, PathAuthorizationPdp pdp, LocalURLService localUrlService) {
     super(config, resolver, pdp, localUrlService, true);
   }
 
   @Override
-  public int vote(Authentication authentication, FilterInvocation filter,
-      Collection<ConfigAttribute> attributes) {
+  public AuthorizationDecision check(Supplier<Authentication> authentication,
+      RequestAuthorizationContext requestAuthorizationContext) {
 
-    if (!isCopyOrMoveRequest(filter.getRequest())) {
-      return ACCESS_ABSTAIN;
+    if (!isCopyOrMoveRequest(requestAuthorizationContext.getRequest())) {
+      return null;
     }
 
-    String destination = filter.getRequest().getHeader(TransferConstants.DESTINATION_HEADER);
+    String destination =
+        requestAuthorizationContext.getRequest().getHeader(TransferConstants.DESTINATION_HEADER);
 
     if (destination == null) {
-      return ACCESS_ABSTAIN;
+      return null;
     }
 
-    if (COPY.name().equals(filter.getRequest().getMethod())
-        && requestHasRemoteDestinationHeader(filter.getRequest(), localUrlService)) {
-      return ACCESS_ABSTAIN;
+    if (COPY.name().equals(requestAuthorizationContext.getRequest().getMethod())
+        && requestHasRemoteDestinationHeader(requestAuthorizationContext.getRequest(),
+            localUrlService)) {
+      return null;
     }
 
     try {
@@ -69,15 +71,16 @@ && requestHasRemoteDestinationHeader(filter.getRequest(), localUrlService)) {
       StorageAreaInfo sa = resolver.resolveStorageArea(destinationPath);
 
       if (sa == null) {
-        return ACCESS_ABSTAIN;
+        return null;
       }
 
       if (!sa.fineGrainedAuthzEnabled()) {
-        return ACCESS_ABSTAIN;
+        return null;
       }
 
-      return renderDecision(PathAuthorizationRequest
-        .newAuthorizationRequest(filter.getHttpRequest(), authentication, destinationPath, PUT),
+      return renderDecision(
+          PathAuthorizationRequest.newAuthorizationRequest(requestAuthorizationContext.getRequest(),
+              authentication.get(), destinationPath, PUT),
           LOG);
 
     } catch (MalformedURLException e) {
diff --git a/src/main/java/org/italiangrid/storm/webdav/authz/voters/LocalAuthzVoter.java b/src/main/java/org/italiangrid/storm/webdav/authz/managers/LocalAuthzManager.java
similarity index 61%
rename from src/main/java/org/italiangrid/storm/webdav/authz/voters/LocalAuthzVoter.java
rename to src/main/java/org/italiangrid/storm/webdav/authz/managers/LocalAuthzManager.java
index 1dfdcfca..824a49f2 100644
--- a/src/main/java/org/italiangrid/storm/webdav/authz/voters/LocalAuthzVoter.java
+++ b/src/main/java/org/italiangrid/storm/webdav/authz/managers/LocalAuthzManager.java
@@ -13,13 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.italiangrid.storm.webdav.authz.voters;
+package org.italiangrid.storm.webdav.authz.managers;
 
 import static com.google.common.base.Strings.isNullOrEmpty;
 
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.Collection;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.function.Supplier;
 
 import org.italiangrid.storm.webdav.authz.pdp.PathAuthorizationPdp;
 import org.italiangrid.storm.webdav.authz.pdp.PathAuthorizationRequest;
@@ -30,47 +30,52 @@
 import org.italiangrid.storm.webdav.tpc.LocalURLService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.security.access.ConfigAttribute;
+import org.springframework.security.authorization.AuthorizationDecision;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
-import org.springframework.security.web.FilterInvocation;
+import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
 
-public class LocalAuthzVoter extends PathAuthzPdpVoterSupport {
+public class LocalAuthzManager extends PathAuthzPdpManagerSupport {
 
-  public static final Logger LOG = LoggerFactory.getLogger(LocalAuthzVoter.class);
+  public static final Logger LOG = LoggerFactory.getLogger(LocalAuthzManager.class);
 
-  final URL localTokenIssuer;
+  final URI localTokenIssuer;
 
-  public LocalAuthzVoter(ServiceConfigurationProperties config, PathResolver resolver,
+  public LocalAuthzManager(ServiceConfigurationProperties config, PathResolver resolver,
       PathAuthorizationPdp pdp, LocalURLService localUrlService) {
     super(config, resolver, pdp, localUrlService, true);
     try {
-      localTokenIssuer = new URL(config.getAuthzServer().getIssuer());
-    } catch (MalformedURLException e) {
+      localTokenIssuer = new URI(config.getAuthzServer().getIssuer());
+    } catch (URISyntaxException e) {
       throw new StoRMIntializationError(e.getMessage());
     }
   }
 
   private boolean isLocalAuthzToken(JwtAuthenticationToken token) {
-    return localTokenIssuer.equals(token.getToken().getIssuer())
+    try {
+      return localTokenIssuer.equals(token.getToken().getIssuer().toURI())
         && !isNullOrEmpty(token.getToken().getClaimAsString(DefaultJwtTokenIssuer.PATH_CLAIM));
+    } catch (URISyntaxException e) {
+      LOG.warn("{}", e.getMessage());
+      return false;
+    }
   }
 
   @Override
-  public int vote(Authentication authentication, FilterInvocation object,
-      Collection<ConfigAttribute> attributes) {
+  public AuthorizationDecision check(Supplier<Authentication> authentication,
+      RequestAuthorizationContext requestAuthorizationContext) {
 
-    if (!(authentication instanceof JwtAuthenticationToken)) {
-      return ACCESS_ABSTAIN;
+    if (!(authentication.get() instanceof JwtAuthenticationToken)) {
+      return null;
     }
 
-    JwtAuthenticationToken token = (JwtAuthenticationToken) authentication;
+    JwtAuthenticationToken token = (JwtAuthenticationToken) authentication.get();
     if (!isLocalAuthzToken(token)) {
-      return ACCESS_ABSTAIN;
+      return null;
     }
 
-    return renderDecision(
-        PathAuthorizationRequest.newAuthorizationRequest(object.getRequest(), authentication), LOG);
+    return renderDecision(PathAuthorizationRequest.newAuthorizationRequest(
+        requestAuthorizationContext.getRequest(), authentication.get()), LOG);
   }
 
 }
diff --git a/src/main/java/org/italiangrid/storm/webdav/authz/managers/MacaroonAuthzManager.java b/src/main/java/org/italiangrid/storm/webdav/authz/managers/MacaroonAuthzManager.java
new file mode 100644
index 00000000..9dddb12d
--- /dev/null
+++ b/src/main/java/org/italiangrid/storm/webdav/authz/managers/MacaroonAuthzManager.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) Istituto Nazionale di Fisica Nucleare, 2014-2023.
+ *
+ * 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
+ *
+ *     http://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 org.italiangrid.storm.webdav.authz.managers;
+
+import java.util.function.Supplier;
+
+import org.springframework.http.HttpMethod;
+import org.springframework.security.authorization.AuthorizationDecision;
+import org.springframework.security.authorization.AuthorizationManager;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
+import org.springframework.util.Assert;
+
+public class MacaroonAuthzManager implements AuthorizationManager<RequestAuthorizationContext> {
+
+  @Override
+  public AuthorizationDecision check(Supplier<Authentication> authentication,
+      RequestAuthorizationContext requestAuthorizationContext) {
+    Assert.notNull(authentication.get(), "authentication must not be null");
+    Assert.notNull(requestAuthorizationContext, "filterInvocation must not be null");
+
+    if (HttpMethod.POST.name().equals(requestAuthorizationContext.getRequest().getMethod())) {
+      return new AuthorizationDecision(true);
+    }
+    return null;
+  }
+
+}
diff --git a/src/main/java/org/italiangrid/storm/webdav/authz/voters/PathAuthzPdpVoterSupport.java b/src/main/java/org/italiangrid/storm/webdav/authz/managers/PathAuthzPdpManagerSupport.java
similarity index 75%
rename from src/main/java/org/italiangrid/storm/webdav/authz/voters/PathAuthzPdpVoterSupport.java
rename to src/main/java/org/italiangrid/storm/webdav/authz/managers/PathAuthzPdpManagerSupport.java
index 4c04911d..03e2b0c5 100644
--- a/src/main/java/org/italiangrid/storm/webdav/authz/voters/PathAuthzPdpVoterSupport.java
+++ b/src/main/java/org/italiangrid/storm/webdav/authz/managers/PathAuthzPdpManagerSupport.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.italiangrid.storm.webdav.authz.voters;
+package org.italiangrid.storm.webdav.authz.managers;
 
 import java.util.EnumSet;
 import java.util.Optional;
@@ -28,12 +28,12 @@
 import org.italiangrid.storm.webdav.tpc.LocalURLService;
 import org.italiangrid.storm.webdav.tpc.TpcUtils;
 import org.slf4j.Logger;
-import org.springframework.security.access.AccessDecisionVoter;
-import org.springframework.security.access.ConfigAttribute;
-import org.springframework.security.web.FilterInvocation;
+import org.springframework.security.authorization.AuthorizationDecision;
+import org.springframework.security.authorization.AuthorizationManager;
+import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
 
-public abstract class PathAuthzPdpVoterSupport
-    implements MatcherUtils, TpcUtils, AccessDecisionVoter<FilterInvocation> {
+public abstract class PathAuthzPdpManagerSupport
+    implements MatcherUtils, TpcUtils, AuthorizationManager<RequestAuthorizationContext> {
 
   protected static final Set<PathAuthorizationResult.Decision> ABSTAIN_DECISIONS =
       EnumSet.of(PathAuthorizationResult.Decision.INDETERMINATE,
@@ -45,7 +45,7 @@ public abstract class PathAuthzPdpVoterSupport
   protected final LocalURLService localUrlService;
   protected final boolean permissive;
 
-  public PathAuthzPdpVoterSupport(ServiceConfigurationProperties config, PathResolver resolver,
+  protected PathAuthzPdpManagerSupport(ServiceConfigurationProperties config, PathResolver resolver,
       PathAuthorizationPdp pdp, LocalURLService localUrlService, boolean permissive) {
     this.config = config;
     this.resolver = resolver;
@@ -54,17 +54,6 @@ public PathAuthzPdpVoterSupport(ServiceConfigurationProperties config, PathResol
     this.permissive = permissive;
   }
 
-  @Override
-  public boolean supports(ConfigAttribute attribute) {
-    return false;
-  }
-
-  @Override
-  public boolean supports(Class<?> clazz) {
-    return FilterInvocation.class.isAssignableFrom(clazz);
-  }
-
-
   protected void logPdpDecision(PathAuthorizationRequest request, PathAuthorizationResult result,
       Logger logger) {
     String requestString = requestToString(request);
@@ -73,19 +62,19 @@ protected void logPdpDecision(PathAuthorizationRequest request, PathAuthorizatio
         result.getPolicy());
   }
 
-  public int renderDecision(PathAuthorizationResult result) {
+  public AuthorizationDecision renderDecision(PathAuthorizationResult result) {
     if (ABSTAIN_DECISIONS.contains(result.getDecision()) && permissive) {
-      return ACCESS_ABSTAIN;
+      return null;
     }
 
     if (PathAuthorizationResult.Decision.PERMIT.equals(result.getDecision())) {
-      return ACCESS_GRANTED;
+      return new AuthorizationDecision(true);
     }
 
-    return ACCESS_DENIED;
+    return new AuthorizationDecision(false);
   }
 
-  public int renderDecision(PathAuthorizationRequest request, Logger log) {
+  public AuthorizationDecision renderDecision(PathAuthorizationRequest request, Logger log) {
     PathAuthorizationResult result = pdp.authorizeRequest(request);
 
     logPdpDecision(request, result, log);
@@ -93,7 +82,6 @@ public int renderDecision(PathAuthorizationRequest request, Logger log) {
     return renderDecision(result);
   }
 
-
   public boolean isPermissive() {
     return permissive;
   }
diff --git a/src/main/java/org/italiangrid/storm/webdav/authz/managers/UnanimousDelegatedManager.java b/src/main/java/org/italiangrid/storm/webdav/authz/managers/UnanimousDelegatedManager.java
new file mode 100644
index 00000000..b5279138
--- /dev/null
+++ b/src/main/java/org/italiangrid/storm/webdav/authz/managers/UnanimousDelegatedManager.java
@@ -0,0 +1,81 @@
+/**
+ * Copyright (c) Istituto Nazionale di Fisica Nucleare, 2014-2023.
+ *
+ * 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
+ *
+ *     http://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 org.italiangrid.storm.webdav.authz.managers;
+
+import java.util.List;
+import java.util.function.Supplier;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.authorization.AuthorizationDecision;
+import org.springframework.security.authorization.AuthorizationManager;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
+
+public class UnanimousDelegatedManager
+    implements AuthorizationManager<RequestAuthorizationContext> {
+
+  public static final Logger LOG = LoggerFactory.getLogger(UnanimousDelegatedManager.class);
+
+  private final List<AuthorizationManager<RequestAuthorizationContext>> managers;
+
+  private final String name;
+
+  private UnanimousDelegatedManager(String name,
+      List<AuthorizationManager<RequestAuthorizationContext>> managers) {
+    this.name = name;
+    this.managers = managers;
+  }
+
+  @Override
+  public AuthorizationDecision check(Supplier<Authentication> authentication,
+      RequestAuthorizationContext filter) {
+    int grant = 0;
+
+    for (AuthorizationManager<RequestAuthorizationContext> manager : managers) {
+      AuthorizationDecision result = manager.check(authentication, filter);
+
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Voter: {}, returned: {}", manager, result);
+      }
+
+      if (result != null) {
+        if (result.isGranted()) {
+          grant++;
+        } else {
+          return new AuthorizationDecision(false);
+        }
+      }
+    }
+
+    // To get this far, there were no deny votes
+    if (grant > 0) {
+      return new AuthorizationDecision(true);
+    }
+
+    return null;
+  }
+
+  public static UnanimousDelegatedManager forVoters(String name,
+      List<AuthorizationManager<RequestAuthorizationContext>> accessDecisionManagers) {
+    return new UnanimousDelegatedManager(name, accessDecisionManagers);
+  }
+
+  @Override
+  public String toString() {
+    return name;
+  }
+}
diff --git a/src/main/java/org/italiangrid/storm/webdav/authz/voters/WlcgScopeAuthzCopyMoveVoter.java b/src/main/java/org/italiangrid/storm/webdav/authz/managers/WlcgScopeAuthzCopyMoveManager.java
similarity index 61%
rename from src/main/java/org/italiangrid/storm/webdav/authz/voters/WlcgScopeAuthzCopyMoveVoter.java
rename to src/main/java/org/italiangrid/storm/webdav/authz/managers/WlcgScopeAuthzCopyMoveManager.java
index f1714411..f431743d 100644
--- a/src/main/java/org/italiangrid/storm/webdav/authz/voters/WlcgScopeAuthzCopyMoveVoter.java
+++ b/src/main/java/org/italiangrid/storm/webdav/authz/managers/WlcgScopeAuthzCopyMoveManager.java
@@ -13,13 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.italiangrid.storm.webdav.authz.voters;
+package org.italiangrid.storm.webdav.authz.managers;
 
 import static org.italiangrid.storm.webdav.server.servlet.WebDAVMethod.COPY;
 import static org.italiangrid.storm.webdav.server.servlet.WebDAVMethod.PUT;
 
 import java.net.MalformedURLException;
-import java.util.Collection;
+import java.util.function.Supplier;
 
 import org.italiangrid.storm.webdav.authz.pdp.PathAuthorizationPdp;
 import org.italiangrid.storm.webdav.authz.pdp.PathAuthorizationRequest;
@@ -31,42 +31,44 @@
 import org.italiangrid.storm.webdav.tpc.TransferConstants;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.security.access.ConfigAttribute;
+import org.springframework.security.authorization.AuthorizationDecision;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
-import org.springframework.security.web.FilterInvocation;
+import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
 
-public class WlcgScopeAuthzCopyMoveVoter extends PathAuthzPdpVoterSupport {
+public class WlcgScopeAuthzCopyMoveManager extends PathAuthzPdpManagerSupport {
 
-  public static final Logger LOG = LoggerFactory.getLogger(WlcgScopeAuthzCopyMoveVoter.class);
+  public static final Logger LOG = LoggerFactory.getLogger(WlcgScopeAuthzCopyMoveManager.class);
 
-  public WlcgScopeAuthzCopyMoveVoter(ServiceConfigurationProperties config, PathResolver resolver,
+  public WlcgScopeAuthzCopyMoveManager(ServiceConfigurationProperties config, PathResolver resolver,
       PathAuthorizationPdp pdp, LocalURLService localUrlService) {
     super(config, resolver, pdp, localUrlService, true);
   }
 
 
   @Override
-  public int vote(Authentication authentication, FilterInvocation filter,
-      Collection<ConfigAttribute> attributes) {
+  public AuthorizationDecision check(Supplier<Authentication> authentication,
+      RequestAuthorizationContext requestAuthorizationContext) {
 
-    if (!(authentication instanceof JwtAuthenticationToken)) {
-      return ACCESS_ABSTAIN;
+    if (!(authentication.get() instanceof JwtAuthenticationToken)) {
+      return null;
     }
 
-    if (!isCopyOrMoveRequest(filter.getRequest())) {
-      return ACCESS_ABSTAIN;
+    if (!isCopyOrMoveRequest(requestAuthorizationContext.getRequest())) {
+      return null;
     }
 
-    String destination = filter.getRequest().getHeader(TransferConstants.DESTINATION_HEADER);
+    String destination =
+        requestAuthorizationContext.getRequest().getHeader(TransferConstants.DESTINATION_HEADER);
 
     if (destination == null) {
-      return ACCESS_ABSTAIN;
+      return null;
     }
 
-    if (COPY.name().equals(filter.getRequest().getMethod())
-        && requestHasRemoteDestinationHeader(filter.getRequest(), localUrlService)) {
-      return ACCESS_ABSTAIN;
+    if (COPY.name().equals(requestAuthorizationContext.getRequest().getMethod())
+        && requestHasRemoteDestinationHeader(requestAuthorizationContext.getRequest(),
+            localUrlService)) {
+      return null;
     }
 
     try {
@@ -75,16 +77,16 @@ && requestHasRemoteDestinationHeader(filter.getRequest(), localUrlService)) {
       StorageAreaInfo sa = resolver.resolveStorageArea(destinationPath);
 
       if (sa == null) {
-        return ACCESS_ABSTAIN;
+        return null;
       }
 
       if (!sa.wlcgScopeAuthzEnabled()) {
-        return ACCESS_ABSTAIN;
+        return null;
       }
 
-      return renderDecision(PathAuthorizationRequest
-        .newAuthorizationRequest(filter.getHttpRequest(), authentication, destinationPath,
-            PUT),
+      return renderDecision(
+          PathAuthorizationRequest.newAuthorizationRequest(requestAuthorizationContext.getRequest(),
+              authentication.get(), destinationPath, PUT),
           LOG);
 
     } catch (MalformedURLException e) {
diff --git a/src/main/java/org/italiangrid/storm/webdav/authz/voters/WlcgScopeAuthzVoter.java b/src/main/java/org/italiangrid/storm/webdav/authz/managers/WlcgScopeAuthzManager.java
similarity index 63%
rename from src/main/java/org/italiangrid/storm/webdav/authz/voters/WlcgScopeAuthzVoter.java
rename to src/main/java/org/italiangrid/storm/webdav/authz/managers/WlcgScopeAuthzManager.java
index 5da7658a..36e0c2e5 100644
--- a/src/main/java/org/italiangrid/storm/webdav/authz/voters/WlcgScopeAuthzVoter.java
+++ b/src/main/java/org/italiangrid/storm/webdav/authz/managers/WlcgScopeAuthzManager.java
@@ -13,11 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.italiangrid.storm.webdav.authz.voters;
+package org.italiangrid.storm.webdav.authz.managers;
 
 import static org.italiangrid.storm.webdav.authz.pdp.PathAuthorizationRequest.newAuthorizationRequest;
 
-import java.util.Collection;
+import java.util.function.Supplier;
 
 import org.italiangrid.storm.webdav.authz.pdp.PathAuthorizationPdp;
 import org.italiangrid.storm.webdav.config.ServiceConfigurationProperties;
@@ -26,41 +26,43 @@
 import org.italiangrid.storm.webdav.tpc.LocalURLService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.security.access.ConfigAttribute;
+import org.springframework.security.authorization.AuthorizationDecision;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
-import org.springframework.security.web.FilterInvocation;
+import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
 
-public class WlcgScopeAuthzVoter extends PathAuthzPdpVoterSupport {
+public class WlcgScopeAuthzManager extends PathAuthzPdpManagerSupport {
 
-  public static final Logger LOG = LoggerFactory.getLogger(WlcgScopeAuthzVoter.class);
+  public static final Logger LOG = LoggerFactory.getLogger(WlcgScopeAuthzManager.class);
 
 
-  public WlcgScopeAuthzVoter(ServiceConfigurationProperties config, PathResolver resolver,
+  public WlcgScopeAuthzManager(ServiceConfigurationProperties config, PathResolver resolver,
       PathAuthorizationPdp pdp, LocalURLService localUrlService) {
     super(config, resolver, pdp, localUrlService, true);
   }
 
   @Override
-  public int vote(Authentication authentication, FilterInvocation filter,
-      Collection<ConfigAttribute> attributes) {
+  public AuthorizationDecision check(Supplier<Authentication> authentication,
+      RequestAuthorizationContext requestAuthorizationContext) {
 
-    if (!(authentication instanceof JwtAuthenticationToken)) {
-      return ACCESS_ABSTAIN;
+    if (!(authentication.get() instanceof JwtAuthenticationToken)) {
+      return null;
     }
 
-    final String requestPath = getRequestPath(filter.getHttpRequest());
+    final String requestPath = getRequestPath(requestAuthorizationContext.getRequest());
     StorageAreaInfo sa = resolver.resolveStorageArea(requestPath);
 
     if (sa == null) {
-      return ACCESS_ABSTAIN;
+      return null;
     }
 
     if (!sa.wlcgScopeAuthzEnabled()) {
-      return ACCESS_ABSTAIN;
+      return null;
     }
 
-    return renderDecision(newAuthorizationRequest(filter.getHttpRequest(), authentication), LOG);
+    return renderDecision(
+        newAuthorizationRequest(requestAuthorizationContext.getRequest(), authentication.get()),
+        LOG);
 
   }
 
diff --git a/src/main/java/org/italiangrid/storm/webdav/authz/voters/MacaroonAuthzVoter.java b/src/main/java/org/italiangrid/storm/webdav/authz/voters/MacaroonAuthzVoter.java
deleted file mode 100644
index c8c0a69b..00000000
--- a/src/main/java/org/italiangrid/storm/webdav/authz/voters/MacaroonAuthzVoter.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * Copyright (c) Istituto Nazionale di Fisica Nucleare, 2014-2023.
- *
- * 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
- *
- *     http://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 org.italiangrid.storm.webdav.authz.voters;
-
-import java.util.Collection;
-
-import org.springframework.http.HttpMethod;
-import org.springframework.security.access.AccessDecisionVoter;
-import org.springframework.security.access.ConfigAttribute;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.web.FilterInvocation;
-import org.springframework.util.Assert;
-
-public class MacaroonAuthzVoter implements AccessDecisionVoter<FilterInvocation> {
-
-  @Override
-  public boolean supports(ConfigAttribute attribute) {
-    return true;
-  }
-
-  @Override
-  public boolean supports(Class<?> clazz) {
-    return true;
-  }
-
-  @Override
-  public int vote(Authentication authentication, FilterInvocation filterInvocation,
-      Collection<ConfigAttribute> attributes) {
-    Assert.notNull(authentication, "authentication must not be null");
-    Assert.notNull(filterInvocation, "filterInvocation must not be null");
- 
-    if (HttpMethod.POST.name().equals(filterInvocation.getHttpRequest().getMethod())) {
-      return ACCESS_GRANTED;
-    }
-    return ACCESS_ABSTAIN;
-  }
-
-}
diff --git a/src/main/java/org/italiangrid/storm/webdav/authz/voters/UnanimousDelegatedVoter.java b/src/main/java/org/italiangrid/storm/webdav/authz/voters/UnanimousDelegatedVoter.java
deleted file mode 100644
index 5ef66557..00000000
--- a/src/main/java/org/italiangrid/storm/webdav/authz/voters/UnanimousDelegatedVoter.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/**
- * Copyright (c) Istituto Nazionale di Fisica Nucleare, 2014-2023.
- *
- * 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
- *
- *     http://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 org.italiangrid.storm.webdav.authz.voters;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.security.access.AccessDecisionVoter;
-import org.springframework.security.access.ConfigAttribute;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.web.FilterInvocation;
-
-public class UnanimousDelegatedVoter implements AccessDecisionVoter<FilterInvocation> {
-
-  public static final Logger LOG = LoggerFactory.getLogger(UnanimousDelegatedVoter.class);
-
-  private final List<AccessDecisionVoter<FilterInvocation>> voters;
-
-  private final String name;
-
-  private UnanimousDelegatedVoter(String name, List<AccessDecisionVoter<FilterInvocation>> voters) {
-    this.name = name;
-    this.voters = voters;
-  }
-
-  @Override
-  public boolean supports(ConfigAttribute attribute) {
-    return false;
-  }
-
-  @Override
-  public boolean supports(Class<?> clazz) {
-    return FilterInvocation.class.isAssignableFrom(clazz);
-  }
-
-  @Override
-  public int vote(Authentication authentication, FilterInvocation filter,
-      Collection<ConfigAttribute> attributes) {
-
-    int grant = 0;
-
-    List<ConfigAttribute> singleAttributeList = new ArrayList<>(1);
-    singleAttributeList.add(null);
-
-    for (ConfigAttribute attribute : attributes) {
-      singleAttributeList.set(0, attribute);
-
-      for (AccessDecisionVoter<FilterInvocation> voter : voters) {
-        int result = voter.vote(authentication, filter, singleAttributeList);
-
-        if (LOG.isDebugEnabled()) {
-          LOG.debug("Voter: {}, returned: {}", voter, result);
-        }
-
-        switch (result) {
-          case AccessDecisionVoter.ACCESS_GRANTED:
-            grant++;
-
-            break;
-
-          case AccessDecisionVoter.ACCESS_DENIED:
-            return AccessDecisionVoter.ACCESS_DENIED;
-
-          default:
-            break;
-        }
-      }
-    }
-
-    // To get this far, there were no deny votes
-    if (grant > 0) {
-      return AccessDecisionVoter.ACCESS_GRANTED;
-    }
-
-
-    return AccessDecisionVoter.ACCESS_ABSTAIN;
-  }
-
-  public static UnanimousDelegatedVoter forVoters(String name,
-      List<AccessDecisionVoter<FilterInvocation>> accessDecisionVoters) {
-    return new UnanimousDelegatedVoter(name, accessDecisionVoters);
-  }
-
-  @Override
-  public String toString() {
-    return name;
-  }
-}
diff --git a/src/main/java/org/italiangrid/storm/webdav/spring/web/SecurityConfig.java b/src/main/java/org/italiangrid/storm/webdav/spring/web/SecurityConfig.java
index 0e85dbf0..dcb93070 100644
--- a/src/main/java/org/italiangrid/storm/webdav/spring/web/SecurityConfig.java
+++ b/src/main/java/org/italiangrid/storm/webdav/spring/web/SecurityConfig.java
@@ -16,7 +16,7 @@
 package org.italiangrid.storm.webdav.spring.web;
 
 import static java.util.Arrays.asList;
-import static org.italiangrid.storm.webdav.authz.voters.UnanimousDelegatedVoter.forVoters;
+import static org.italiangrid.storm.webdav.authz.managers.UnanimousDelegatedManager.forVoters;
 import static org.springframework.http.HttpStatus.BAD_REQUEST;
 import static org.springframework.http.HttpStatus.FORBIDDEN;
 import static org.springframework.http.HttpStatus.METHOD_NOT_ALLOWED;
@@ -41,13 +41,14 @@
 import org.italiangrid.storm.webdav.authz.pdp.WlcgStructuredPathAuthorizationPdp;
 import org.italiangrid.storm.webdav.authz.util.ReadonlyHttpMethodMatcher;
 import org.italiangrid.storm.webdav.authz.util.SaveAuthnAccessDeniedHandler;
-import org.italiangrid.storm.webdav.authz.voters.FineGrainedAuthzVoter;
-import org.italiangrid.storm.webdav.authz.voters.FineGrainedCopyMoveAuthzVoter;
-import org.italiangrid.storm.webdav.authz.voters.LocalAuthzVoter;
-import org.italiangrid.storm.webdav.authz.voters.MacaroonAuthzVoter;
-import org.italiangrid.storm.webdav.authz.voters.UnanimousDelegatedVoter;
-import org.italiangrid.storm.webdav.authz.voters.WlcgScopeAuthzCopyMoveVoter;
-import org.italiangrid.storm.webdav.authz.voters.WlcgScopeAuthzVoter;
+import org.italiangrid.storm.webdav.authz.managers.ConsensusBasedManager;
+import org.italiangrid.storm.webdav.authz.managers.FineGrainedAuthzManager;
+import org.italiangrid.storm.webdav.authz.managers.FineGrainedCopyMoveAuthzManager;
+import org.italiangrid.storm.webdav.authz.managers.LocalAuthzManager;
+import org.italiangrid.storm.webdav.authz.managers.MacaroonAuthzManager;
+import org.italiangrid.storm.webdav.authz.managers.UnanimousDelegatedManager;
+import org.italiangrid.storm.webdav.authz.managers.WlcgScopeAuthzCopyMoveManager;
+import org.italiangrid.storm.webdav.authz.managers.WlcgScopeAuthzManager;
 import org.italiangrid.storm.webdav.config.OAuthProperties;
 import org.italiangrid.storm.webdav.config.ServiceConfigurationProperties;
 import org.italiangrid.storm.webdav.config.StorageAreaConfiguration;
@@ -65,24 +66,26 @@
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.http.HttpMethod;
-import org.springframework.security.access.AccessDecisionManager;
-import org.springframework.security.access.AccessDecisionVoter;
-import org.springframework.security.access.vote.ConsensusBased;
 import org.springframework.security.authentication.InsufficientAuthenticationException;
+import org.springframework.security.authorization.AuthorizationManager;
+import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
+import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer.HstsConfig;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.web.SecurityFilterChain;
 import org.springframework.security.web.access.AccessDeniedHandlerImpl;
-import org.springframework.security.web.access.expression.WebExpressionVoter;
+import org.springframework.security.web.access.expression.WebExpressionAuthorizationManager;
+import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
 import org.springframework.security.web.firewall.HttpFirewall;
 import org.springframework.security.web.firewall.RequestRejectedException;
 import org.springframework.security.web.firewall.RequestRejectedHandler;
 import org.springframework.security.web.firewall.StrictHttpFirewall;
+import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
 
 import com.google.common.collect.Lists;
 
 @Configuration
+@EnableMethodSecurity(proxyTargetClass = true)
 public class SecurityConfig {
 
   private static final Logger LOG = LoggerFactory.getLogger(SecurityConfig.class);
@@ -148,51 +151,65 @@ SecurityFilterChain filterChain(HttpSecurity http, VOMSAuthenticationProvider vo
 
     if (serviceConfigurationProperties.getAuthz().isDisabled()) {
       LOG.warn("AUTHORIZATION DISABLED: this shouldn't be used in production!");
-      http.authorizeRequests().anyRequest().permitAll();
+      http.authorizeHttpRequests(authorize -> authorize.anyRequest().permitAll());
     } else {
-      http.authorizeRequests().accessDecisionManager(fineGrainedAccessDecisionManager());
       addAccessRules(http);
       addAnonymousAccessRules(http);
     }
 
     if (serviceConfigurationProperties.getRedirector().isEnabled()) {
-      http.headers().httpStrictTransportSecurity().disable();
+      http.headers(headers -> headers.httpStrictTransportSecurity(HstsConfig::disable));
     }
 
-    http.oauth2ResourceServer().jwt().jwtAuthenticationConverter(authConverter);
-
-    http.authorizeRequests().antMatchers("/errors/**").permitAll();
-
-    http.authorizeRequests()
-      .antMatchers(HttpMethod.GET, "/.well-known/oauth-authorization-server",
-          "/.well-known/openid-configuration", "/.well-known/wlcg-tape-rest-api")
-      .permitAll();
+    http.oauth2ResourceServer(
+        oauth2 -> oauth2.jwt(jwt -> jwt.jwtAuthenticationConverter(authConverter)));
+
+    http.authorizeHttpRequests(
+        authorize -> authorize.requestMatchers(AntPathRequestMatcher.antMatcher("/errors/**"))
+          .permitAll());
+
+    http.authorizeHttpRequests(authorize -> authorize
+      .requestMatchers(
+          AntPathRequestMatcher.antMatcher(HttpMethod.GET,
+              "/.well-known/oauth-authorization-server"),
+          AntPathRequestMatcher.antMatcher(HttpMethod.GET, "/.well-known/openid-configuration"),
+          AntPathRequestMatcher.antMatcher(HttpMethod.GET, "/.well-known/wlcg-tape-rest-api"))
+      .permitAll());
+
+    http.authorizeHttpRequests(
+        authorize -> authorize
+          .requestMatchers(AntPathRequestMatcher.antMatcher("/css/*"),
+              AntPathRequestMatcher.antMatcher("/js/*"))
+          .permitAll());
+
+    if (!serviceConfigurationProperties.getAuthz().isDisabled()) {
+      http.authorizeHttpRequests(
+          authorize -> authorize.anyRequest().access(fineGrainedAuthorizationManager(null)));
+    }
 
     AccessDeniedHandlerImpl handler = new AccessDeniedHandlerImpl();
     handler.setErrorPage("/errors/403");
-    http.exceptionHandling()
-      .accessDeniedHandler(new SaveAuthnAccessDeniedHandler(principalHelper, handler));
+    http.exceptionHandling(exception -> exception
+      .accessDeniedHandler(new SaveAuthnAccessDeniedHandler(principalHelper, handler)));
 
-    http.logout()
-      .logoutUrl("/logout")
+    http.logout(logout -> logout.logoutUrl("/logout")
       .clearAuthentication(true)
       .invalidateHttpSession(true)
-      .logoutSuccessUrl("/");
+      .logoutSuccessUrl("/"));
 
     if (!oauthProperties.isEnableOidc()) {
-      http.exceptionHandling().authenticationEntryPoint(new ErrorPageAuthenticationEntryPoint());
+      http.exceptionHandling(
+          exception -> exception.authenticationEntryPoint(new ErrorPageAuthenticationEntryPoint()));
     }
 
     configureOidcAuthn(http);
 
-    http.csrf().disable();
-    http.cors().disable();
+    http.csrf(csrf -> csrf.disable());
+    http.cors(cors -> cors.disable());
 
     return http.build();
   }
 
-
-
   @Bean
   static ErrorPageRegistrar securityErrorPageRegistrar() {
     return r -> {
@@ -206,11 +223,6 @@ static ErrorPageRegistrar securityErrorPageRegistrar() {
     };
   }
 
-  @Bean
-  WebSecurityCustomizer webSecurityCustomizer() {
-    return web -> web.ignoring().antMatchers("/css/*", "/js/*");
-  }
-
   @Bean
   RequestRejectedHandler requestRejectedHandler() {
     return new HttpMethodRequestRejectedHandler(ALLOWED_METHODS);
@@ -226,13 +238,13 @@ protected void addAnonymousAccessRules(HttpSecurity http) throws Exception {
     }
 
     if (!anonymousAccessPermissions.isEmpty()) {
-      http.anonymous().authorities(anonymousAccessPermissions);
+      http.anonymous(anonymous -> anonymous.authorities(anonymousAccessPermissions));
     }
   }
 
   protected void configureOidcAuthn(HttpSecurity http) throws Exception {
     if (oauthProperties.isEnableOidc()) {
-      http.oauth2Login().loginPage("/oidc-login");
+      http.oauth2Login(oauth2Login -> oauth2Login.loginPage("/oidc-login"));
     }
   }
 
@@ -251,45 +263,56 @@ protected void addAccessRules(HttpSecurity http) throws Exception {
       String readAccessRule =
           String.format("hasAuthority('%s')", SAPermission.canRead(sa).getAuthority());
       LOG.debug("Read access rule: {}", readAccessRule);
-      http.authorizeRequests()
-        .requestMatchers(new ReadonlyHttpMethodMatcher(ap + "/**"))
-        .access(readAccessRule);
-
-      http.authorizeRequests().antMatchers(ap + "/**").access(writeAccessRule);
+      http.authorizeHttpRequests(
+          authorize -> authorize.requestMatchers(new ReadonlyHttpMethodMatcher(ap + "/**"))
+            .access(fineGrainedAuthorizationManager(
+                new WebExpressionAuthorizationManager(readAccessRule))));
+
+      http.authorizeHttpRequests(
+          authorize -> authorize.requestMatchers(AntPathRequestMatcher.antMatcher(ap + "/**"))
+            .access(fineGrainedAuthorizationManager(
+                new WebExpressionAuthorizationManager(writeAccessRule))));
     }
   }
 
-  protected AccessDecisionManager fineGrainedAccessDecisionManager() throws MalformedURLException {
-    List<AccessDecisionVoter<?>> voters = new ArrayList<>();
+  protected AuthorizationManager<RequestAuthorizationContext> fineGrainedAuthorizationManager(
+      WebExpressionAuthorizationManager webExpressionAuthorizationManager) {
+    List<AuthorizationManager<RequestAuthorizationContext>> voters = new ArrayList<>();
 
-    UnanimousDelegatedVoter fineGrainedVoters = forVoters("FineGrainedAuthz",
+    UnanimousDelegatedManager fineGrainedVoters = forVoters("FineGrainedAuthz",
         asList(
-            new FineGrainedAuthzVoter(serviceConfigurationProperties, pathResolver,
+            new FineGrainedAuthzManager(serviceConfigurationProperties, pathResolver,
                 fineGrainedAuthzPdp, localURLService),
-            new FineGrainedCopyMoveAuthzVoter(serviceConfigurationProperties, pathResolver,
+            new FineGrainedCopyMoveAuthzManager(serviceConfigurationProperties, pathResolver,
                 fineGrainedAuthzPdp, localURLService)));
 
     WlcgStructuredPathAuthorizationPdp wlcgPdp = new WlcgStructuredPathAuthorizationPdp(
         serviceConfigurationProperties, pathResolver, localURLService);
 
-    UnanimousDelegatedVoter wlcgVoters = forVoters("WLCGScopeBasedAuthz",
+    UnanimousDelegatedManager wlcgVoters = forVoters("WLCGScopeBasedAuthz",
         asList(
-            new WlcgScopeAuthzVoter(serviceConfigurationProperties, pathResolver, wlcgPdp,
+            new WlcgScopeAuthzManager(serviceConfigurationProperties, pathResolver, wlcgPdp,
                 localURLService),
-            new WlcgScopeAuthzCopyMoveVoter(serviceConfigurationProperties, pathResolver, wlcgPdp,
+            new WlcgScopeAuthzCopyMoveManager(serviceConfigurationProperties, pathResolver, wlcgPdp,
                 localURLService)));
 
     if (serviceConfigurationProperties.getRedirector().isEnabled()) {
-      voters.add(new LocalAuthzVoter(serviceConfigurationProperties, pathResolver,
-          new LocalAuthorizationPdp(serviceConfigurationProperties), localURLService));
+      try {
+        voters.add(new LocalAuthzManager(serviceConfigurationProperties, pathResolver,
+            new LocalAuthorizationPdp(serviceConfigurationProperties), localURLService));
+      } catch (MalformedURLException e) {
+        LOG.error(e.getMessage(), e);
+      }
     }
     if (serviceConfigurationProperties.getAuthzServer().isEnabled()
         && serviceConfigurationProperties.getMacaroonFilter().isEnabled()) {
-      voters.add(new MacaroonAuthzVoter());
+      voters.add(new MacaroonAuthzManager());
+    }
+    if (webExpressionAuthorizationManager != null) {
+      voters.add(webExpressionAuthorizationManager);
     }
-    voters.add(new WebExpressionVoter());
     voters.add(fineGrainedVoters);
     voters.add(wlcgVoters);
-    return new ConsensusBased(voters);
+    return new ConsensusBasedManager("Consensus", voters);
   }
 }
diff --git a/src/main/java/org/italiangrid/storm/webdav/spring/web/SecurityExpressionHandlerConfiguration.java b/src/main/java/org/italiangrid/storm/webdav/spring/web/SecurityExpressionHandlerConfiguration.java
deleted file mode 100644
index c4701882..00000000
--- a/src/main/java/org/italiangrid/storm/webdav/spring/web/SecurityExpressionHandlerConfiguration.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * Copyright (c) Istituto Nazionale di Fisica Nucleare, 2014-2023.
- *
- * 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
- *
- *     http://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 org.italiangrid.storm.webdav.spring.web;
-
-import org.springframework.context.annotation.Configuration;
-import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
-import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
-import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
-import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
-
-@Configuration
-@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
-public class SecurityExpressionHandlerConfiguration extends GlobalMethodSecurityConfiguration {
-
-  @Override
-  protected MethodSecurityExpressionHandler createExpressionHandler() {
-    return new DefaultMethodSecurityExpressionHandler();
-  }
-
-}