From f01cb5a7182a8588af16363b52e5c7a065a6e5b6 Mon Sep 17 00:00:00 2001 From: IvanM Date: Tue, 19 May 2026 18:09:54 +0300 Subject: [PATCH 1/2] Resolve WSDL schema imports offline via jax-ws-catalog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit wsdl/WinRM.wsdl references three schemas by absolute URL: - http://schemas.dmtf.org/wbem/wsman/1/dsp8033_1.0.xsd - http://schemas.dmtf.org/wbem/wsman/1/dsp8034_1.0.xsd - http://www.w3.org/2001/xml.xsd Apache CXF fetches each over HTTP at every WinRMService.createInstance() call. On offline / air-gapped / restricted-egress hosts the connect() attempt blocks ~75 s per missing schema (OS TCP timeout) and finally throws: javax.wsdl.WSDLException (at /wsdl:definitions/wsdl:types/xs:schema[1]): faultCode=PARSER_ERROR: Problem parsing 'http://schemas.dmtf.org/wbem/wsman/1/dsp8034_1.0.xsd'.: java.net.ConnectException: Connection timed out dsp8034_1.0.xsd is also transitively imported by the bundled xsd/dsp8033_1.0.xsd, so even when dsp8033 resolves locally a network fetch of dsp8034 is still required without this catalog. Fix: - Ship the three missing schemas under src/main/resources/xsd/. - Add META-INF/jax-ws-catalog.xml — auto-discovered by CXF's OASISCatalogManager — mapping all four absolute URLs (dsp8033, dsp8034, xml.xsd, ws-addr.xsd) to the local classpath copies. - Add CatalogResolutionTest verifying OASISCatalogManager returns a non-network URI for each systemId. After this change WinRMService initialization performs no outbound HTTP to schemas.dmtf.org or www.w3.org, eliminating the offline-fetch timeout and removing a silent runtime dependency on DMTF / W3C servers for every WinRM session. --- .../resources/META-INF/jax-ws-catalog.xml | 30 ++ src/main/resources/xsd/dsp8034_1.0.xsd | 165 ++++++++++ src/main/resources/xsd/ws-addr.xsd | 137 +++++++++ src/main/resources/xsd/xml.xsd | 287 ++++++++++++++++++ .../winrm/CatalogResolutionTest.java | 51 ++++ 5 files changed, 670 insertions(+) create mode 100644 src/main/resources/META-INF/jax-ws-catalog.xml create mode 100644 src/main/resources/xsd/dsp8034_1.0.xsd create mode 100644 src/main/resources/xsd/ws-addr.xsd create mode 100644 src/main/resources/xsd/xml.xsd create mode 100644 src/test/java/org/metricshub/winrm/CatalogResolutionTest.java diff --git a/src/main/resources/META-INF/jax-ws-catalog.xml b/src/main/resources/META-INF/jax-ws-catalog.xml new file mode 100644 index 0000000..9a15209 --- /dev/null +++ b/src/main/resources/META-INF/jax-ws-catalog.xml @@ -0,0 +1,30 @@ + + + + + + + + diff --git a/src/main/resources/xsd/dsp8034_1.0.xsd b/src/main/resources/xsd/dsp8034_1.0.xsd new file mode 100644 index 0000000..5b4dca1 --- /dev/null +++ b/src/main/resources/xsd/dsp8034_1.0.xsd @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + If "Policy" elements from namespace + "http://schemas.xmlsoap.org/ws/2002/12/policy#policy" are used, + they must appear first (before any extensibility elements). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/xsd/ws-addr.xsd b/src/main/resources/xsd/ws-addr.xsd new file mode 100644 index 0000000..47362ed --- /dev/null +++ b/src/main/resources/xsd/ws-addr.xsd @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/xsd/xml.xsd b/src/main/resources/xsd/xml.xsd new file mode 100644 index 0000000..aea7d0d --- /dev/null +++ b/src/main/resources/xsd/xml.xsd @@ -0,0 +1,287 @@ + + + + + + +
+

About the XML namespace

+ +
+

+ This schema document describes the XML namespace, in a form + suitable for import by other schema documents. +

+

+ See + http://www.w3.org/XML/1998/namespace.html and + + http://www.w3.org/TR/REC-xml for information + about this namespace. +

+

+ Note that local names in this namespace are intended to be + defined only by the World Wide Web Consortium or its subgroups. + The names currently defined in this namespace are listed below. + They should not be used with conflicting semantics by any Working + Group, specification, or document instance. +

+

+ See further below in this document for more information about how to refer to this schema document from your own + XSD schema documents and about the + namespace-versioning policy governing this schema document. +

+
+
+
+
+ + + + +
+ +

lang (as an attribute name)

+

+ denotes an attribute whose value + is a language code for the natural language of the content of + any element; its value is inherited. This name is reserved + by virtue of its definition in the XML specification.

+ +
+
+

Notes

+

+ Attempting to install the relevant ISO 2- and 3-letter + codes as the enumerated possible values is probably never + going to be a realistic possibility. +

+

+ See BCP 47 at + http://www.rfc-editor.org/rfc/bcp/bcp47.txt + and the IANA language subtag registry at + + http://www.iana.org/assignments/language-subtag-registry + for further information. +

+

+ The union allows for the 'un-declaration' of xml:lang with + the empty string. +

+
+
+
+ + + + + + + + + +
+ + + + +
+ +

space (as an attribute name)

+

+ denotes an attribute whose + value is a keyword indicating what whitespace processing + discipline is intended for the content of the element; its + value is inherited. This name is reserved by virtue of its + definition in the XML specification.

+ +
+
+
+ + + + + + +
+ + + +
+ +

base (as an attribute name)

+

+ denotes an attribute whose value + provides a URI to be used as the base for interpreting any + relative URIs in the scope of the element on which it + appears; its value is inherited. This name is reserved + by virtue of its definition in the XML Base specification.

+ +

+ See http://www.w3.org/TR/xmlbase/ + for information about this attribute. +

+
+
+
+
+ + + + +
+ +

id (as an attribute name)

+

+ denotes an attribute whose value + should be interpreted as if declared to be of type ID. + This name is reserved by virtue of its definition in the + xml:id specification.

+ +

+ See http://www.w3.org/TR/xml-id/ + for information about this attribute. +

+
+
+
+
+ + + + + + + + + + +
+ +

Father (in any context at all)

+ +
+

+ denotes Jon Bosak, the chair of + the original XML Working Group. This name is reserved by + the following decision of the W3C XML Plenary and + XML Coordination groups: +

+
+

+ In appreciation for his vision, leadership and + dedication the W3C XML Plenary on this 10th day of + February, 2000, reserves for Jon Bosak in perpetuity + the XML name "xml:Father". +

+
+
+
+
+
+ + + +
+

About this schema document

+ +
+

+ This schema defines attributes and an attribute group suitable + for use by schemas wishing to allow xml:base, + xml:lang, xml:space or + xml:id attributes on elements they define. +

+

+ To enable this, such a schema must import this schema for + the XML namespace, e.g. as follows: +

+
+          <schema . . .>
+           . . .
+           <import namespace="http://www.w3.org/XML/1998/namespace"
+                      schemaLocation="http://www.w3.org/2001/xml.xsd"/>
+     
+

+ or +

+
+           <import namespace="http://www.w3.org/XML/1998/namespace"
+                      schemaLocation="http://www.w3.org/2009/01/xml.xsd"/>
+     
+

+ Subsequently, qualified reference to any of the attributes or the + group defined below will have the desired effect, e.g. +

+
+          <type . . .>
+           . . .
+           <attributeGroup ref="xml:specialAttrs"/>
+     
+

+ will define a type which will schema-validate an instance element + with any of those attributes. +

+
+
+
+
+ + + +
+

Versioning policy for this schema document

+
+

+ In keeping with the XML Schema WG's standard versioning + policy, this schema document will persist at + + http://www.w3.org/2009/01/xml.xsd. +

+

+ At the date of issue it can also be found at + + http://www.w3.org/2001/xml.xsd. +

+

+ The schema document at that URI may however change in the future, + in order to remain compatible with the latest version of XML + Schema itself, or with the XML namespace itself. In other words, + if the XML Schema or XML namespaces change, the version of this + document at + http://www.w3.org/2001/xml.xsd + + will change accordingly; the version at + + http://www.w3.org/2009/01/xml.xsd + + will not change. +

+

+ Previous dated (and unchanging) versions of this schema + document are at: +

+ +
+
+
+
+ +
+ diff --git a/src/test/java/org/metricshub/winrm/CatalogResolutionTest.java b/src/test/java/org/metricshub/winrm/CatalogResolutionTest.java new file mode 100644 index 0000000..09c6678 --- /dev/null +++ b/src/test/java/org/metricshub/winrm/CatalogResolutionTest.java @@ -0,0 +1,51 @@ +package org.metricshub.winrm; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.apache.cxf.Bus; +import org.apache.cxf.BusFactory; +import org.apache.cxf.catalog.OASISCatalogManager; +import org.junit.jupiter.api.Test; + +/** + * Verifies that the JAX-WS catalog shipped at META-INF/jax-ws-catalog.xml is + * auto-discovered by Apache CXF and remaps the absolute schema URLs referenced + * by wsdl/WinRM.wsdl to local classpath resources. + * + *

Without this mapping the WSDL loader fetches dsp8033 / dsp8034 / xml.xsd / + * ws-addr.xsd from schemas.dmtf.org / www.w3.org over the network. On offline + * or restricted-egress hosts that fetch blocks for ~75 s (OS TCP timeout) and + * the connection attempt fails with + * {@code WSDLException(PARSER_ERROR) ... Caused by: ConnectException}. + */ +class CatalogResolutionTest { + + @Test + void catalogResolvesWsdlImportUrlsToClasspathResources() throws Exception { + final Bus bus = BusFactory.getDefaultBus(true); + final OASISCatalogManager catalog = OASISCatalogManager.getCatalogManager(bus); + assertNotNull(catalog, "CXF OASISCatalogManager must be available"); + + assertResolvesToClasspath(catalog, "http://schemas.dmtf.org/wbem/wsman/1/dsp8033_1.0.xsd", "dsp8033_1.0.xsd"); + assertResolvesToClasspath(catalog, "http://schemas.dmtf.org/wbem/wsman/1/dsp8034_1.0.xsd", "dsp8034_1.0.xsd"); + assertResolvesToClasspath(catalog, "http://www.w3.org/2001/xml.xsd", "xml.xsd"); + assertResolvesToClasspath(catalog, "http://www.w3.org/2006/03/addressing/ws-addr.xsd", "ws-addr.xsd"); + } + + private static void assertResolvesToClasspath( + final OASISCatalogManager catalog, + final String systemId, + final String expectedSuffix + ) throws Exception { + final String resolved = catalog.resolveSystem(systemId); + assertNotNull(resolved, "catalog did not resolve " + systemId); + // Must NOT be a network URL — otherwise CXF will still hit the network at runtime. + assertFalse( + resolved.startsWith("http://") || resolved.startsWith("https://"), + "catalog returned a network URL for " + systemId + " -> " + resolved + ); + assertTrue(resolved.endsWith(expectedSuffix), "resolved URI does not end with " + expectedSuffix + ": " + resolved); + } +} From 22c4fbbec4033a63e78d7695bcbfedb6b296a7f6 Mon Sep 17 00:00:00 2001 From: Bertrand Martin Date: Tue, 21 Jul 2026 11:49:35 +0200 Subject: [PATCH 2/2] Address review comments in CatalogResolutionTest - Use a dedicated CXF Bus and shut it down after the assertions instead of mutating the JVM-wide default Bus (avoids leaking CXF resources and test order-dependence) - Verify each catalog-resolved URI actually exists and is readable, not just well-formed Co-Authored-By: Claude Fable 5 --- .../winrm/CatalogResolutionTest.java | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/test/java/org/metricshub/winrm/CatalogResolutionTest.java b/src/test/java/org/metricshub/winrm/CatalogResolutionTest.java index 09c6678..e57f7d4 100644 --- a/src/test/java/org/metricshub/winrm/CatalogResolutionTest.java +++ b/src/test/java/org/metricshub/winrm/CatalogResolutionTest.java @@ -4,6 +4,8 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.io.InputStream; +import java.net.URI; import org.apache.cxf.Bus; import org.apache.cxf.BusFactory; import org.apache.cxf.catalog.OASISCatalogManager; @@ -24,14 +26,20 @@ class CatalogResolutionTest { @Test void catalogResolvesWsdlImportUrlsToClasspathResources() throws Exception { - final Bus bus = BusFactory.getDefaultBus(true); - final OASISCatalogManager catalog = OASISCatalogManager.getCatalogManager(bus); - assertNotNull(catalog, "CXF OASISCatalogManager must be available"); + // Dedicated Bus so the test neither leaks CXF resources nor mutates the + // JVM-wide default Bus shared with other tests. + final Bus bus = BusFactory.newInstance().createBus(); + try { + final OASISCatalogManager catalog = OASISCatalogManager.getCatalogManager(bus); + assertNotNull(catalog, "CXF OASISCatalogManager must be available"); - assertResolvesToClasspath(catalog, "http://schemas.dmtf.org/wbem/wsman/1/dsp8033_1.0.xsd", "dsp8033_1.0.xsd"); - assertResolvesToClasspath(catalog, "http://schemas.dmtf.org/wbem/wsman/1/dsp8034_1.0.xsd", "dsp8034_1.0.xsd"); - assertResolvesToClasspath(catalog, "http://www.w3.org/2001/xml.xsd", "xml.xsd"); - assertResolvesToClasspath(catalog, "http://www.w3.org/2006/03/addressing/ws-addr.xsd", "ws-addr.xsd"); + assertResolvesToClasspath(catalog, "http://schemas.dmtf.org/wbem/wsman/1/dsp8033_1.0.xsd", "dsp8033_1.0.xsd"); + assertResolvesToClasspath(catalog, "http://schemas.dmtf.org/wbem/wsman/1/dsp8034_1.0.xsd", "dsp8034_1.0.xsd"); + assertResolvesToClasspath(catalog, "http://www.w3.org/2001/xml.xsd", "xml.xsd"); + assertResolvesToClasspath(catalog, "http://www.w3.org/2006/03/addressing/ws-addr.xsd", "ws-addr.xsd"); + } finally { + bus.shutdown(true); + } } private static void assertResolvesToClasspath( @@ -47,5 +55,10 @@ private static void assertResolvesToClasspath( "catalog returned a network URL for " + systemId + " -> " + resolved ); assertTrue(resolved.endsWith(expectedSuffix), "resolved URI does not end with " + expectedSuffix + ": " + resolved); + // The mapping must point at a resource that actually exists and is readable, + // not just a well-formed URI. + try (InputStream stream = new URI(resolved).toURL().openStream()) { + assertTrue(stream.read() != -1, "resolved URI is empty: " + resolved); + } } }