[ https://issues.apache.org/jira/browse/CXF-7597?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16325056#comment-16325056 ]
ASF GitHub Bot commented on CXF-7597: ------------------------------------- ffang closed pull request #363: [CXF-7597] Fix suspicious class loader findResource calls URL: https://github.com/apache/cxf/pull/363 This is a PR merged from a forked repository. As GitHub hides the original diff on merge, it is displayed below for the sake of provenance: As this is a foreign pull request (from a fork), the diff is supplied below (as it won't show otherwise due to GitHub magic): diff --git a/core/src/main/java/org/apache/cxf/resource/URIResolver.java b/core/src/main/java/org/apache/cxf/resource/URIResolver.java index 019935865f4..5a9e43d7e55 100644 --- a/core/src/main/java/org/apache/cxf/resource/URIResolver.java +++ b/core/src/main/java/org/apache/cxf/resource/URIResolver.java @@ -83,7 +83,8 @@ public URIResolver(String baseUriStr, String uriStr, Class<?> calling) throws IO } else if (baseUriStr != null && (baseUriStr.startsWith("jar:") || baseUriStr.startsWith("zip:") - || baseUriStr.startsWith("wsjar:"))) { + || baseUriStr.startsWith("wsjar:")) + && !isAbsolute(uriStr)) { tryArchive(baseUriStr, uriStr); } else if (uriStr.startsWith("jar:") || uriStr.startsWith("zip:") @@ -112,7 +113,8 @@ public void resolve(String baseUriStr, String uriStr, Class<?> callingCls) throw } else if (baseUriStr != null && (baseUriStr.startsWith("jar:") || baseUriStr.startsWith("zip:") - || baseUriStr.startsWith("wsjar:"))) { + || baseUriStr.startsWith("wsjar:")) + && !isAbsolute(uriStr)) { tryArchive(baseUriStr, uriStr); } else if (uriStr.startsWith("jar:") || uriStr.startsWith("zip:") @@ -123,7 +125,13 @@ public void resolve(String baseUriStr, String uriStr, Class<?> callingCls) throw } } - + private boolean isAbsolute(String uriStr) { + try { + return new URI(uriStr).isAbsolute(); + } catch (URISyntaxException e) { + return false; + } + } private void tryFileSystem(String baseUriStr, String uriStr) throws IOException, MalformedURLException { try { diff --git a/core/src/test/java/org/apache/cxf/resource/URIResolverTest.java b/core/src/test/java/org/apache/cxf/resource/URIResolverTest.java index 4ef6338fcb4..9efb8f00417 100644 --- a/core/src/test/java/org/apache/cxf/resource/URIResolverTest.java +++ b/core/src/test/java/org/apache/cxf/resource/URIResolverTest.java @@ -32,6 +32,7 @@ private URL resourceURL = getClass().getResource("resources/helloworld.bpr"); + private Throwable checkingThreadThrowable; // assumes single-thread test execution @Test public void testJARProtocol() throws Exception { @@ -57,6 +58,9 @@ public void testJARProtocol() throws Exception { is2.read(barray2); is2.close(); assertEquals(IOUtils.newStringFromBytes(barray), IOUtils.newStringFromBytes(barray2)); + + resolveWithCheckingClassloader(uriResolver, "baseUriStr", uriStr, null); + resolveWithCheckingClassloaderInConstructor("baseUriStr", uriStr, null); } @Test @@ -79,8 +83,30 @@ public void testJARResolver() throws Exception { InputStream is3 = uriResolver.getInputStream(); assertNotNull(is3); + + resolveWithCheckingClassloader(uriResolver, uriStr, "hello_world_2.wsdl", null); + resolveWithCheckingClassloaderInConstructor(uriStr, "hello_world_2.wsdl", null); } + @Test + public void testJARResolveBaseAndAbsolute() throws Exception { + uriResolver = new URIResolver(); + + String baseUriStr = "jar:" + resourceURL.toString() + "!/wsdl/hello_world.wsdl"; + + URL jarURL = new URL(baseUriStr); + InputStream is = jarURL.openStream(); + assertNotNull(is); + + String uriStr = "jar:" + resourceURL.toString() + "!/wsdl/hello_world_2.wsdl"; + + URL jarURL2 = new URL(uriStr); + InputStream is2 = jarURL2.openStream(); + assertNotNull(is2); + + resolveWithCheckingClassloader(uriResolver, baseUriStr, uriStr, null); + resolveWithCheckingClassloaderInConstructor(baseUriStr, uriStr, null); + } @Test public void testResolveRelativeFile() throws Exception { @@ -98,12 +124,15 @@ public void testResolveRelativeFile() throws Exception { URIResolver xsdResolver = new URIResolver(); xsdResolver.resolve(baseUri, schemaLocation, this.getClass()); assertNotNull(xsdResolver.getInputStream()); + resolveWithCheckingClassloader(xsdResolver, baseUri, schemaLocation, this.getClass()); + resolveWithCheckingClassloaderInConstructor(baseUri, schemaLocation, this.getClass()); // resolve the schema using relative location with base uri fragment xsdResolver = new URIResolver(); xsdResolver.resolve(baseUri + "#type2", schemaLocation, this.getClass()); assertNotNull(xsdResolver.getInputStream()); - + resolveWithCheckingClassloader(xsdResolver, baseUri + "#type2", schemaLocation, this.getClass()); + resolveWithCheckingClassloaderInConstructor(baseUri + "#type2", schemaLocation, this.getClass()); } @Test @@ -122,12 +151,15 @@ public void testResolvePathWithSpace() throws Exception { URIResolver xsdResolver = new URIResolver(); xsdResolver.resolve(baseUri, schemaLocation, this.getClass()); assertNotNull(xsdResolver.getInputStream()); + resolveWithCheckingClassloader(xsdResolver, baseUri, schemaLocation, this.getClass()); + resolveWithCheckingClassloaderInConstructor(baseUri, schemaLocation, this.getClass()); // resolve the schema using relative location with base uri fragment xsdResolver = new URIResolver(); xsdResolver.resolve(baseUri + "#type2", schemaLocation, this.getClass()); assertNotNull(xsdResolver.getInputStream()); - + resolveWithCheckingClassloader(xsdResolver, baseUri + "#type2", schemaLocation, this.getClass()); + resolveWithCheckingClassloaderInConstructor(baseUri + "#type2", schemaLocation, this.getClass()); } @Test @@ -136,6 +168,8 @@ public void testBasePathWithSpace() throws Exception { // resolve the wsdl wsdlResolver.resolve(null, "wsdl/folder with spaces/foo.wsdl", this.getClass()); assertTrue(wsdlResolver.isResolved()); + resolveWithCheckingClassloader(wsdlResolver, null, "wsdl/folder with spaces/foo.wsdl", this.getClass()); + resolveWithCheckingClassloaderInConstructor(null, "wsdl/folder with spaces/foo.wsdl", this.getClass()); } @Test @@ -144,5 +178,62 @@ public void testBasePathWithEncodedSpace() throws Exception { // resolve the wsdl wsdlResolver.resolve(null, "wsdl/folder%20with%20spaces/foo.wsdl", this.getClass()); assertTrue(wsdlResolver.isResolved()); + resolveWithCheckingClassloader(wsdlResolver, null, "wsdl/folder%20with%20spaces/foo.wsdl", this.getClass()); + resolveWithCheckingClassloaderInConstructor(null, "wsdl/folder%20with%20spaces/foo.wsdl", this.getClass()); + } + + private void resolveWithCheckingClassloader(URIResolver resolver, String baseUriStr, String uriStr, + Class<?> callingCls) throws InterruptedException { + checkingThreadThrowable = null; + Runnable operation = () -> { + try { + resolver.resolve(baseUriStr, uriStr, callingCls); + } catch (Throwable t) { + checkingThreadThrowable = t; + } + assertNotNull(resolver.getInputStream()); + }; + Thread thread = new Thread(operation); + thread.setContextClassLoader(new CheckingClassLoader(this.getClass().getClassLoader())); + thread.start(); + thread.join(10000); + assertFalse("resolve operation did not finish in time", thread.isAlive()); + assertNull(checkingThreadThrowable); + } + + private void resolveWithCheckingClassloaderInConstructor(String baseUriStr, String uriStr, Class<?> callingCls) + throws InterruptedException { + checkingThreadThrowable = null; + Runnable operation = () -> { + URIResolver resolver = null; + try { + resolver = new URIResolver(baseUriStr, uriStr, callingCls); + } catch (Throwable t) { + checkingThreadThrowable = t; + } + if (resolver != null) { + assertNotNull(resolver.getInputStream()); + } + }; + Thread thread = new Thread(operation); + thread.setContextClassLoader(new CheckingClassLoader(this.getClass().getClassLoader())); + thread.start(); + thread.join(10000); + assertFalse("resolve operation did not finish in time", thread.isAlive()); + assertNull(checkingThreadThrowable); + } + + static class CheckingClassLoader extends ClassLoader { + CheckingClassLoader(ClassLoader parent) { + super(parent); + } + + @Override + protected URL findResource(String name) { + if (name != null && name.startsWith("jar:file:")) { + throw new AssertionError("Suspicious resource name: " + name); + } + return super.findResource(name); + } } } ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org > Suspicious calls to ClassLoader.findResource when resolving absolute base and > actual URIs > ----------------------------------------------------------------------------------------- > > Key: CXF-7597 > URL: https://issues.apache.org/jira/browse/CXF-7597 > Project: CXF > Issue Type: Bug > Affects Versions: 3.2.1 > Reporter: Pavol Mederly > Assignee: Freeman Fang > > When {{URIResolver.resolve(..)}} is called with both {{baseUriStr}} and > {{uriStr}} containing absolute URIs, e.g. > {quote} > # *baseUriStr* = > jar:file:/C:/midpoint/tgit/cxf/core/target/test-classes/org/apache/cxf/resource/resources/helloworld.bpr!/wsdl/hello_world.wsdl > # *uriStr* = > jar:file:/C:/midpoint/tgit/cxf/core/target/test-classes/org/apache/cxf/resource/resources/helloworld.bpr!/wsdl/hello_world_2.wsdl > {quote} > then it makes suspicious calls to a class loader, trying to find resources > with names like > {quote} > # > jar:file:/C:/midpoint/tgit/cxf/core/target/test-classes/org/apache/cxf/resource/resources/helloworld.bpr!/wsdl/hello_world_2.wsdl > # > /jar:file:/C:/midpoint/tgit/cxf/core/target/test-classes/org/apache/cxf/resource/resources/helloworld.bpr!/wsdl/hello_world_2.wsdl > # > jar:file:/C:/midpoint/tgit/cxf/core/target/test-classes/org/apache/cxf/resource/resources/helloworld.bpr!/wsdl/hello_world_2.wsdl > {quote} > In our case (when used as part of the > [midPoint|https://github.com/Evolveum/midpoint/] product) the situation is > like this: > Resolving: > {quote} > # *baseUriStr* = > jar:file:/C:/tmp/mp/lib/midpoint.war!/WEB-INF/lib/schema-3.7.jar!/xml/ns/public/common/common-3.xsd > # *uriStr* = > jar:file:/C:/tmp/mp/lib/midpoint.war!/WEB-INF/lib/schema-3.7.jar!/prism/xml/ns/public/types-3.xsd > {quote} > leads first to the resolution of obviously wrong URL: > bq. > jar:file:/C:/tmp/mp/lib/midpoint.war!jar:file:/C:/tmp/mp/lib/midpoint.war!/WEB-INF/lib/schema-3.7.jar!/prism/xml/ns/public/types-3.xsd > (note the two midpoint.war segments there) > and then to the resolution of the following resource name (via class loader): > bq. > jar:file:/C:/tmp/mp/lib/midpoint.war!/WEB-INF/lib/schema-3.7.jar!/prism/xml/ns/public/types-3.xsd > Note that as per ClassLoader javadocs, "The name of a resource is a > '/'-separated path name that identifies the resource." Although formally the > above URIs match this definition, some class loader implementations, namely > the one in Spring Boot which we use in midPoint, react to such requests in an > unexpected way, returning wrong (unrelated) content. The result is that > {{URIResolver.resolve(..)}} returns the wrong content as well. See [Spring > Boot issue > #11367|https://github.com/spring-projects/spring-boot/issues/11367]. > Even when Spring Boot is eventually fixed, {{classLoader.findResource(..)}} > calls are unnecessary overhead. > Please see > {{[URIResolverTest.testJARResolveBaseAndAbsolute|https://github.com/Evolveum/cxf/commit/44d99924db52f2a4b5bdacc41bd83b81bffb8cb4#diff-565a425d43d14b14b2dbb4a251b04697R92]}} > in the upcoming commit as well as the proposed > [fix|https://github.com/Evolveum/cxf/commit/44d99924db52f2a4b5bdacc41bd83b81bffb8cb4#diff-b7160a28d60b729a956bd1a5f5ffa351] > in {{URIResolver}}. -- This message was sent by Atlassian JIRA (v6.4.14#64029)