This is an automated email from the ASF dual-hosted git repository. coheigea pushed a commit to branch coheigea/remote-uri in repository https://gitbox.apache.org/repos/asf/ws-xmlschema.git
commit e77579e64b9df6c738d8c06f60bfb9c12f41655a Author: Colm O hEigeartaigh <[email protected]> AuthorDate: Wed Sep 16 10:49:09 2026 +0100 Updating docs for remote URI dereferencing --- README.txt | 31 +++++ SECURITY.md | 20 +++ THREAT-MODEL.md | 147 +++++++++++++++------ .../ws/commons/schema/XmlSchemaCollection.java | 44 +++++- .../schema/resolver/DefaultURIResolver.java | 14 ++ .../ws/commons/schema/resolver/URIResolver.java | 21 ++- 6 files changed, 229 insertions(+), 48 deletions(-) diff --git a/README.txt b/README.txt index f1d6559b..32e1b930 100644 --- a/README.txt +++ b/README.txt @@ -76,6 +76,37 @@ For example, set a limit with: -Dorg.apache.ws.commons.schema.maxNestingDepth=256 +=================== + Security +=================== + + XmlSchemaCollection resolves xs:import, xs:include and xs:redefine + schema locations through a URIResolver. The bundled DefaultURIResolver + is a convenience for trusted, operator-controlled schema sets. It + resolves http, https, file and jar locations and applies no host or + address filtering, so a schema location naming an internal host, a + cloud metadata endpoint, or a local file is fetched on request. + + Applications that parse schema or WSDL documents from an untrusted + source must install a restricting resolver before reading them: + + XmlSchemaCollection collection = new XmlSchemaCollection(); + collection.setSchemaResolver(myRestrictingResolver); + collection.read(source); + + A resolver that returns null declines the location, and the collection + falls back to any schema already registered for that namespace; a + resolver that throws rejects the read outright. + + Note that a host allowlist cannot be enforced from inside a URIResolver: + it returns a system ID and the JDK opens the connection, following HTTP + redirects without consulting the resolver again. A resolver that must + restrict destinations has to fetch the bytes itself and return an + InputSource wrapping the stream. + + See THREAT-MODEL.md section 10 for the full list of downstream + responsibilities. + =================== Support =================== diff --git a/SECURITY.md b/SECURITY.md index 6d484062..071e4408 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -30,3 +30,23 @@ GitHub issues or pull requests for security reports. What the project treats as in scope and out of scope, the security properties it provides and disclaims, the adversary model, and how findings are triaged are documented in [THREAT-MODEL.md](./THREAT-MODEL.md). + +## Parsing untrusted schema documents + +`XmlSchemaCollection` follows `xs:import` / `xs:include` / +`xs:redefine` schema locations through a `URIResolver`. The bundled +`DefaultURIResolver` restricts the URI schemes it will resolve, but +applies no host or address filtering, and is a convenience default for +trusted, operator-controlled schema sets. + +**An application that parses schema or WSDL documents from an untrusted +source must install a restricting resolver via +`XmlSchemaCollection.setSchemaResolver(...)` before calling `read(...)`.** +See [THREAT-MODEL.md](./THREAT-MODEL.md) section 10 for the full set of +downstream responsibilities. + +A report that the bundled default resolver dereferenced an attacker-supplied +`schemaLocation` is a documented property of that default, not a +vulnerability in the library (THREAT-MODEL.md section 9 and section 14 +Q12). A report that the resolver's scheme or base-scheme checks can be +bypassed *is* in scope, and should be reported through the process above. diff --git a/THREAT-MODEL.md b/THREAT-MODEL.md index b8c45796..b7609303 100644 --- a/THREAT-MODEL.md +++ b/THREAT-MODEL.md @@ -29,10 +29,11 @@ at clone time. A report against project release *N* should be triaged against the model as it stood at *N*, not at HEAD. Latest release documented in `RELEASE-NOTE.txt`: 2.3.0. -- **Date**: 2026-08-26. +- **Date**: 2026-09-16. - **Authors**: ASF Security team, awaiting XMLSchema / Webservices PMC review. -- **Status**: under maintainer review. +- **Status**: under maintainer review; §14 Q12 ruled (see §12 + revision log). - **Reporting**: vulnerabilities that fall under §8 (claimed properties) should be reported per `SECURITY.md` and the Apache Security Team disclosure channel (<https://www.apache.org/security/>); @@ -46,7 +47,9 @@ *(inferred)* = synthesized by the producer from code structure or domain knowledge, awaiting PMC ratification (every *(inferred)* tag has a matching §14 question). -- **Model confidence**: 22 documented / 0 maintainer / 24 inferred. +- **Model confidence**: 22 documented / 4 maintainer / 20 inferred. + The four maintainer entries are the §14 Q12 ruling and the three + statements that depended on it. XMLSchema is a Java library that parses, models, walks, and serializes W3C XML Schema documents (`.xsd` files). It is *not* a document @@ -151,7 +154,7 @@ A finding is in-model only if it reaches a row marked **yes**. | --- | --- | --- | --- | | B1 | Caller → `XmlSchemaCollection.read(InputSource | Reader | Source | Document | Element)` | none — caller is trusted | none | | B2 | `XmlSchemaCollection.read(InputSource, ...)` → hardened JDK `DocumentBuilder` | none | external DTD/entity resolution disabled unconditionally; DOCTYPE accepted | -| B3 | Schema parser → `URIResolver.resolveEntity(namespace, schemaLocation, baseUri)` | none | bundled `DefaultURIResolver` does **no host filtering**: it constructs `new URL(new URL(baseUri), schemaLocation)` and hands back an `InputSource` pointing at it | +| B3 | Schema parser → `URIResolver.resolveEntity(namespace, schemaLocation, baseUri)` | none | bundled `DefaultURIResolver` allowlists the effective scheme (`http`, `https`, `file`, `jar`, judged through any `jar:` wrapper) and refuses a location that changes the scheme of a remote base or resolves to a non-local `file:` / `jar:` authority; it does **no host filtering** on the `http(s)` targets it allows | | B4 | Resolved `InputSource` → `XmlSchemaCollection.read(InputSource, ...)` (recursive) | none | none | | B5 | `XmlSchema.write(...)` → JDK `TransformerFactory` (with `FEATURE_SECURE_PROCESSING=true` and external DTD/stylesheet access disabled where supported) | none | none | | B6 | `XmlSchemaCollection` ctor → `System.getProperty("org.apache.ws.commons.schema.extension_registry")` → `Class.forName()` | none | trusts system properties to be operator-controlled | @@ -172,8 +175,9 @@ A finding is in-model only if it reaches a row marked **yes**. - **`xmlschema-core` URI resolver** (`DefaultURIResolver`): in-model for SSRF / cross-origin fetch when the input schema is attacker- controlled and contains an `xs:import schemaLocation="…"`. The - bundled resolver constructs `new URL(...)` and returns an `InputSource`; - the JDK then fetches it on `parse()`. + bundled resolver checks the effective scheme against an allowlist and + then returns an `InputSource`; the JDK fetches it on `parse()`, and + follows any HTTP redirects itself without consulting the resolver. - **`xmlschema-core` parser fed a pre-parsed DOM** (`read(Document)`, `read(Element)`): out of model for XXE; the caller's `DocumentBuilderFactory` decided that. In-model for whatever the @@ -258,7 +262,7 @@ points*: | Knob | Default | Maintainer stance | Effect | | --- | --- | --- | --- | | `org.apache.ws.commons.schema.extension_registry` system property | unset *(documented: `XmlSchemaCollection.java` line 361)* | dev-time customization; if set by an untrusted actor the named class is loaded into the JVM | extension-registry class is `Class.forName`-loaded at `XmlSchemaCollection` ctor time | -| `XmlSchemaCollection.setSchemaResolver(URIResolver)` | `DefaultURIResolver` *(documented: `DefaultURIResolver.java`)* | **maintainer ruling required** — is the documented expectation that production deployments install a *restricted* resolver that refuses untrusted hosts (proposed: **yes, §10**), or is the default resolver supported as production-safe? *(inferred — §14 Q12)* | controls whether `xs:include`/`xs:import` may reach the network | +| `XmlSchemaCollection.setSchemaResolver(URIResolver)` | `DefaultURIResolver` *(documented: `DefaultURIResolver.java`)* | **ruled (b) — §14 Q12**: the bundled default is a convenience for trusted, operator-controlled schema sets; deployments parsing untrusted bytes are *required* to install a restricting resolver per §10 item 1 *(maintainer)* | controls whether `xs:include`/`xs:import` may reach the network | | `XmlSchemaCollection.setBaseUri(String)` | unset *(documented)* | caller-supplied | base URI against which relative `schemaLocation` values resolve | | `org.apache.ws.commons.schema.walker.maxDecisionPoints` system property | `10000` *(documented: `XmlSchemaPathFinder.java`)* | operator-tunable per-process limit | maximum decision points created while matching one document | | `org.apache.ws.commons.schema.walker.maxReplayedEvents` system property | `1000000` *(documented: `XmlSchemaPathFinder.java`)* | operator-tunable per-process limit | maximum previously traversed events replayed while backtracking through one document | @@ -269,13 +273,18 @@ points*: ### The insecure-default case -The bundled `DefaultURIResolver` **does follow remote URLs by default**. -The maintainer ruling captured in §14 Q12 will determine whether -"a schema with `<xs:import schemaLocation='http://attacker/'/>` fetched -the URL during parse" is a `VALID` report (production deployments -should be protected by the default) or an `OUT-OF-MODEL: -non-default-build` report (production deployments are *documented* as -required to install a restricting resolver per §10). +The bundled `DefaultURIResolver` **does follow remote URLs by default**, +subject only to the scheme checks described in §9. Per the §14 Q12(b) +ruling this is a documented convenience default for trusted, +operator-controlled schema sets — not a supported posture for untrusted +input. A report that "a schema with +`<xs:import schemaLocation='http://attacker/'/>` fetched the URL during +parse" is therefore `BY-DESIGN: property-disclaimed` *(maintainer)*. + +Changing that default is a compatibility break, not a patch-release +fix: ordinary schemas import `http://www.w3.org/2001/xml.xsd` and +similar by absolute URL, so a default-deny has to land in a major +release. XMLSchema's internal schema parser disables external DTD and external entity resolution. This applies both to top-level @@ -299,7 +308,7 @@ leave open. | `XmlSchemaCollection.read(Source src)` | `src` | **yes** | `SAXSource`/`StreamSource`/other route through the internal hardened factory (same as `read(InputSource)`); a `DOMSource` routes to the pre-parsed `read(Document)`/`read(Element)` path, so the upstream parser's XXE/DTD posture applies | | `XmlSchemaCollection.read(Document doc)` | `doc` | **yes if doc was parsed from untrusted bytes** | caller's `DocumentBuilderFactory` is responsible for XXE / DTD posture; XMLSchema does not re-parse | | `XmlSchemaCollection.read(Element el)` | `el` | same as `read(Document)` | same as above | -| `XmlSchemaCollection.setSchemaResolver(URIResolver)` | resolver | caller-supplied | replacing the default is the documented path for production hardening *(inferred — §14 Q12)* | +| `XmlSchemaCollection.setSchemaResolver(URIResolver)` | resolver | caller-supplied | replacing the default is the documented path for production hardening, and is required for untrusted schema bytes *(maintainer — §14 Q12)* | | `XmlSchemaCollection.setBaseUri(String)` | `baseUri` | **caller-supplied trusted string** | not validated; if attacker can set this they can pivot the import-resolver origin | | `XmlSchemaCollection.setExtReg(ExtensionRegistry)` | registry | caller-supplied | caller's choice | | `XmlSchema.write(OutputStream)` / `XmlSchema.write(Writer)` | output sink | caller-supplied | caller's choice; `FEATURE_SECURE_PROCESSING=true` is set on the internal `TransformerFactory`, with external DTD/stylesheet access disabled where supported | @@ -324,8 +333,8 @@ leave open. groups, model groups, and attribute groups. This prevents recursive stack exhaustion for malformed but parseable schemas; it is not a general limit on the size or cost of an acyclic schema. -- No rate limit on URL fetches when following `xs:import` - *(inferred — §14 Q12)*. +- No rate limit on URL fetches when following `xs:import`; bounding + fetch rate is a §10 caller responsibility *(maintainer — §14 Q12)*. - `XmlSchemaPathFinder` bounds decision points and replayed events per document by default; these limits are configurable through the `org.apache.ws.commons.schema.walker.maxDecisionPoints` and @@ -439,10 +448,18 @@ matching disclaimer. The bundled `DefaultURIResolver` constructs a `URL` from the parent schema's base URI plus the schema-location value and returns an `InputSource` pointing at it. The JDK then fetches it on parse. - XMLSchema applies *no* allowlist, *no* protocol restriction, and *no* - host filtering of any kind. The caller is responsible for installing - a restricting `URIResolver` if the input schema is attacker-controlled - *(documented: `DefaultURIResolver.java`)*. + The resolver restricts the *scheme* it will hand back — `http`, + `https`, `file` and `jar`, judged through any `jar:` wrapper — and + refuses a location that changes the scheme of a remote base or + resolves to a non-local `file:` / `jar:` authority. Within those + schemes it applies **no host or address filtering of any kind**: any + `http(s)` host is fetched on request, including loopback, link-local + (`169.254.169.254`) and RFC1918 addresses, and the JDK follows HTTP + redirects without consulting the resolver again — so a host allowlist + is not enforceable at the `resolveEntity` boundary. The caller is + responsible for installing a restricting `URIResolver` if the input + schema is attacker-controlled *(documented: `DefaultURIResolver.java`; + ratified — §14 Q12)*. - **No guarantee that external DTD or external entity content is ever resolved.** XMLSchema accepts a DOCTYPE declaration, but never fetches an external DTD subset or an external entity; a schema that depends on @@ -512,9 +529,14 @@ The embedding Java application **must**: 1. Decide whether the schema bytes being parsed are attacker-controllable. If yes, install a restricting `URIResolver` via `XmlSchemaCollection.setSchemaResolver(...)` that - refuses arbitrary `http://` / `https://` / `file://` / `jar:` / - `ftp:` URLs. The bundled `DefaultURIResolver` does not filter - *(documented: `DefaultURIResolver.java`)*. + refuses arbitrary `http://` / `https://` / `file://` / `jar:` URLs. + The bundled `DefaultURIResolver` does not filter by host + *(documented: `DefaultURIResolver.java`)*. This is a **requirement**, + not a recommendation: per the §14 Q12(b) ruling the bundled default + is not a supported production posture for untrusted schema bytes. A + resolver that returns `null` declines the location (the collection + falls back to any schema already registered for that namespace); one + that throws rejects the read outright. 2. When passing a pre-parsed `Document` / `Element` into `XmlSchemaCollection.read(...)`, use a `DocumentBuilderFactory` hardened against XXE — specifically with `disallow-doctype-decl=true` @@ -587,11 +609,13 @@ security scans. Each entry: tool symptom, why it is safe under the model, the section that licenses the call. - **"`new URL(baseUri, schemaLocation).openConnection()` — SSRF risk in - `DefaultURIResolver`."** Bundled behavior, explicitly documented as - defaulted unrestricted; operator must install a restricting resolver - per §10 item 1. → `OUT-OF-MODEL: trusted-input` *(if the maintainer - rules at Q12 that the default is dev/test)*, or `VALID-HARDENING` - *(if the maintainer rules the default is supported)*. + `DefaultURIResolver`."** Bundled behavior, disclaimed in §9 and + ratified at §14 Q12(b): the default resolver is not a production + posture for untrusted schema bytes, and the operator must install a + restricting resolver per §10 item 1. → + `BY-DESIGN: property-disclaimed`. Such a report is only `VALID` if it + defeats a restricting resolver, or bypasses the scheme and base-scheme + checks the bundled resolver *does* make (§9 first bullet). - **"`DocumentBuilderFactory.newInstance()` allows XXE in `XmlSchemaCollection`."** Current XMLSchema internal parsing disables external DTD/entity resolution. A report must show a bypass of those @@ -613,10 +637,11 @@ model, the section that licenses the call. reachable from input *(documented: `XmlSchema.java`)*. → `KNOWN-NON-FINDING`. - **"`URLConnection.getInputStream()` without timeout."** True; - XMLSchema does no read-timeout on fetched imports - *(inferred — §14 Q12)*. → `VALID-HARDENING` if Q12 rules the - default-resolver is production-safe; otherwise documented as a §10 - responsibility. + XMLSchema does no read-timeout on fetched imports *(maintainer — + §14 Q12)*. The resolver returns a system ID and the JDK opens the + connection, so a timeout cannot be imposed without changing the + resolver's contract. → `BY-DESIGN: property-disclaimed`; + connect/read timeouts are a §10 item 4 caller responsibility. - **"Path traversal via `XmlSchemaCollection.setBaseUri()`."** Caller- supplied trusted string per §6. → `OUT-OF-MODEL: trusted-input`. - **"Schemas in `w3c-testcases/` contain wide-open DTDs."** W3C @@ -650,6 +675,28 @@ Revise this document when any of the following lands: - A vulnerability report that cannot be cleanly routed to one of the §13 dispositions — evidence the model has a gap. +### Revision log + +- **2026-09-16** — the default `URIResolver` changed twice after this + model was first written, and both changes are revision triggers under + the first bullet above. "Harden default resolver" (#135) added + base-scheme and `file:` / `jar:` authority checks; "Restrict default + protocols allowed by the DefaultURIResolver" (#148) restricted the + resolver to the `http`, `https`, `file` and `jar` schemes, judged + through any `jar:` wrapper, on both the based and no-base resolution + paths. §4 B3, §4 reachability, §9 and the appendix are updated to + match; §9's earlier claim of "*no* protocol restriction" no longer + held. §14 Q12 is ruled (b) in the same pass, which resolves the + conditional dispositions in §5a and §11a to + `BY-DESIGN: property-disclaimed`. +- **2026-09-16** — "Fix up DTD handling" (#147) changed the default + parser DTD posture, a revision trigger under the second bullet above: + external DTD and external entity resolution are now disabled + unconditionally, the DOCTYPE declaration itself is accepted, and the + `org.apache.ws.commons.schema.allowDTD` property is gone. §4 B2, + §4 reachability, §5a, §9 and §10 item 3 were updated with that + change. + ## §13 Triage dispositions A report against XMLSchema receives exactly one of the following: @@ -746,19 +793,35 @@ points (proposed). *(maps to §5a)* **Q12.** **The big URI-resolver question.** The bundled `DefaultURIResolver` follows `http://` / `https://` / `file://` / -`jar:` URLs without filtering. Is this: +`jar:` URLs without host filtering. Is this: - (a) "Supported production posture" — a report that an attacker schema's `<xs:import schemaLocation='http://attacker/'/>` triggered a fetch is `VALID`? - (b) "Dev/test default; operators are documented as required to - install a restricting resolver per §10" — same report is - `OUT-OF-MODEL: non-default-build`? - -Proposed: **(b)** with a clarification in `README.txt` and/or -`SECURITY.md` that production deployments handling untrusted schema -bytes must install a restricting `URIResolver`. *(maps to §5a, §9, -§10 item 1, §11a, §13)* + install a restricting resolver per §10" — same report is not a + vulnerability in XMLSchema? + +**Ruled 2026-09-16: (b)** *(maintainer)*. The bundled resolver is a +convenience default for trusted, operator-controlled schema sets. An +application that parses schema or WSDL bytes from an untrusted source +must install a restricting `URIResolver` via +`XmlSchemaCollection.setSchemaResolver(...)` per §10 item 1; the +bundled default is not supported as a production posture for untrusted +input. A report that an untrusted `schemaLocation` was dereferenced is +`BY-DESIGN: property-disclaimed`. + +Two riders on that ruling: + +1. It does **not** license the bundled resolver to be careless within + its posture. The scheme allowlist and base-scheme / authority checks + of §9 are load-bearing, and a bypass of *those* is `VALID`. +2. The disposition is `BY-DESIGN: property-disclaimed`, not + `OUT-OF-MODEL: non-default-build`. The permissive default *is* the + default build, so the §13 "non-default-build" row never fitted; the + §9 SSRF disclaimer is the licensing text. + +*(maps to §5a, §9, §10 item 1, §11a, §13)* ### Wave 4 — adversary model, edge cases @@ -834,7 +897,7 @@ the JavaDoc / source comments. The project website is | `XmlSchemaCollection.java` | internal parser sets `FEATURE_SECURE_PROCESSING` and disables external DTD/entity resolution unconditionally; DOCTYPE declarations are accepted | §5a, §8 P2 | | `XmlSchemaCollection.java` line 745 | `AccessController.doPrivileged` wrapper for the SAX parse | §5 | | `XmlSchema.java` | serializer `TransformerFactory` sets `FEATURE_SECURE_PROCESSING` and disables external DTD/stylesheet access where supported | §5a, §8 P2 | -| `xmlschema-core/src/main/java/.../resolver/DefaultURIResolver.java` | URL composed from `baseUri` + `schemaLocation`; no filtering | §3 item 7, §9 SSRF disclaim, §10 item 1, §11 first bullet | +| `xmlschema-core/src/main/java/.../resolver/DefaultURIResolver.java` | URL composed from `baseUri` + `schemaLocation`; scheme allowlist plus base-scheme / authority checks, but no host filtering | §3 item 7, §9 SSRF disclaim, §10 item 1, §11 first bullet, §14 Q12 | | `xmlschema-core/src/main/java/.../resolver/URIResolver.java` | Resolver interface — caller-pluggable | §2 caller-roles, §10 item 1 | | `xmlschema-walker/src/main/java/.../docpath/DomBuilderFromSax.java` line 81 | `factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, TRUE)` | §5a, §8 P2 | | `xmlschema-walker/src/main/java/.../docpath/XmlSchemaPathFinder.java` | Configurable per-document limits on decision points and replayed events | §4, §5a, §6, §12 | diff --git a/xmlschema-core/src/main/java/org/apache/ws/commons/schema/XmlSchemaCollection.java b/xmlschema-core/src/main/java/org/apache/ws/commons/schema/XmlSchemaCollection.java index e27fb870..fdfdc056 100644 --- a/xmlschema-core/src/main/java/org/apache/ws/commons/schema/XmlSchemaCollection.java +++ b/xmlschema-core/src/main/java/org/apache/ws/commons/schema/XmlSchemaCollection.java @@ -65,6 +65,23 @@ import org.apache.ws.commons.schema.utils.TargetNamespaceValidator; /** * Contains a cache of XML Schema definition language (XSD). + * <p> + * When a schema read into this collection contains an <code>xs:import</code>, + * <code>xs:include</code> or <code>xs:redefine</code>, the referenced + * <code>schemaLocation</code> is dereferenced through the collection's + * {@link URIResolver}. The default is {@link DefaultURIResolver}, which resolves + * <code>http</code>, <code>https</code>, <code>file</code> and <code>jar</code> locations and + * applies no host or address filtering. It is a convenience for trusted, + * operator-controlled schema sets. + * </p> + * <p> + * <strong>An application that reads schema or WSDL documents from an untrusted source must + * install a restricting resolver with {@link #setSchemaResolver(URIResolver)} before calling + * any <code>read</code> method.</strong> Otherwise a schema location chosen by the document's + * author is fetched by this JVM, which may reach internal hosts or read local files. See + * <code>THREAT-MODEL.md</code> section 10 in the project sources for the full set of caller + * responsibilities. + * </p> */ public final class XmlSchemaCollection { @@ -249,7 +266,8 @@ public final class XmlSchemaCollection { /** * Retrieve the custom URI resolver, if any. * - * @return the current resolver. + * @return the current resolver; a {@link DefaultURIResolver} unless + * {@link #setSchemaResolver(URIResolver)} has replaced it. */ public URIResolver getSchemaResolver() { return schemaResolver; @@ -619,6 +637,13 @@ public final class XmlSchemaCollection { * in the concatenation of system ID and targetNamespace. In this API, the systemID is taken from the * source. * + * <p> + * Any <code>xs:import</code> / <code>xs:include</code> / <code>xs:redefine</code> in the + * document has its <code>schemaLocation</code> dereferenced during this call, through the + * resolver returned by {@link #getSchemaResolver()}. Install a restricting resolver with + * {@link #setSchemaResolver(URIResolver)} first when the document is untrusted. + * </p> + * * @param inputSource the XSD document. * @return the XML schema object. */ @@ -722,7 +747,22 @@ public final class XmlSchemaCollection { } /** - * Register a custom URI resolver + * Register a custom URI resolver, replacing the {@link DefaultURIResolver} that is installed + * by default. + * <p> + * This is the control point for <code>xs:import</code> / <code>xs:include</code> / + * <code>xs:redefine</code> resolution. Installing a restricting resolver here is + * <strong>required</strong> before reading schema documents that come from an untrusted + * source. A resolver that returns <code>null</code> declines the location, in which case the + * collection falls back to any schema already registered for that namespace; a resolver that + * throws rejects the read outright. + * </p> + * <p> + * Note that a resolver cannot enforce a host allowlist by inspecting the location alone: it + * returns a system ID and the JDK opens the connection, following HTTP redirects without + * consulting the resolver again. A resolver that has to restrict destinations must fetch the + * bytes itself and return an <code>InputSource</code> wrapping the stream. + * </p> * * @param schemaResolver resolver */ 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 cc6e8bb3..561a268f 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 @@ -35,6 +35,16 @@ import org.xml.sax.InputSource; /** * This resolver provides the means of resolving the imports and includes of a given schema document. The * system will call this default resolver if there is no other resolver present in the system. + * <p> + * This resolver is a convenience for trusted, operator-controlled schema sets. It restricts the URI + * schemes it will resolve to <code>http</code>, <code>https</code>, <code>file</code> and + * <code>jar</code>, and refuses a schema location that changes the scheme of a remote base URI or + * resolves to a non-local <code>file:</code> / <code>jar:</code> authority. Within those schemes it + * applies no host or address filtering, so any reachable host or readable file a schema location + * names is fetched. An application that parses untrusted schema documents must install a restricting + * resolver instead; see + * {@link org.apache.ws.commons.schema.XmlSchemaCollection#setSchemaResolver(URIResolver)}. + * </p> */ public class DefaultURIResolver implements CollectionURIResolver { @@ -54,6 +64,10 @@ public class DefaultURIResolver implements CollectionURIResolver { * @param namespace target namespace. * @param schemaLocation system ID. * @param baseUri base URI for the schema. + * @return an input source for the resolved location, or <code>null</code> if the location + * cannot be resolved against the given base. + * @throws XmlSchemaException if the location resolves to a URI scheme this resolver does not + * permit, or escapes the scheme or authority of its base URI. */ public InputSource resolveEntity(String namespace, String schemaLocation, String baseUri) { diff --git a/xmlschema-core/src/main/java/org/apache/ws/commons/schema/resolver/URIResolver.java b/xmlschema-core/src/main/java/org/apache/ws/commons/schema/resolver/URIResolver.java index 0afcb5a4..99284be5 100644 --- a/xmlschema-core/src/main/java/org/apache/ws/commons/schema/resolver/URIResolver.java +++ b/xmlschema-core/src/main/java/org/apache/ws/commons/schema/resolver/URIResolver.java @@ -20,13 +20,26 @@ package org.apache.ws.commons.schema.resolver; import org.xml.sax.InputSource; +/** + * Resolves the <code>schemaLocation</code> of an <code>xs:import</code>, + * <code>xs:include</code> or <code>xs:redefine</code> to the document it names. + * <p> + * An implementation of this interface decides what a schema document is allowed to pull in, so it + * is the control point for applications that parse untrusted schema documents: install one that + * refuses locations outside an approved set, via + * {@link org.apache.ws.commons.schema.XmlSchemaCollection#setSchemaResolver(URIResolver)}. + * </p> + */ public interface URIResolver { /** - * Resolves an interface + * Resolve a schema location to the document it names. * - * @param targetNamespace - * @param schemaLocation - * @param baseUri + * @param targetNamespace the target namespace of the referenced schema, as declared by the + * referring document. + * @param schemaLocation the schema location to resolve. + * @param baseUri the base URI of the referring document, or <code>null</code> if it has none. + * @return an input source for the referenced document, or <code>null</code> to decline the + * location. */ InputSource resolveEntity(String targetNamespace, String schemaLocation, String baseUri);
