Loading src/main/java/it/inaf/oats/vospace/CreateNodeController.java +22 −0 Original line number Diff line number Diff line package it.inaf.oats.vospace; import it.inaf.ia2.aa.data.User; import it.inaf.oats.vospace.datamodel.NodeProperties; import it.inaf.oats.vospace.datamodel.NodeUtils; import net.ivoa.xml.vospace.v2.Node; import org.springframework.http.MediaType; Loading @@ -13,6 +14,8 @@ import org.springframework.web.bind.annotation.PutMapping; import it.inaf.oats.vospace.exception.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.ivoa.xml.vospace.v2.Property; import java.util.List; @RestController public class CreateNodeController extends BaseNodeController { Loading Loading @@ -68,6 +71,25 @@ public class CreateNodeController extends BaseNodeController { 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); return node; Loading src/main/java/it/inaf/oats/vospace/ListNodeController.java +19 −4 Original line number Diff line number Diff line Loading @@ -13,6 +13,10 @@ import javax.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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 public class ListNodeController extends BaseNodeController { Loading @@ -24,10 +28,21 @@ public class ListNodeController extends BaseNodeController { @GetMapping(value = {"/nodes", "/nodes/**"}, 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(); 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()); } } src/test/java/it/inaf/oats/vospace/CreateNodeControllerTest.java +52 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ import java.io.InputStream; import java.net.URI; import java.nio.charset.StandardCharsets; import net.ivoa.xml.vospace.v2.Property; import it.inaf.oats.vospace.datamodel.NodeProperties; import net.ivoa.xml.vospace.v2.UnstructuredDataNode; import org.junit.jupiter.api.Test; import static org.mockito.ArgumentMatchers.argThat; Loading Loading @@ -272,6 +273,57 @@ public class CreateNodeControllerTest { 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 public void testSubPath() throws Exception { Loading src/test/java/it/inaf/oats/vospace/ListNodeControllerTest.java +59 −0 Original line number Diff line number Diff line package it.inaf.oats.vospace; import static it.inaf.oats.vospace.VOSpaceXmlTestUtil.loadDocument; import it.inaf.oats.vospace.datamodel.NodeProperties; import it.inaf.oats.vospace.persistence.NodeDAO; import java.util.Optional; import net.ivoa.xml.vospace.v2.ContainerNode; import net.ivoa.xml.vospace.v2.DataNode; import net.ivoa.xml.vospace.v2.Node; import net.ivoa.xml.vospace.v2.Property; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; import static org.mockito.ArgumentMatchers.eq; Loading @@ -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.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.HttpHeaders; 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 static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; Loading @@ -25,6 +30,8 @@ import org.w3c.dom.Document; @SpringBootTest @AutoConfigureMockMvc @ContextConfiguration(classes = {TokenFilterConfig.class}) @TestPropertySource(properties = "spring.main.allow-bean-definition-overriding=true") public class ListNodeControllerTest { private static final String URI_PREFIX = "vos://example.com!vospace"; Loading Loading @@ -78,9 +85,38 @@ public class ListNodeControllerTest { .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() { ContainerNode root = new ContainerNode(); 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()); return Optional.of(root); } Loading @@ -88,6 +124,29 @@ public class ListNodeControllerTest { private Node getDataNode() { DataNode node = new DataNode(); 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; } } src/test/resources/create-unstructured-data-node-user1.xml 0 → 100644 +11 −0 Original line number Diff line number Diff line <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 src/test/resources/create-unstructured-data-node.xml +1 −1 File changed.Contains only whitespace changes. Show changes Loading
src/main/java/it/inaf/oats/vospace/CreateNodeController.java +22 −0 Original line number Diff line number Diff line package it.inaf.oats.vospace; import it.inaf.ia2.aa.data.User; import it.inaf.oats.vospace.datamodel.NodeProperties; import it.inaf.oats.vospace.datamodel.NodeUtils; import net.ivoa.xml.vospace.v2.Node; import org.springframework.http.MediaType; Loading @@ -13,6 +14,8 @@ import org.springframework.web.bind.annotation.PutMapping; import it.inaf.oats.vospace.exception.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.ivoa.xml.vospace.v2.Property; import java.util.List; @RestController public class CreateNodeController extends BaseNodeController { Loading Loading @@ -68,6 +71,25 @@ public class CreateNodeController extends BaseNodeController { 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); return node; Loading
src/main/java/it/inaf/oats/vospace/ListNodeController.java +19 −4 Original line number Diff line number Diff line Loading @@ -13,6 +13,10 @@ import javax.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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 public class ListNodeController extends BaseNodeController { Loading @@ -24,10 +28,21 @@ public class ListNodeController extends BaseNodeController { @GetMapping(value = {"/nodes", "/nodes/**"}, 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(); 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()); } }
src/test/java/it/inaf/oats/vospace/CreateNodeControllerTest.java +52 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ import java.io.InputStream; import java.net.URI; import java.nio.charset.StandardCharsets; import net.ivoa.xml.vospace.v2.Property; import it.inaf.oats.vospace.datamodel.NodeProperties; import net.ivoa.xml.vospace.v2.UnstructuredDataNode; import org.junit.jupiter.api.Test; import static org.mockito.ArgumentMatchers.argThat; Loading Loading @@ -272,6 +273,57 @@ public class CreateNodeControllerTest { 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 public void testSubPath() throws Exception { Loading
src/test/java/it/inaf/oats/vospace/ListNodeControllerTest.java +59 −0 Original line number Diff line number Diff line package it.inaf.oats.vospace; import static it.inaf.oats.vospace.VOSpaceXmlTestUtil.loadDocument; import it.inaf.oats.vospace.datamodel.NodeProperties; import it.inaf.oats.vospace.persistence.NodeDAO; import java.util.Optional; import net.ivoa.xml.vospace.v2.ContainerNode; import net.ivoa.xml.vospace.v2.DataNode; import net.ivoa.xml.vospace.v2.Node; import net.ivoa.xml.vospace.v2.Property; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; import static org.mockito.ArgumentMatchers.eq; Loading @@ -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.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.HttpHeaders; 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 static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; Loading @@ -25,6 +30,8 @@ import org.w3c.dom.Document; @SpringBootTest @AutoConfigureMockMvc @ContextConfiguration(classes = {TokenFilterConfig.class}) @TestPropertySource(properties = "spring.main.allow-bean-definition-overriding=true") public class ListNodeControllerTest { private static final String URI_PREFIX = "vos://example.com!vospace"; Loading Loading @@ -78,9 +85,38 @@ public class ListNodeControllerTest { .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() { ContainerNode root = new ContainerNode(); 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()); return Optional.of(root); } Loading @@ -88,6 +124,29 @@ public class ListNodeControllerTest { private Node getDataNode() { DataNode node = new DataNode(); 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; } }
src/test/resources/create-unstructured-data-node-user1.xml 0 → 100644 +11 −0 Original line number Diff line number Diff line <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
src/test/resources/create-unstructured-data-node.xml +1 −1 File changed.Contains only whitespace changes. Show changes