Loading src/main/java/it/inaf/oats/vospace/CreateNodeService.java +6 −33 Original line number Original line Diff line number Diff line Loading @@ -39,14 +39,12 @@ public class CreateNodeService { LOG.debug("createNodeService called for node with URI {} and PATH {}", node.getUri(), path); LOG.debug("createNodeService called for node with URI {} and PATH {}", node.getUri(), path); // Validate payload node URI // Get Node path (and validates it too) if (!isValidURI(node.getUri())) { String decodedURIFromNode = URIUtils.returnVosPathFromNodeURI(node.getUri(), authority); throw new InvalidURIException(node.getUri()); } // Check if payload URI is consistent with http request // Check if payload URI is consistent with http request if (!isUrlConsistentWithPayloadURI(node.getUri(), path)) { if (!decodedURIFromNode.equals(path)) { throw new InvalidURIException(node.getUri(), path); throw new InvalidURIException(decodedURIFromNode, path); } } // Check if another node is already present at specified path // Check if another node is already present at specified path Loading Loading @@ -127,31 +125,6 @@ public class CreateNodeService { } } // Assuming that this service implementation uses only ! as a separator // in the authority part of the URI private boolean isValidURI(String nodeURI) { String parsedAuthority; if (!nodeURI.startsWith("vos://")) { return false; } else { parsedAuthority = nodeURI.replaceAll("vos://", "").split("/", -1)[0]; } if (parsedAuthority.isEmpty() || !parsedAuthority.replace("~", "!").equals(authority)) { return false; } return true; } private boolean isUrlConsistentWithPayloadURI(String nodeURI, String path) { // It's assumed that nodeURI has been validated to be in the expected // form vos://authority[!~]somepath/mynode..." return nodeURI.replaceAll("vos://[^/]+", "").equals(path); } private String getParentPath(String path) { private String getParentPath(String path) { return NodeUtils.getParentPath(path); return NodeUtils.getParentPath(path); } } Loading src/main/java/it/inaf/oats/vospace/MoveService.java +5 −3 Original line number Original line Diff line number Diff line Loading @@ -8,6 +8,7 @@ package it.inaf.oats.vospace; import it.inaf.ia2.aa.data.User; import it.inaf.ia2.aa.data.User; import it.inaf.oats.vospace.datamodel.NodeUtils; import it.inaf.oats.vospace.datamodel.NodeUtils; import it.inaf.oats.vospace.exception.InternalFaultException; import it.inaf.oats.vospace.exception.InternalFaultException; import it.inaf.oats.vospace.exception.InvalidURIException; import it.inaf.oats.vospace.exception.NodeBusyException; import it.inaf.oats.vospace.exception.NodeBusyException; import it.inaf.oats.vospace.exception.NodeNotFoundException; import it.inaf.oats.vospace.exception.NodeNotFoundException; import it.inaf.oats.vospace.exception.PermissionDeniedException; import it.inaf.oats.vospace.exception.PermissionDeniedException; Loading Loading @@ -41,10 +42,10 @@ public class MoveService { public void processMoveJob(Transfer transfer) { public void processMoveJob(Transfer transfer) { // Get Source Vos Path // Get Source Vos Path String sourcePath = transfer.getTarget().substring("vos://".length() + authority.length()); String sourcePath = URIUtils.returnVosPathFromNodeURI(transfer.getTarget(), authority); // Get Destination Vos Path (it's in transfer direction) // Get Destination Vos Path (it's in transfer direction) String destinationPath = transfer.getDirection().substring("vos://".length() + authority.length()); String destinationPath = URIUtils.returnVosPathFromNodeURI(transfer.getDirection(), authority); // Extract User permissions from servlet request // Extract User permissions from servlet request User user = (User) servletRequest.getUserPrincipal(); User user = (User) servletRequest.getUserPrincipal(); Loading Loading @@ -114,6 +115,7 @@ public class MoveService { } } } } private void validatePath(String path) { private void validatePath(String path) { if (path.equals("/")) { if (path.equals("/")) { throw new IllegalArgumentException("Cannot move root node or to root node"); throw new IllegalArgumentException("Cannot move root node or to root node"); Loading src/main/java/it/inaf/oats/vospace/URIUtils.java 0 → 100644 +66 −0 Original line number Original line Diff line number Diff line /* * This file is part of vospace-rest * Copyright (C) 2021 Istituto Nazionale di Astrofisica * SPDX-License-Identifier: GPL-3.0-or-later */ package it.inaf.oats.vospace; import it.inaf.oats.vospace.exception.InvalidArgumentException; import it.inaf.oats.vospace.exception.InvalidURIException; import java.net.URI; import java.net.URISyntaxException; import java.util.regex.Pattern; public class URIUtils { // It's different from the one in NodeUtils! // Slashes are treated separately private static final Pattern FORBIDDEN_CHARS = Pattern.compile("[\\x00\\x08\\x0B\\x0C\\x0E-\\x1F" + Pattern.quote("<>?\":\\|'`*") + "]"); // This method validates the URI too public static String returnVosPathFromNodeURI(String nodeURI, String authority) { String scheme = "vos"; String resultPath = null; try{ URI uri = new URI(nodeURI); // Check scheme if(!uri.isAbsolute() || uri.isOpaque() || !uri.getRawSchemeSpecificPart().startsWith("//") || !uri.getScheme().equalsIgnoreCase(scheme)) throw new InvalidURIException(nodeURI); // Check authority if(!uri.getAuthority().replace("~", "!").equals(authority)) throw new InvalidURIException(nodeURI); // Check path String rawPath = uri.getRawPath(); // Check if raw Path is null or contains percent encoded slashes or multiple // separators if(rawPath == null || rawPath.contains("//") || rawPath.contains("%2F") || rawPath.contains("%2f")) throw new InvalidURIException(nodeURI); resultPath = uri.getPath(); if(resultPath.isBlank() || FORBIDDEN_CHARS.matcher(resultPath).find() || (!resultPath.equals("/") && resultPath.endsWith("/"))) throw new InvalidURIException(nodeURI); } catch(URISyntaxException e) { throw new InvalidURIException(nodeURI); } return resultPath; } } src/test/java/it/inaf/oats/vospace/URIUtilsTest.java 0 → 100644 +82 −0 Original line number Original line Diff line number Diff line /* * This file is part of vospace-datamodel * Copyright (C) 2021 Istituto Nazionale di Astrofisica * SPDX-License-Identifier: GPL-3.0-or-later */ package it.inaf.oats.vospace; import it.inaf.oats.vospace.exception.InvalidURIException; import java.util.ArrayList; import java.util.List; import net.ivoa.xml.vospace.v2.DataNode; import net.ivoa.xml.vospace.v2.LinkNode; import net.ivoa.xml.vospace.v2.Node; import net.ivoa.xml.vospace.v2.Property; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; public class URIUtilsTest { private final String authority = "example.com!vospace"; @Test public void testReturnVosPathFromNodeURI() { String test1 = "vos://example.com!wrong/"; assertThrows(InvalidURIException.class, () -> { URIUtils.returnVosPathFromNodeURI(test1, authority); }); String test2 = "wrong://example.com!wrong/"; assertThrows(InvalidURIException.class, () -> { URIUtils.returnVosPathFromNodeURI(test2, authority); }); String test3 = "vos://example.com!vospace"; assertThrows(InvalidURIException.class, () -> { URIUtils.returnVosPathFromNodeURI(test3, authority); }); String test4 = "vos://example.com!vospace/n1/n2/n3/n%2F4"; assertThrows(InvalidURIException.class, () -> { URIUtils.returnVosPathFromNodeURI(test4, authority); }); String test5 = "vos://example.com!vospace/n1/n2/n3//n4"; assertThrows(InvalidURIException.class, () -> { URIUtils.returnVosPathFromNodeURI(test5, authority); }); String test6 = "vos://example.com!vospace/n1/n2/n3/n4/"; assertThrows(InvalidURIException.class, () -> { URIUtils.returnVosPathFromNodeURI(test6, authority); }); String test7 = "vos://example.com!vospace/n1/n2/n*3/n4/"; assertThrows(InvalidURIException.class, () -> { URIUtils.returnVosPathFromNodeURI(test7, authority); }); String test8 = "vos://example.com!vospace/n1/n2/n3/n4"; assertEquals("/n1/n2/n3/n4", URIUtils.returnVosPathFromNodeURI(test8, authority)); } } Loading
src/main/java/it/inaf/oats/vospace/CreateNodeService.java +6 −33 Original line number Original line Diff line number Diff line Loading @@ -39,14 +39,12 @@ public class CreateNodeService { LOG.debug("createNodeService called for node with URI {} and PATH {}", node.getUri(), path); LOG.debug("createNodeService called for node with URI {} and PATH {}", node.getUri(), path); // Validate payload node URI // Get Node path (and validates it too) if (!isValidURI(node.getUri())) { String decodedURIFromNode = URIUtils.returnVosPathFromNodeURI(node.getUri(), authority); throw new InvalidURIException(node.getUri()); } // Check if payload URI is consistent with http request // Check if payload URI is consistent with http request if (!isUrlConsistentWithPayloadURI(node.getUri(), path)) { if (!decodedURIFromNode.equals(path)) { throw new InvalidURIException(node.getUri(), path); throw new InvalidURIException(decodedURIFromNode, path); } } // Check if another node is already present at specified path // Check if another node is already present at specified path Loading Loading @@ -127,31 +125,6 @@ public class CreateNodeService { } } // Assuming that this service implementation uses only ! as a separator // in the authority part of the URI private boolean isValidURI(String nodeURI) { String parsedAuthority; if (!nodeURI.startsWith("vos://")) { return false; } else { parsedAuthority = nodeURI.replaceAll("vos://", "").split("/", -1)[0]; } if (parsedAuthority.isEmpty() || !parsedAuthority.replace("~", "!").equals(authority)) { return false; } return true; } private boolean isUrlConsistentWithPayloadURI(String nodeURI, String path) { // It's assumed that nodeURI has been validated to be in the expected // form vos://authority[!~]somepath/mynode..." return nodeURI.replaceAll("vos://[^/]+", "").equals(path); } private String getParentPath(String path) { private String getParentPath(String path) { return NodeUtils.getParentPath(path); return NodeUtils.getParentPath(path); } } Loading
src/main/java/it/inaf/oats/vospace/MoveService.java +5 −3 Original line number Original line Diff line number Diff line Loading @@ -8,6 +8,7 @@ package it.inaf.oats.vospace; import it.inaf.ia2.aa.data.User; import it.inaf.ia2.aa.data.User; import it.inaf.oats.vospace.datamodel.NodeUtils; import it.inaf.oats.vospace.datamodel.NodeUtils; import it.inaf.oats.vospace.exception.InternalFaultException; import it.inaf.oats.vospace.exception.InternalFaultException; import it.inaf.oats.vospace.exception.InvalidURIException; import it.inaf.oats.vospace.exception.NodeBusyException; import it.inaf.oats.vospace.exception.NodeBusyException; import it.inaf.oats.vospace.exception.NodeNotFoundException; import it.inaf.oats.vospace.exception.NodeNotFoundException; import it.inaf.oats.vospace.exception.PermissionDeniedException; import it.inaf.oats.vospace.exception.PermissionDeniedException; Loading Loading @@ -41,10 +42,10 @@ public class MoveService { public void processMoveJob(Transfer transfer) { public void processMoveJob(Transfer transfer) { // Get Source Vos Path // Get Source Vos Path String sourcePath = transfer.getTarget().substring("vos://".length() + authority.length()); String sourcePath = URIUtils.returnVosPathFromNodeURI(transfer.getTarget(), authority); // Get Destination Vos Path (it's in transfer direction) // Get Destination Vos Path (it's in transfer direction) String destinationPath = transfer.getDirection().substring("vos://".length() + authority.length()); String destinationPath = URIUtils.returnVosPathFromNodeURI(transfer.getDirection(), authority); // Extract User permissions from servlet request // Extract User permissions from servlet request User user = (User) servletRequest.getUserPrincipal(); User user = (User) servletRequest.getUserPrincipal(); Loading Loading @@ -114,6 +115,7 @@ public class MoveService { } } } } private void validatePath(String path) { private void validatePath(String path) { if (path.equals("/")) { if (path.equals("/")) { throw new IllegalArgumentException("Cannot move root node or to root node"); throw new IllegalArgumentException("Cannot move root node or to root node"); Loading
src/main/java/it/inaf/oats/vospace/URIUtils.java 0 → 100644 +66 −0 Original line number Original line Diff line number Diff line /* * This file is part of vospace-rest * Copyright (C) 2021 Istituto Nazionale di Astrofisica * SPDX-License-Identifier: GPL-3.0-or-later */ package it.inaf.oats.vospace; import it.inaf.oats.vospace.exception.InvalidArgumentException; import it.inaf.oats.vospace.exception.InvalidURIException; import java.net.URI; import java.net.URISyntaxException; import java.util.regex.Pattern; public class URIUtils { // It's different from the one in NodeUtils! // Slashes are treated separately private static final Pattern FORBIDDEN_CHARS = Pattern.compile("[\\x00\\x08\\x0B\\x0C\\x0E-\\x1F" + Pattern.quote("<>?\":\\|'`*") + "]"); // This method validates the URI too public static String returnVosPathFromNodeURI(String nodeURI, String authority) { String scheme = "vos"; String resultPath = null; try{ URI uri = new URI(nodeURI); // Check scheme if(!uri.isAbsolute() || uri.isOpaque() || !uri.getRawSchemeSpecificPart().startsWith("//") || !uri.getScheme().equalsIgnoreCase(scheme)) throw new InvalidURIException(nodeURI); // Check authority if(!uri.getAuthority().replace("~", "!").equals(authority)) throw new InvalidURIException(nodeURI); // Check path String rawPath = uri.getRawPath(); // Check if raw Path is null or contains percent encoded slashes or multiple // separators if(rawPath == null || rawPath.contains("//") || rawPath.contains("%2F") || rawPath.contains("%2f")) throw new InvalidURIException(nodeURI); resultPath = uri.getPath(); if(resultPath.isBlank() || FORBIDDEN_CHARS.matcher(resultPath).find() || (!resultPath.equals("/") && resultPath.endsWith("/"))) throw new InvalidURIException(nodeURI); } catch(URISyntaxException e) { throw new InvalidURIException(nodeURI); } return resultPath; } }
src/test/java/it/inaf/oats/vospace/URIUtilsTest.java 0 → 100644 +82 −0 Original line number Original line Diff line number Diff line /* * This file is part of vospace-datamodel * Copyright (C) 2021 Istituto Nazionale di Astrofisica * SPDX-License-Identifier: GPL-3.0-or-later */ package it.inaf.oats.vospace; import it.inaf.oats.vospace.exception.InvalidURIException; import java.util.ArrayList; import java.util.List; import net.ivoa.xml.vospace.v2.DataNode; import net.ivoa.xml.vospace.v2.LinkNode; import net.ivoa.xml.vospace.v2.Node; import net.ivoa.xml.vospace.v2.Property; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; public class URIUtilsTest { private final String authority = "example.com!vospace"; @Test public void testReturnVosPathFromNodeURI() { String test1 = "vos://example.com!wrong/"; assertThrows(InvalidURIException.class, () -> { URIUtils.returnVosPathFromNodeURI(test1, authority); }); String test2 = "wrong://example.com!wrong/"; assertThrows(InvalidURIException.class, () -> { URIUtils.returnVosPathFromNodeURI(test2, authority); }); String test3 = "vos://example.com!vospace"; assertThrows(InvalidURIException.class, () -> { URIUtils.returnVosPathFromNodeURI(test3, authority); }); String test4 = "vos://example.com!vospace/n1/n2/n3/n%2F4"; assertThrows(InvalidURIException.class, () -> { URIUtils.returnVosPathFromNodeURI(test4, authority); }); String test5 = "vos://example.com!vospace/n1/n2/n3//n4"; assertThrows(InvalidURIException.class, () -> { URIUtils.returnVosPathFromNodeURI(test5, authority); }); String test6 = "vos://example.com!vospace/n1/n2/n3/n4/"; assertThrows(InvalidURIException.class, () -> { URIUtils.returnVosPathFromNodeURI(test6, authority); }); String test7 = "vos://example.com!vospace/n1/n2/n*3/n4/"; assertThrows(InvalidURIException.class, () -> { URIUtils.returnVosPathFromNodeURI(test7, authority); }); String test8 = "vos://example.com!vospace/n1/n2/n3/n4"; assertEquals("/n1/n2/n3/n4", URIUtils.returnVosPathFromNodeURI(test8, authority)); } }