From dcea92caaef1a0483fe5cef239ba03f038a6673c Mon Sep 17 00:00:00 2001 From: Nicola Fulvio Calabria <nicola.calabria@inaf.it> Date: Sat, 28 Aug 2021 20:34:25 +0200 Subject: [PATCH] Added LinkNode support to pullFromVoSpace --- .../inaf/oats/vospace/BaseNodeController.java | 18 ++++++++++++- .../oats/vospace/CreateNodeController.java | 16 ++--------- .../inaf/oats/vospace/SetNodeController.java | 4 +++ .../java/it/inaf/oats/vospace/UriService.java | 27 +++++++++++++++---- 4 files changed, 45 insertions(+), 20 deletions(-) diff --git a/src/main/java/it/inaf/oats/vospace/BaseNodeController.java b/src/main/java/it/inaf/oats/vospace/BaseNodeController.java index ddf00d9..1b317c3 100644 --- a/src/main/java/it/inaf/oats/vospace/BaseNodeController.java +++ b/src/main/java/it/inaf/oats/vospace/BaseNodeController.java @@ -6,15 +6,21 @@ package it.inaf.oats.vospace; import it.inaf.oats.vospace.datamodel.NodeUtils; +import it.inaf.oats.vospace.exception.InvalidArgumentException; import it.inaf.oats.vospace.exception.InvalidURIException; import javax.servlet.http.HttpServletRequest; +import net.ivoa.xml.vospace.v2.LinkNode; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; public abstract class BaseNodeController { @Autowired private HttpServletRequest servletRequest; - + + @Value("${vospace-authority}") + protected String authority; + protected String getPath() { String requestURL = servletRequest.getRequestURL().toString(); try { @@ -27,4 +33,14 @@ public abstract class BaseNodeController { protected String getParentPath(String path) { return NodeUtils.getParentPath(path); } + + protected void validateInternalLinkNode(LinkNode linkNode) { + String target = linkNode.getTarget(); + // I validate it here to add context easily + if (target == null) { + throw new InvalidArgumentException("LinkNode in payload has no target element specified"); + } + + URIUtils.returnVosPathFromNodeURI(linkNode.getTarget(), authority); + } } diff --git a/src/main/java/it/inaf/oats/vospace/CreateNodeController.java b/src/main/java/it/inaf/oats/vospace/CreateNodeController.java index 759af9f..e115d15 100644 --- a/src/main/java/it/inaf/oats/vospace/CreateNodeController.java +++ b/src/main/java/it/inaf/oats/vospace/CreateNodeController.java @@ -6,7 +6,6 @@ package it.inaf.oats.vospace; import it.inaf.ia2.aa.data.User; -import it.inaf.oats.vospace.exception.InvalidArgumentException; import it.inaf.oats.vospace.exception.InvalidURIException; import net.ivoa.xml.vospace.v2.LinkNode; import net.ivoa.xml.vospace.v2.Node; @@ -17,7 +16,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PutMapping; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; @RestController public class CreateNodeController extends BaseNodeController { @@ -27,9 +25,6 @@ public class CreateNodeController extends BaseNodeController { @Autowired private CreateNodeService createNodeService; - @Value("${vospace-authority}") - private String authority; - @PutMapping(value = {"/nodes", "/nodes/**"}, consumes = {MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_JSON_VALUE}, produces = {MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_JSON_VALUE}) @@ -40,7 +35,7 @@ public class CreateNodeController extends BaseNodeController { LOG.debug("createNodeController called for node with URI {} and PATH {}", node.getUri(), path); // Get Node path (and validates it too) - String decodedURIPathFromNode = URIUtils.returnVosPathFromNodeURI(node.getUri(), authority); + String decodedURIPathFromNode = URIUtils.returnVosPathFromNodeURI(node.getUri(), this.authority); LOG.debug("createNodeController URI: {} decoded as {}", node.getUri(), decodedURIPathFromNode); @@ -59,14 +54,7 @@ public class CreateNodeController extends BaseNodeController { private void validateInputNode(Node node) { if (node instanceof LinkNode) { - LinkNode linkNode = (LinkNode) node; - String target = linkNode.getTarget(); - // I validate it here to add context easily - if (target == null) { - throw new InvalidArgumentException("LinkNode in payload has no target element specified"); - } - - URIUtils.returnVosPathFromNodeURI(linkNode.getTarget(), authority); + this.validateInternalLinkNode((LinkNode) node); } } diff --git a/src/main/java/it/inaf/oats/vospace/SetNodeController.java b/src/main/java/it/inaf/oats/vospace/SetNodeController.java index 91b6d7f..88621d4 100644 --- a/src/main/java/it/inaf/oats/vospace/SetNodeController.java +++ b/src/main/java/it/inaf/oats/vospace/SetNodeController.java @@ -13,6 +13,7 @@ import it.inaf.oats.vospace.persistence.NodeDAO; import java.util.List; import javax.servlet.http.HttpServletRequest; 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.View; import org.slf4j.Logger; @@ -65,8 +66,11 @@ public class SetNodeController extends BaseNodeController { // This method cannot be used to modify the accepts or provides list of Views for the Node. // Only DataNodes has Views (see VOSpace Data Model) + // Also if input node is LinkNode, target must be validated as internal URI if (node instanceof DataNode) { checkViews((DataNode) node, (DataNode) toBeModifiedNode); + } else if(node instanceof LinkNode) { + this.validateInternalLinkNode((LinkNode) node); } //The service SHOULD throw a HTTP 500 status code including an InternalFault fault diff --git a/src/main/java/it/inaf/oats/vospace/UriService.java b/src/main/java/it/inaf/oats/vospace/UriService.java index 13f755d..0f23ddb 100644 --- a/src/main/java/it/inaf/oats/vospace/UriService.java +++ b/src/main/java/it/inaf/oats/vospace/UriService.java @@ -32,6 +32,7 @@ import java.util.stream.Collectors; import javax.servlet.http.HttpServletRequest; import net.ivoa.xml.uws.v1.JobSummary; 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.Protocol; import net.ivoa.xml.vospace.v2.Transfer; @@ -77,7 +78,7 @@ public class UriService { negotiatedTransfer.setTarget(transfer.getTarget()); negotiatedTransfer.setDirection(transfer.getDirection()); // according to examples found in specification view is not copied - + if (transfer.getProtocols().isEmpty()) { // At least one protocol is expected from client throw new InvalidArgumentException("Transfer contains no protocols"); @@ -118,7 +119,7 @@ public class UriService { } negotiatedTransfer.getProtocols().addAll(validProtocols); - + return negotiatedTransfer; } @@ -127,7 +128,16 @@ public class UriService { User user) { Optional<Node> optNode = nodeDao.listNode(relativePath); if (optNode.isPresent()) { - return optNode.get(); + Node node = optNode.get(); + if (jobType.equals(JobService.JobDirection.pullFromVoSpace)) { + if (node instanceof LinkNode) { + if (!NodeUtils.checkIfReadable(node, user.getName(), user.getGroups())) { + throw PermissionDeniedException.forPath(relativePath); + } + node = this.followLink((LinkNode) node); + } + } + return node; } else { switch (jobType) { case pullFromVoSpace: @@ -152,8 +162,8 @@ public class UriService { List<String> groups = user.getGroups(); // Check privileges write or read according to job type - JobService.JobDirection jobType = - JobDirection.getJobDirectionEnumFromTransfer(transfer); + JobService.JobDirection jobType + = JobDirection.getJobDirectionEnumFromTransfer(transfer); Node node = this.getEndpointNode(relativePath, jobType, user); switch (jobType) { @@ -266,4 +276,11 @@ public class UriService { return (Transfer) job.getJobInfo().getAny().get(0); } + + private Node followLink(LinkNode linkNode) { + String targetPath = URIUtils.returnVosPathFromNodeURI(linkNode.getTarget(), authority); + Optional<Node> targetNode = nodeDao.listNode(targetPath); + return targetNode.orElseThrow(() -> new InternalFaultException("Broken Link to target: " + targetPath)); + + } } -- GitLab