Skip to content
Snippets Groups Projects
Commit 969406ac authored by Sara Bertocco's avatar Sara Bertocco
Browse files
parents 7456a69e 773e1e0d
No related branches found
No related tags found
No related merge requests found
package it.inaf.oats.vospace; 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.NodeProperties;
import it.inaf.oats.vospace.datamodel.NodeUtils; import it.inaf.oats.vospace.datamodel.NodeUtils;
import net.ivoa.xml.vospace.v2.Node; import net.ivoa.xml.vospace.v2.Node;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
...@@ -13,6 +14,8 @@ import org.springframework.web.bind.annotation.PutMapping; ...@@ -13,6 +14,8 @@ import org.springframework.web.bind.annotation.PutMapping;
import it.inaf.oats.vospace.exception.*; import it.inaf.oats.vospace.exception.*;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import net.ivoa.xml.vospace.v2.Property;
import java.util.List;
@RestController @RestController
public class CreateNodeController extends BaseNodeController { public class CreateNodeController extends BaseNodeController {
...@@ -68,6 +71,25 @@ public class CreateNodeController extends BaseNodeController { ...@@ -68,6 +71,25 @@ public class CreateNodeController extends BaseNodeController {
throw new PermissionDeniedException(path); throw new PermissionDeniedException(path);
} }
// Check if node creator property is set. If not set it according to
// token. In case of creator mistmatch between node and token throw
// exception
String creator = NodeProperties.getNodePropertyByURI(
node, NodeProperties.CREATOR_URI);
if(creator == null)
{
Property creatorProperty = new Property();
creatorProperty.setUri(NodeProperties.CREATOR_URI);
creatorProperty.setValue(principal.getName());
node.getProperties().add(creatorProperty);
} else {
if(!creator.equals(principal.getName()))
// maybe a more specific exception would be more appropriate?
throw new PermissionDeniedException(path);
}
nodeDao.createNode(node); nodeDao.createNode(node);
return node; return node;
......
...@@ -13,6 +13,10 @@ import javax.servlet.http.HttpServletRequest; ...@@ -13,6 +13,10 @@ import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import it.inaf.ia2.aa.data.User;
import it.inaf.oats.vospace.datamodel.NodeUtils;
import java.util.Optional;
import it.inaf.oats.vospace.exception.PermissionDeniedException;
@RestController @RestController
public class ListNodeController extends BaseNodeController { public class ListNodeController extends BaseNodeController {
...@@ -24,10 +28,21 @@ public class ListNodeController extends BaseNodeController { ...@@ -24,10 +28,21 @@ public class ListNodeController extends BaseNodeController {
@GetMapping(value = {"/nodes", "/nodes/**"}, @GetMapping(value = {"/nodes", "/nodes/**"},
produces = {MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE, MediaType.TEXT_XML_VALUE}) produces = {MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE, MediaType.TEXT_XML_VALUE})
public ResponseEntity<Node> listNode(HttpServletRequest request) { public ResponseEntity<Node> listNode(HttpServletRequest request, User principal) {
String path = getPath(); String path = getPath();
LOG.debug("listNode called for path {}", path); LOG.debug("listNode called for path {}", path);
return ResponseEntity.ok(nodeDAO.listNode(path)
.orElseThrow(() -> new NodeNotFoundException(path))); Optional<Node> optNode = nodeDAO.listNode(path);
if (optNode.isEmpty()) {
throw new NodeNotFoundException(path);
} else {
if (!NodeUtils.checkIfReadable(
optNode.get(), principal.getName(), principal.getGroups())) {
throw new PermissionDeniedException(path);
}
}
return ResponseEntity.ok(optNode.get());
} }
} }
...@@ -5,6 +5,7 @@ import java.io.InputStream; ...@@ -5,6 +5,7 @@ import java.io.InputStream;
import java.net.URI; import java.net.URI;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import net.ivoa.xml.vospace.v2.Property; import net.ivoa.xml.vospace.v2.Property;
import it.inaf.oats.vospace.datamodel.NodeProperties;
import net.ivoa.xml.vospace.v2.UnstructuredDataNode; import net.ivoa.xml.vospace.v2.UnstructuredDataNode;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.argThat;
...@@ -272,6 +273,57 @@ public class CreateNodeControllerTest { ...@@ -272,6 +273,57 @@ public class CreateNodeControllerTest {
verify(nodeDao, times(1)).createNode(any()); verify(nodeDao, times(1)).createNode(any());
} }
@Test
public void testWriteOwnerAbsent() throws Exception {
String requestBody =
getResourceFileContent("create-unstructured-data-node.xml");
when(nodeDao.listNode(eq("/")))
.thenReturn(Optional.of(getContainerParentNodeWithCreator("/")));
// no node creator specified in xml file
mockMvc.perform(put("/nodes/mydata1")
.header("Authorization", "Bearer user2_token")
.content(requestBody)
.contentType(MediaType.APPLICATION_XML)
.accept(MediaType.APPLICATION_XML))
.andDo(print())
.andExpect(status().is2xxSuccessful());
// assert creator properties now matches user2
verify(nodeDao, times(1)).createNode(argThat(node->{
UnstructuredDataNode udn = (UnstructuredDataNode) node;
String creator = NodeProperties.getNodePropertyByURI(
udn, NodeProperties.CREATOR_URI);
return (creator != null && creator.equals("user2"));
}
));
}
@Test
public void testWriteOwnerMismatch() throws Exception {
String requestBody =
getResourceFileContent("create-unstructured-data-node-user1.xml");
when(nodeDao.listNode(eq("/")))
.thenReturn(Optional.of(getContainerParentNodeWithCreator("/")));
// no node creator specified in xml file
mockMvc.perform(put("/nodes/mydata1")
.header("Authorization", "Bearer user2_token")
.content(requestBody)
.contentType(MediaType.APPLICATION_XML)
.accept(MediaType.APPLICATION_XML))
.andDo(print())
.andExpect(status().is4xxClientError());
// assert createNode is not called
verify(nodeDao, times(0)).createNode(any());
}
@Test @Test
public void testSubPath() throws Exception { public void testSubPath() throws Exception {
......
package it.inaf.oats.vospace; package it.inaf.oats.vospace;
import static it.inaf.oats.vospace.VOSpaceXmlTestUtil.loadDocument; import static it.inaf.oats.vospace.VOSpaceXmlTestUtil.loadDocument;
import it.inaf.oats.vospace.datamodel.NodeProperties;
import it.inaf.oats.vospace.persistence.NodeDAO; import it.inaf.oats.vospace.persistence.NodeDAO;
import java.util.Optional; import java.util.Optional;
import net.ivoa.xml.vospace.v2.ContainerNode; import net.ivoa.xml.vospace.v2.ContainerNode;
import net.ivoa.xml.vospace.v2.DataNode; import net.ivoa.xml.vospace.v2.DataNode;
import net.ivoa.xml.vospace.v2.Node; import net.ivoa.xml.vospace.v2.Node;
import net.ivoa.xml.vospace.v2.Property;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
...@@ -16,7 +18,10 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -16,7 +18,10 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
...@@ -25,6 +30,8 @@ import org.w3c.dom.Document; ...@@ -25,6 +30,8 @@ import org.w3c.dom.Document;
@SpringBootTest @SpringBootTest
@AutoConfigureMockMvc @AutoConfigureMockMvc
@ContextConfiguration(classes = {TokenFilterConfig.class})
@TestPropertySource(properties = "spring.main.allow-bean-definition-overriding=true")
public class ListNodeControllerTest { public class ListNodeControllerTest {
private static final String URI_PREFIX = "vos://example.com!vospace"; private static final String URI_PREFIX = "vos://example.com!vospace";
...@@ -78,9 +85,38 @@ public class ListNodeControllerTest { ...@@ -78,9 +85,38 @@ public class ListNodeControllerTest {
.andExpect(status().isNotFound()); .andExpect(status().isNotFound());
} }
@Test
public void testPermissionDeniedUser() throws Exception {
Node node = getDataNodeByOwnership("user2","group1");
when(dao.listNode(eq("/mynode"))).thenReturn(Optional.of(node));
mockMvc.perform(get("/nodes/mynode")
.header("Authorization", "Bearer user1_token")
.accept(MediaType.APPLICATION_XML))
.andExpect(status().is4xxClientError());
}
@Test
public void testGrantedByGroup() throws Exception {
Node node = getDataNodeByOwnership("user1","group1");
when(dao.listNode(eq("/mynode"))).thenReturn(Optional.of(node));
mockMvc.perform(get("/nodes/mynode")
.header("Authorization", "Bearer user2_token")
.accept(MediaType.APPLICATION_XML))
.andExpect(status().is2xxSuccessful());
}
private Optional<Node> getRootNode() { private Optional<Node> getRootNode() {
ContainerNode root = new ContainerNode(); ContainerNode root = new ContainerNode();
root.setUri(URI_PREFIX + "/"); root.setUri(URI_PREFIX + "/");
Property publicProperty = new Property();
publicProperty.setUri(NodeProperties.PUBLIC_READ_URI);
publicProperty.setValue("true");
root.getProperties().add(publicProperty);
root.getNodes().add(getDataNode()); root.getNodes().add(getDataNode());
return Optional.of(root); return Optional.of(root);
} }
...@@ -88,6 +124,29 @@ public class ListNodeControllerTest { ...@@ -88,6 +124,29 @@ public class ListNodeControllerTest {
private Node getDataNode() { private Node getDataNode() {
DataNode node = new DataNode(); DataNode node = new DataNode();
node.setUri(URI_PREFIX + "/mynode"); node.setUri(URI_PREFIX + "/mynode");
Property publicProperty = new Property();
publicProperty.setUri(NodeProperties.PUBLIC_READ_URI);
publicProperty.setValue("true");
node.getProperties().add(publicProperty);
return node;
}
private Node getDataNodeByOwnership(String ownerID, String group)
{
DataNode node = new DataNode();
node.setUri(URI_PREFIX + "/mynode");
// Set owner
Property creatorProperty = new Property();
creatorProperty.setUri(NodeProperties.CREATOR_URI);
creatorProperty.setValue(ownerID);
node.getProperties().add(creatorProperty);
// set group
Property readGroupProperty = new Property();
readGroupProperty.setUri(NodeProperties.GROUP_READ_URI);
readGroupProperty.setValue(group);
node.getProperties().add(readGroupProperty);
return node; return node;
} }
} }
<vos:node xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:vos="http://www.ivoa.net/xml/VOSpace/v2.0" xsi:type="vos:UnstructuredDataNode" uri="vos://example.com!vospace/mydata1">
<vos:properties>
<vos:property uri="ivo://ivoa.net/vospace/core#description">test value</vos:property>
<vos:property uri="ivo://ivoa.net/vospace/core#creator">user1</vos:property>
</vos:properties>
<vos:accepts/>
<vos:provides/>
<vos:capabilities/>
</vos:node>
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment