Commit a9ec1449 authored by Sonia Zorba's avatar Sonia Zorba
Browse files

Handled special characters and illegal characters on node paths

parent 5a20bd0a
Pipeline #1009 passed with stages
in 50 seconds
package it.inaf.oats.vospace.datamodel; 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.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import net.ivoa.xml.vospace.v2.Node; import net.ivoa.xml.vospace.v2.Node;
public class NodeUtils { 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 * Slash is a special character in defining REST endpoints and trying to
* define a PathVariable containing slashes doesn't work, so the endpoint * define a PathVariable containing slashes doesn't work, so the endpoint
* has been defined using "/nodes/**" instead of "/nodes/{path}" and the * has been defined using "/nodes/**" instead of "/nodes/{path}" and the
* path is extracted manually parsing the request URL. * 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) { public static String getPathFromRequestURLString(String requestUrlString) {
return getPathFromRequestURLString(requestUrlString, "/nodes/");
}
String[] split = requestUrlString.split("/nodes/"); public static String getPathFromRequestURLString(String requestUrlString, String prefix) {
String[] split = requestUrlString.split(prefix);
String path = "/"; String path = "/";
if (split.length == 2) { if (split.length == 2) {
path += split[1]; 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; 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/... // This method assumes that URL is in the format /node1/node2/...
// multiple slashes as a single separator are allowed // multiple slashes as a single separator are allowed
// But the output has only single slash separators // But the output has only single slash separators
......
package it.inaf.oats.vospace.datamodel;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
public class NodeUtilsTest {
@Test
public void testGetPathFromRequestURLString() {
String requestUrl = "http://localhost/vospace/nodes/a/b/c/";
assertEquals("/a/b/c", NodeUtils.getPathFromRequestURLString(requestUrl));
}
@Test
public void testGetPathWithSpacesFromRequestURLString() {
String requestUrl = "http://localhost/vospace/nodes/a/b/c%20d%20%C3%A4.pdf";
assertEquals("/a/b/c d ä.pdf", NodeUtils.getPathFromRequestURLString(requestUrl));
}
@Test
public void testEncodePathSpecialChars() {
String specialChars = "ä è#+ /other/+-ò@";
assertEquals("%C3%A4+%C3%A8%23%2B+/other/%2B-%C3%B2%40", NodeUtils.urlEncodePath(specialChars));
}
@Test
public void testIllegalBrakets() {
testIllegalChars("<no>.pdf");
}
@Test
public void testIllegalQuestionMark() {
testIllegalChars("???.pdf");
}
@Test
public void testIllegalQuotes() {
testIllegalChars("\"'.pdf");
}
private void testIllegalChars(String illegalString) {
boolean exception = false;
try {
NodeUtils.getPathFromRequestURLString("http://localhost/vospace/nodes/path/to/" + illegalString);
} catch (IllegalArgumentException ex) {
exception = true;
}
assertTrue(exception);
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment