SLING-7814 - URLs with JCR namespaces can get double encoded by XSSAPI.getValidHref
* decode the potentially encoded mangledPath before reconstructing the URI
diff --git a/src/main/java/org/apache/sling/xss/impl/XSSAPIImpl.java b/src/main/java/org/apache/sling/xss/impl/XSSAPIImpl.java
index 546eb0c..e9d8afc 100644
--- a/src/main/java/org/apache/sling/xss/impl/XSSAPIImpl.java
+++ b/src/main/java/org/apache/sling/xss/impl/XSSAPIImpl.java
@@ -19,7 +19,7 @@
import java.io.StringReader;
import java.io.StringWriter;
import java.net.URI;
-import java.net.URISyntaxException;
+import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
@@ -202,28 +202,25 @@
}
}
if (mangledPath != null) {
- try {
- URI mangledURI = new URI(uri.getScheme(), uri.getUserInfo(), uri.getHost(), uri.getPort(), mangledPath,
- uri.getRawQuery(), uri.getRawFragment());
- StringBuilder uriBuilder = new StringBuilder();
- if (StringUtils.isNotEmpty(mangledURI.getScheme()) && StringUtils.isNotEmpty(mangledURI.getAuthority())) {
- uriBuilder.append(mangledURI.getScheme()).append("://").append(mangledURI.getRawAuthority());
- }
- if (StringUtils.isNotEmpty(mangledURI.getPath())) {
- uriBuilder.append(mangledURI.getRawPath());
- }
- if (StringUtils.isNotEmpty(mangledURI.getQuery())) {
- uriBuilder.append("?").append(mangledURI.getRawQuery());
- }
- if (StringUtils.isNotEmpty(mangledURI.getFragment())) {
- uriBuilder.append("#").append(mangledURI.getRawFragment());
- }
- return uriBuilder.toString();
- } catch (URISyntaxException e) {
- LOGGER.warn("Invalid URI.", e);
+ URI mangledURI = new URI(uri.getScheme(), uri.getUserInfo(), uri.getHost(), uri.getPort(),
+ URLDecoder.decode(mangledPath, "UTF-8"),
+ uri.getRawQuery(), uri.getRawFragment());
+ StringBuilder uriBuilder = new StringBuilder();
+ if (StringUtils.isNotEmpty(mangledURI.getScheme()) && StringUtils.isNotEmpty(mangledURI.getAuthority())) {
+ uriBuilder.append(mangledURI.getScheme()).append("://").append(mangledURI.getRawAuthority());
}
+ if (StringUtils.isNotEmpty(mangledURI.getPath())) {
+ uriBuilder.append(mangledURI.getRawPath());
+ }
+ if (StringUtils.isNotEmpty(mangledURI.getQuery())) {
+ uriBuilder.append("?").append(mangledURI.getRawQuery());
+ }
+ if (StringUtils.isNotEmpty(mangledURI.getFragment())) {
+ uriBuilder.append("#").append(mangledURI.getRawFragment());
+ }
+ return uriBuilder.toString();
}
- } catch (URISyntaxException e) {
+ } catch (Exception e) {
LOGGER.warn("Invalid URI.", e);
}
return absPath;
diff --git a/src/test/java/org/apache/sling/xss/impl/XSSAPIImplTest.java b/src/test/java/org/apache/sling/xss/impl/XSSAPIImplTest.java
index 76c302d..5d1737b 100644
--- a/src/test/java/org/apache/sling/xss/impl/XSSAPIImplTest.java
+++ b/src/test/java/org/apache/sling/xss/impl/XSSAPIImplTest.java
@@ -235,6 +235,8 @@
// JCR namespaces:
{"my/page/jcr:content.feed", "my/page/_jcr_content.feed"},
{"my/jcr:content/page/jcr:content", "my/_jcr_content/page/_jcr_content"},
+ {"my/jcr:content/encoded%20spaces", "my/_jcr_content/encoded%20spaces"},
+ {"my/jcr:content/this path has spaces", "my/_jcr_content/this%20path%20has%20spaces"},
{"\" onClick=ugly", "%22%20onClick=ugly"},
{"javascript:ugly", ""},
@@ -272,6 +274,14 @@
"/test/jcr:content/search.html?0_tag:id=test",
"/test/_jcr_content/search.html?0_tag:id=test"
},
+ { // JCR namespaces and colons in query string plus encoded path
+ "/test%20with%20encoded%20spaces/jcr:content/search.html?0_tag:id=test",
+ "/test%20with%20encoded%20spaces/_jcr_content/search.html?0_tag:id=test"
+ },
+ { // JCR namespaces and colons in query string plus spaces in path
+ "/test with spaces/jcr:content/search.html?0_tag:id=test",
+ "/test%20with%20spaces/_jcr_content/search.html?0_tag:id=test"
+ },
{ // ? in query string
"/test/search.html?0_tag:id=test?ing&1_tag:id=abc",
"/test/search.html?0_tag:id=test?ing&1_tag:id=abc",