Newer
Older
package it.inaf.oats.vospace.datamodel;
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;
import net.ivoa.xml.vospace.v2.Node;
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))
.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("[/]+");
if (pathComponents.length == 0) {
// 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;
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
}
public static boolean checkIfReadable(Node myNode, String userName, List<String> userGroups) {
if ("true".equals(NodeProperties.getNodePropertyByURI(myNode, NodeProperties.PUBLIC_READ_URI))) {
return true;
}
String creator = NodeProperties.getNodePropertyByURI(myNode, NodeProperties.CREATOR_URI);
if (creator != null && creator.equals(userName)) {
return true;
}
if (userGroups == null || userGroups.isEmpty()) {
return false;
}
List<String> groupReadValues = NodeProperties.getNodePropertyAsListByURI(myNode, NodeProperties.GROUP_READ_URI);
if (groupReadValues == null) {
return false;
}
for (String group : groupReadValues) {
if (userGroups.contains(group)) {
return true;
}
}
return false;
public static boolean checkIfWritable(Node myNode, String userName, List<String> userGroups) {
// 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;
}
List<String> groupWritePropValues
= NodeProperties.getNodePropertyAsListByURI(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;
}
}
return true;
}
}