diff --git a/pom.xml b/pom.xml index 0024cfcb..c629d286 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 org.italiangrid storm-webdav-server - 1.0.2 + 1.0.3 jar storm-webdav-server @@ -42,6 +42,7 @@ 3.2.5.RELEASE 2.1.3.RELEASE + 1.10.19 @@ -337,6 +338,14 @@ commons-cli ${commons-cli.version} + + + org.mockito + mockito-core + ${mockito-core.version} + test + + diff --git a/src/main/java/org/italiangrid/storm/webdav/authz/CopyMoveAuthzVoter.java b/src/main/java/org/italiangrid/storm/webdav/authz/CopyMoveAuthzVoter.java index eaa8a551..c687556c 100644 --- a/src/main/java/org/italiangrid/storm/webdav/authz/CopyMoveAuthzVoter.java +++ b/src/main/java/org/italiangrid/storm/webdav/authz/CopyMoveAuthzVoter.java @@ -25,6 +25,7 @@ import org.italiangrid.storm.webdav.config.StorageAreaConfiguration; import org.italiangrid.storm.webdav.config.StorageAreaInfo; +import org.italiangrid.storm.webdav.server.PathResolver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.access.AccessDecisionVoter; @@ -45,10 +46,13 @@ public class CopyMoveAuthzVoter implements .compile(WEBDAV_PATH_REGEX); final StorageAreaConfiguration saConfig; - - public CopyMoveAuthzVoter(StorageAreaConfiguration saConfig) { + final PathResolver pathResolver; + + public CopyMoveAuthzVoter(StorageAreaConfiguration saConfig, + PathResolver pathResolver) { this.saConfig = saConfig; + this.pathResolver = pathResolver; } @Override @@ -85,18 +89,8 @@ private StorageAreaInfo getSAFromPath(String destinationURL) throws MalformedURLException { URL url = new URL(destinationURL); - - String path = dropSlashWebdavFromPath(url.getPath()); - - for (StorageAreaInfo sa : saConfig.getStorageAreaInfo()) { - for (String ap : sa.accessPoints()) { - if (path.startsWith(ap)) { - return sa; - } - } - } - - return null; + String pathInContext = dropSlashWebdavFromPath(url.getPath()); + return pathResolver.resolveStorageArea(pathInContext); } @Override diff --git a/src/main/java/org/italiangrid/storm/webdav/server/DefaultPathResolver.java b/src/main/java/org/italiangrid/storm/webdav/server/DefaultPathResolver.java index fe4b4cc3..f7a7878b 100644 --- a/src/main/java/org/italiangrid/storm/webdav/server/DefaultPathResolver.java +++ b/src/main/java/org/italiangrid/storm/webdav/server/DefaultPathResolver.java @@ -22,6 +22,7 @@ import org.eclipse.jetty.util.URIUtil; import org.italiangrid.storm.webdav.config.StorageAreaConfiguration; import org.italiangrid.storm.webdav.config.StorageAreaInfo; +import org.italiangrid.storm.webdav.server.PathResolver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,18 +33,18 @@ public class DefaultPathResolver implements PathResolver { private static final Logger logger = LoggerFactory .getLogger(DefaultPathResolver.class); - private final NavigableMap contextMap; + private final NavigableMap contextMap; public DefaultPathResolver(StorageAreaConfiguration cfg) { this.saConfig = cfg; - contextMap = new TreeMap(); + contextMap = new TreeMap(); for (StorageAreaInfo sa : saConfig.getStorageAreaInfo()) { for (String ap : sa.accessPoints()) { logger.debug("Adding path mapping for sa {}: {} -> {}", sa.name(), ap, sa.rootPath()); - contextMap.put(ap, sa.rootPath()); + contextMap.put(ap, sa); } } @@ -61,11 +62,11 @@ protected String stripContextPath(String context, String path) { @Override public String resolvePath(String pathInContext) { - for (Map.Entry e : contextMap.descendingMap().entrySet()) { + for (Map.Entry e : contextMap.descendingMap().entrySet()) { if (pathInContext.startsWith(e.getKey())) { - String resolvedPath = URIUtil.addPaths(e.getValue(), + String resolvedPath = URIUtil.addPaths(e.getValue().rootPath(), stripContextPath(e.getKey(), pathInContext)); if (logger.isDebugEnabled()) { @@ -80,4 +81,22 @@ public String resolvePath(String pathInContext) { return null; } + @Override + public StorageAreaInfo resolveStorageArea(String pathInContext) { + + for (Map.Entry e : contextMap.descendingMap().entrySet()) { + + if (pathInContext.startsWith(e.getKey())) { + + if (logger.isDebugEnabled()) { + logger.debug("{} matches with access point {}. Resolved storage area name: {}", + pathInContext, e.getKey(), e.getValue().name()); + } + + return e.getValue(); + } + } + return null; + } + } diff --git a/src/main/java/org/italiangrid/storm/webdav/server/PathResolver.java b/src/main/java/org/italiangrid/storm/webdav/server/PathResolver.java index 75ebe003..8c74fcca 100644 --- a/src/main/java/org/italiangrid/storm/webdav/server/PathResolver.java +++ b/src/main/java/org/italiangrid/storm/webdav/server/PathResolver.java @@ -15,9 +15,13 @@ */ package org.italiangrid.storm.webdav.server; +import org.italiangrid.storm.webdav.config.StorageAreaInfo; + public interface PathResolver { public String resolvePath(String pathInContext); + + public StorageAreaInfo resolveStorageArea(String pathInContext); } 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 e598fbd5..ddf19cc8 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 @@ -33,6 +33,7 @@ import org.italiangrid.storm.webdav.config.ServiceConfiguration; import org.italiangrid.storm.webdav.config.StorageAreaConfiguration; import org.italiangrid.storm.webdav.config.StorageAreaInfo; +import org.italiangrid.storm.webdav.server.PathResolver; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -61,11 +62,14 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired VOMapDetailsService vomsMapDetailsService; + + @Autowired + PathResolver pathResolver; @Bean public AccessDecisionVoter customVoter() { - return new CopyMoveAuthzVoter(saConfiguration); + return new CopyMoveAuthzVoter(saConfiguration, pathResolver); } @Bean diff --git a/src/test/java/org/italiangrid/storm/webdav/authz/vomsmap/PathResolverTests.java b/src/test/java/org/italiangrid/storm/webdav/authz/vomsmap/PathResolverTests.java new file mode 100644 index 00000000..942bf84b --- /dev/null +++ b/src/test/java/org/italiangrid/storm/webdav/authz/vomsmap/PathResolverTests.java @@ -0,0 +1,124 @@ +/** + * Copyright (c) Istituto Nazionale di Fisica Nucleare, 2014. + * + * 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.vomsmap; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +import org.junit.Assert; +import org.italiangrid.storm.webdav.config.StorageAreaConfiguration; +import org.italiangrid.storm.webdav.config.StorageAreaInfo; +import org.italiangrid.storm.webdav.server.DefaultPathResolver; +import org.italiangrid.storm.webdav.server.PathResolver; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class PathResolverTests { + + private final String ROOTDIR = "/storage"; + + /* + * Map SA-name -> VO name + */ + private static Map input; + + @BeforeClass + public static void init() { + + input = new HashMap(); + input.put("test.vo.bis", "testers.eu-emi.eu"); + input.put("test.vo", "test.vo"); + input.put("test1", "testers.eu-emi.eu"); + input.put("test12", "test.vo"); + input.put("12test.", "testers.eu-emi.eu"); + input.put("12test", "test.vo"); + input.put("1", "testers.eu-emi.eu"); + input.put("12", "test.vo"); + input.put(".", "testers.eu-emi.eu"); + input.put(".1", "test.vo"); + } + + PathResolver pathResolver; + StorageAreaConfiguration saConfig; + List saInfoList; + + @Before + public void setup() { + + saInfoList = new ArrayList(); + for (String ap : input.keySet()) { + saInfoList.add(getMockSAInfo(ap, input.get(ap))); + } + + saConfig = mock(StorageAreaConfiguration.class); + when(saConfig.getStorageAreaInfo()).thenReturn(saInfoList); + + pathResolver = new DefaultPathResolver(saConfig); + } + + private StorageAreaInfo getMockSAInfo(String name, String voname) { + + StorageAreaInfo saInfo = mock(StorageAreaInfo.class); + + String ap = "/".concat(name); + String rootPath = ROOTDIR.concat("/").concat(voname); + + when(saInfo.name()).thenReturn(name); + when(saInfo.accessPoints()).thenReturn(Arrays.asList(ap)); + when(saInfo.rootPath()).thenReturn(rootPath); + when(saInfo.vos()).thenReturn(new HashSet(Arrays.asList(voname))); + + return saInfo; + } + + @Test + public void checkResolvedRootPath() { + + for (String name : input.keySet()) { + + String pathToTest = "/".concat(name).concat("/testdir"); + String expectedRootPath = ROOTDIR.concat("/").concat(input.get(name)) + .concat("/testdir"); + + String rootPath = pathResolver.resolvePath(pathToTest); + Assert.assertEquals(expectedRootPath, rootPath); + } + + } + + @Test + public void checkResolvedStorageArea() { + + for (String name : input.keySet()) { + + String pathToTest = "/".concat(name).concat("/testdir"); + String expectedRootPath = ROOTDIR.concat("/").concat(input.get(name)) + .concat("/testdir"); + + StorageAreaInfo sa = pathResolver.resolveStorageArea(pathToTest); + Assert.assertEquals(expectedRootPath, sa.rootPath() + "/testdir"); + } + } + +}