Skip to content

Commit

Permalink
Upgrade to Spring Security 5.8
Browse files Browse the repository at this point in the history
  • Loading branch information
Luca Bassi committed Dec 13, 2024
1 parent 54978b2 commit 7d6fb5f
Show file tree
Hide file tree
Showing 15 changed files with 404 additions and 367 deletions.
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand All @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}

}
Original file line number Diff line number Diff line change
@@ -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;
}

}
Loading

0 comments on commit 7d6fb5f

Please sign in to comment.