diff --git a/src/main/java/it/inaf/oats/vospace/datamodel/NodeProperties.java b/src/main/java/it/inaf/oats/vospace/datamodel/NodeProperties.java
new file mode 100644
index 0000000000000000000000000000000000000000..c704b4ae9582aebe77a7afa8f79471b61f83b2de
--- /dev/null
+++ b/src/main/java/it/inaf/oats/vospace/datamodel/NodeProperties.java
@@ -0,0 +1,74 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package it.inaf.oats.vospace.datamodel;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import net.ivoa.xml.vospace.v2.Node;
+
+/**
+ *
+ * @author bertocco
+ */
+public class NodeProperties {
+    
+    
+    private NodeProperties() { }
+    
+    public static final String AVAILABLE_SPACE_URI = "ivo://ivoa.net/vospace/core#availableSpace";      // the amount of space available within a container      
+    public static final String INITIAL_CREATION_TIME_URI  = "ivo://ivoa.net/vospace/core#btime";       // the initial creation time
+    public static final String CONTRIBUTOR_URI  = "ivo://ivoa.net/vospace/core#contributor"; // an entity responsible for making contributions to this resource
+    public static final String COVERAGE_URI  = "ivo://ivoa.net/vospace/core#coverage";    // a spatial or temporal topic of the resource, the spatial applicability of the resource, or the jurisdiction under which the resource is relevant      
+    public static final String CREATOR_URI  = "ivo://ivoa.net/vospace/core#creator";     // an entity primarily responsible for making the resource
+    public static final String STATUS_CHANGE_TIME_URI  = "ivo://ivoa.net/vospace/core#ctime";       // the status change (aka metadata modification) time    
+    public static final String DATE_URI  = "ivo://ivoa.net/vospace/core#date";        // a point or period of time associated with an event in the lifecycle of the resource
+    public static final String DESCRIPTION_URI  = "ivo://ivoa.net/vospace/core#description"; // an account of the resource    
+    public static final String FORMAT_URI  = "ivo://ivoa.net/vospace/core#format";      // the file format, physical medium or dimensions of the resource
+    public static final String GROUP_READ_URI  = "ivo://ivoa.net/vospace/core#groupread";   // the list of groups which can only read this resource  delimiter-separated 
+    public static final String GROUP_WRITE_URI  = "ivo://ivoa.net/vospace/core#groupwrite";  // the list of groups which can read and write to this resource  delimiter-separated 
+    public static final String IDENTIFIER_URI  = "ivo://ivoa.net/vospace/core#identifier";  // an unambiguous reference to the resource within a given context
+    public static final String LANGUAGE_URI  = "ivo://ivoa.net/vospace/core#language";    // a language of the resource    
+    public static final String CORE_URI  = "ivo://ivoa.net/vospace/core#length";      // the length or size of a resource      
+    public static final String MODIFICATION_TIME_URI  = "ivo://ivoa.net/vospace/core#mtime";       // the data modification time    
+    public static final String PUBLIC_READ_URI  = "ivo://ivoa.net/vospace/core#publicread";  // whether this resource is world readable
+    public static final String PUBLISHER_URI  = "ivo://ivoa.net/vospace/core#publisher";   // an entity responsible for making the resource available
+    public static final String QUOTA_URI  = "ivo://ivoa.net/vospace/core#quota";       // the value of a system quota on the resource   
+    public static final String RELATED_RESOURCE_URI  = "ivo://ivoa.net/vospace/core#relation";    // a related resource    
+    public static final String RIGHTS_ON_URI  = "ivo://ivoa.net/vospace/core#rights";      // information about rights held in and over the resource
+    public static final String RESOURCE_RELATED_URI  = "ivo://ivoa.net/vospace/core#source";      // a related resource from which the described resource is derived
+    public static final String SUBJECT_URI  = "ivo://ivoa.net/vospace/core#subject";     // the topic of the resource     
+    public static final String TITLE_URI  = "ivo://ivoa.net/vospace/core#title";       // a name given to the resource  
+    public static final String TYPE_URI  = "ivo://ivoa.net/vospace/core#type";        // the nature or genre of the resource
+
+
+    // Returns all properties stored inside the node under the requested
+    // property URI.    
+    public static List<String> getNodePropertyByURI(Node node, String propertyURI) {
+
+        List<String> propertyList = node.getProperties().stream()
+                .filter((i) -> i.getUri()
+                .equals(propertyURI))
+                .map((i) -> i.getValue())
+                .collect(Collectors.toList());
+
+        return propertyList;
+    }
+
+    public static List<String> parsePropertyStringToList(String property) {
+        // If separator changes, this method should remain consistent
+        // For now it assumes that " " is the separator        
+        String separator = " ";
+
+        String trimmedProperty = property.trim();
+        if (trimmedProperty.isEmpty()) {
+            return List.of();
+        }
+
+        return List.of(trimmedProperty.split(separator));
+
+    }
+    
+}
diff --git a/src/main/java/it/inaf/oats/vospace/datamodel/NodeUtils.java b/src/main/java/it/inaf/oats/vospace/datamodel/NodeUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..853afb8cd3ffeb6fd266e8ef3638d5ca05c8dd8d
--- /dev/null
+++ b/src/main/java/it/inaf/oats/vospace/datamodel/NodeUtils.java
@@ -0,0 +1,132 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package it.inaf.oats.vospace.datamodel;
+
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.List;
+import net.ivoa.xml.vospace.v2.Node;
+
+
+public class NodeUtils {
+ 
+    
+    
+    /**
+     * Slash is a special character in defining REST endpoints and trying to
+     * define a PathVariable containing slashes doesn't work, so the endpoint
+     * has been defined using "/nodes/**" instead of "/nodes/{path}" and the
+     * path is extracted manually parsing the request URL.
+     */
+    public static String getPathFromRequestURLString(String requestUrlString ) {
+        
+        String[] split = requestUrlString.split("/nodes/");
+
+        String path = "/";
+        if (split.length == 2) {
+            path += split[1];
+        }
+        return path;
+    }
+    
+    // This method assumes that URL is in the format /node1/node2/...
+    // multiple slashes as a single separator are allowed
+    // But the output has only single slash separators
+    public static String getParentPath(String path) {
+
+        String[] parsedPath = path.split("[/]+");
+
+        if (parsedPath.length < 2 || !parsedPath[0].isEmpty()) {
+            throw new IllegalArgumentException();
+        }
+
+        StringBuilder sb = new StringBuilder();
+        sb.append("/");
+
+        for (int i = 1; i < parsedPath.length - 1; i++) {
+            sb.append(parsedPath[i]);
+            if (i < parsedPath.length - 2) {
+                sb.append("/");
+            }
+        }
+
+        return sb.toString();
+    }
+    
+    
+    public static List<String> subPathComponents(String path) {
+        
+        List resultList = new ArrayList<String>();
+        
+        String[] pathComponents = path.split("[/]+");
+        
+        if (pathComponents.length == 0) { 
+                       
+            // Manage root node
+            resultList.add("/");
+            
+        } else {
+            
+            // Manage all precursors in full path
+            String parentPath="/";
+            for (int i = 1; i < pathComponents.length; i++) { 
+                parentPath = parentPath + pathComponents[i] + "/";
+                // "I'm managing path = " + parentPath.substring(0, parentPath.length()-1));
+                resultList.add(parentPath.substring(0, parentPath.length()-1));
+                            
+            }
+                    
+        }
+        
+        return resultList;
+        
+    }
+    
+    public static boolean checkIfWritable(Node myNode, String userName, List<String> userGroups) {
+        
+        List<String> nodeOwner
+                = NodeProperties.getNodePropertyByURI(myNode, NodeProperties.CREATOR_URI);
+                //= getNodePropertyByURI(
+                //        toBeDeletedNode, "ivo://ivoa.net/vospace/core#creator");
+        
+        
+        if (nodeOwner == null
+                || nodeOwner.isEmpty()
+                || !nodeOwner.get(0).equals(userName)) {
+            // Node owner check has failed: let's check if user can write
+            // due to group privileges
+
+            // If the user doesn't belong to any groups throw exception
+            if (userGroups == null || userGroups.isEmpty()) {
+                return false;
+            }
+
+            List<String> groupWritePropValues
+                    = NodeProperties.getNodePropertyByURI(myNode,
+                            NodeProperties.GROUP_WRITE_URI);
+
+            // If groupwrite property is absent in Parent Node throw exception
+            if (groupWritePropValues == null
+                    || groupWritePropValues.isEmpty()) {
+                return false;                
+            }
+
+            List<String> nodeGroups
+                    = NodeProperties.parsePropertyStringToList(groupWritePropValues.get(0));
+
+            if (nodeGroups.isEmpty()
+                    || !nodeGroups.stream()
+                            .anyMatch((i) -> userGroups.contains(i))) {
+                return false;
+            }
+
+        }
+
+        // DUPLICATED code from CreateNodeController - END
+        return true;
+    }
+    
+}