This is an automated email from the ASF dual-hosted git repository.
coheigea pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ws-xmlschema.git
The following commit(s) were added to refs/heads/master by this push:
new 5c9ad53c More DefaultURIResolver hardening
5c9ad53c is described below
commit 5c9ad53c9b2f9bc1758502ae66c1fa1023d3cd8d
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Wed Sep 16 13:57:46 2026 +0100
More DefaultURIResolver hardening
---
.../schema/resolver/DefaultURIResolver.java | 10 ++++-
.../test/java/tests/DefaultURIResolverTest.java | 47 ++++++++++++++++++++++
2 files changed, 56 insertions(+), 1 deletion(-)
diff --git
a/xmlschema-core/src/main/java/org/apache/ws/commons/schema/resolver/DefaultURIResolver.java
b/xmlschema-core/src/main/java/org/apache/ws/commons/schema/resolver/DefaultURIResolver.java
index 347b2653..5a645cf9 100644
---
a/xmlschema-core/src/main/java/org/apache/ws/commons/schema/resolver/DefaultURIResolver.java
+++
b/xmlschema-core/src/main/java/org/apache/ws/commons/schema/resolver/DefaultURIResolver.java
@@ -108,7 +108,10 @@ public class DefaultURIResolver implements
CollectionURIResolver {
}
}
- if (isAbsoluteUri(schemaLocation)) {
+ // A location carrying a scheme is checked even when java.net.URI will
not parse it.
+ // URI is stricter than the java.net.URL the parser goes on to build,
so a location URI
+ // rejects is not thereby harmless.
+ if (isAbsoluteUri(schemaLocation) || extractScheme(schemaLocation) !=
null) {
verifyPermittedLocation(schemaLocation, schemaLocation);
return new InputSource(schemaLocation);
}
@@ -165,6 +168,11 @@ public class DefaultURIResolver implements
CollectionURIResolver {
}
final String trimmed = uri.trim();
final boolean wrapped = "jar".equals(extractScheme(trimmed));
+ if (wrapped && extractScheme(trimmed.substring(4)) == null) {
+ throw new XmlSchemaException("The schema location \"" +
schemaLocation
+ + "\" is a jar: URL whose archive
names no scheme this"
+ + " resolver recognises.");
+ }
// A jar: URL delegates to the URL of the archive; the entry after
"!/" is inside it.
final String archive = wrapped ? stripJarEntry(trimmed.substring(4)) :
trimmed;
if (wrapped && isNetworkScheme(scheme)) {
diff --git a/xmlschema-core/src/test/java/tests/DefaultURIResolverTest.java
b/xmlschema-core/src/test/java/tests/DefaultURIResolverTest.java
index 0144066e..4e394092 100644
--- a/xmlschema-core/src/test/java/tests/DefaultURIResolverTest.java
+++ b/xmlschema-core/src/test/java/tests/DefaultURIResolverTest.java
@@ -247,4 +247,51 @@ public class DefaultURIResolverTest extends Assert {
// The same shape reached by composing a relative location against a
local base.
assertSchemeRefused("////attacker.example/share/x.xsd", localBase(),
"non-local authority");
}
+
+ @Test
+ public void testSchemeCheckSurvivesALocationUriCannotParse() {
+ // java.net.URI rejects a space, so isAbsoluteUri() said "not
absolute" and the location
+ // fell through to the relative-path branch, which returned it
unchecked. java.net.URL is
+ // laxer, so the parser still fetched it: a space was enough to defeat
the scheme allowlist.
+ assertSchemeRefused("ftp://attacker.example/a b.xsd", null);
+ assertSchemeRefused("mailto:[email protected]?x= y", null);
+ assertSchemeRefused("jrt:/java.base/a b", null);
+ }
+
+ @Test
+ public void testUnparseableFileLocationIsRefused() {
+ DefaultURIResolver resolver = new DefaultURIResolver();
+ try {
+ resolver.resolveEntity("urn:x",
"file:///\\\\attacker.example\\share\\x.xsd", null);
+ fail("A file: location that will not parse as a URI must be
refused.");
+ } catch (XmlSchemaException expected) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testJarWrappingAnUnrecognisedSchemeIsRefused() {
+ assertSchemeRefused("jar:fi%6Ce://attacker.example/a.jar!/x.xsd",
null, "names no scheme");
+ // Against a base the URL parser rejects the unknown nested protocol
before this check,
+ // so only require that it is refused.
+ DefaultURIResolver resolver = new DefaultURIResolver();
+ try {
+ resolver.resolveEntity("urn:x",
"jar:fi%6Ce://attacker.example/a.jar!/x.xsd",
+ localBase());
+ fail("A jar: URL wrapping an unrecognised scheme must be
refused.");
+ } catch (XmlSchemaException expected) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testRelativeLocationsAreStillNotSchemeChecked() {
+ DefaultURIResolver resolver = new DefaultURIResolver();
+
+ // No scheme: extractScheme() returns null for a colon that follows a
path separator, so
+ // these stay plain relative paths.
+ assertEquals("sub/x.xsd", resolver.resolveEntity("urn:x", "sub/x.xsd",
null).getSystemId());
+ assertEquals("dir/a:b.xsd",
+ resolver.resolveEntity("urn:x", "dir/a:b.xsd",
null).getSystemId());
+ }
}