Newer
Older
package it.inaf.oats.vospace.datamodel;
import net.ivoa.xml.vospace.v2.Node;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class NodeUtils {
/**
* Forbidden path chars are non printable characters and some symbols that
* could create issues to scripts that manipulates files. Other UTF-8
* characters are allowed. Front end needs to pay attention to other allowed
* characters like & and parenthesis in any case, also to avoid XSS attacks.
*/
private static final Pattern FORBIDDEN_CHARS = Pattern.compile("[\\x00\\x08\\x0B\\x0C\\x0E-\\x1F" + Pattern.quote("<>?\":\\|/'`*") + "]");
/**
* 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. Proper URL encoding
* handling is needed, considering also that slashes mustn't be escaped.
public static String getPathFromRequestURLString(String requestUrlString) {
return getPathFromRequestURLString(requestUrlString, "/nodes/");
}
public static String getPathFromRequestURLString(String requestUrlString, String prefix) {
String[] split = requestUrlString.split(prefix);
String path = "/";
if (split.length == 2) {
String[] parts = split[1].split("/");
path += String.join("/", Arrays.stream(parts)
.map(p -> {
String decoded = URLDecoder.decode(p, StandardCharsets.UTF_8);
if (FORBIDDEN_CHARS.matcher(decoded).find()) {
throw new IllegalArgumentException("Path segment " + decoded + " contains an illegal character");
}
return decoded;
})
.collect(Collectors.toList()));
}
return path;
}
public static String urlEncodePath(String path) {
String[] parts = path.split("/");
return String.join("/", Arrays.stream(parts)
.map(p -> URLEncoder.encode(p, StandardCharsets.UTF_8).replace("+", "%20"))
.collect(Collectors.toList()));
}
// 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("[/]+");
// Manage root node
resultList.add("/");
// 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) {
return checkAccessPropery(myNode, userName, userGroups, NodeProperties.GROUP_WRITE_URI);
public static boolean checkIfRedeable(Node myNode, String userName, List<String> userGroups) {
return checkAccessPropery(myNode, userName, userGroups, NodeProperties.GROUP_READ_URI);
public static boolean checkAccessPropery(Node myNode, String userName,
List<String> userGroups, String accessPropertyName) {
// First check if parent node creator is == userid
List<String> nodeOwner
= NodeProperties.getNodePropertyAsListByURI(myNode, NodeProperties.CREATOR_URI);
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;
}
= NodeProperties.getNodePropertyAsListByURI(myNode,
// If groupwrite property is absent in Parent Node throw exception
if (groupAccessPropValues == null
|| groupAccessPropValues.isEmpty()) {
}
List<String> nodeGroups
= NodeProperties.parsePropertyStringToList(groupAccessPropValues.get(0));
if (nodeGroups.isEmpty()
|| !nodeGroups.stream()
.anyMatch((i) -> userGroups.contains(i))) {
return false;
}
}
return true;