Skip to content

Commit

Permalink
[JBWS-4385]:This fix starts with Brad Maxwell's proposed change and a…
Browse files Browse the repository at this point in the history
…dded a JAXPDelegateClassLoader to Protect the jbossws runtime from loading the jaxp impl from user's deployment
  • Loading branch information
jimma committed Nov 1, 2023
1 parent cd88a18 commit 1c27976
Show file tree
Hide file tree
Showing 10 changed files with 328 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,12 @@ private void updateAvailableBusWithServletInfo(ServletConfig servletConfig)
@Override
protected void invoke(HttpServletRequest req, HttpServletResponse res) throws ServletException
{
ServletHelper.callRequestHandler(req, res, getServletContext(), bus, endpoint);
ClassLoader previous = pushServerCL();
try {
ServletHelper.callRequestHandler(req, res, getServletContext(), bus, endpoint);
} finally {
popServerCL(previous);
}
}

@Override
Expand Down Expand Up @@ -137,11 +142,27 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha
ServletException
{
// filtering not supported, move on
chain.doFilter(request, response);
ClassLoader previous = pushServerCL();
try {
chain.doFilter(request, response);
} finally {
popServerCL(previous);
}
}

protected Bus getBus()
{
return bus;
}
private ClassLoader pushServerCL()
{
ClassLoader current = SecurityActions.getContextClassLoader();
SecurityActions.setContextClassLoader(SecurityActions.createDelegateClassLoader(current, CXFServletExt.class.getClassLoader()));
return current;
}

private void popServerCL(ClassLoader previousCL)
{
SecurityActions.setContextClassLoader(previousCL);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package org.jboss.wsf.stack.cxf;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.SecureClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.NoSuchElementException;
import java.util.Set;
import org.jboss.ws.common.utils.DelegateClassLoader;

public class JAXPDelegateClassLoader extends DelegateClassLoader
{
private final ClassLoader delegate;

private final ClassLoader parent;
private static Set<String> skipSps = new HashSet<String>(Arrays. asList(
"META-INF/services/javax.xml.parsers.DocumentBuilderFactory",
"META-INF/services/javax.xml.parsers.SAXParserFactory",
"META-INF/services/javax.xml.validation.SchemaFactory",
"META-INF/services/javax.xml.stream.XMLEventFactory",
"META-INF/services/javax.xml.datatype.DatatypeFactory",
"META-INF/services/javax.xml.transform.TransformerFactory",
"META-INF/services/javax.xml.xpath.XPathFactory"
));

public JAXPDelegateClassLoader(final ClassLoader delegate, final ClassLoader parent)
{
super(delegate, parent);
this.delegate = delegate;
this.parent = parent;
}

@Override
public URL getResource(final String name)
{
URL url = null;
if (parent != null)
{
url = parent.getResource(name);
}
return (url == null && !skipSps.contains(name)) ? delegate.getResource(name) : url;
}

/** {@inheritDoc} */
@Override
public Enumeration<URL> getResources(final String name) throws IOException
{
final ArrayList<Enumeration<URL>> foundResources = new ArrayList<Enumeration<URL>>();

if (!skipSps.contains(name)) {
foundResources.add(delegate.getResources(name));
}
if (parent != null)
{
foundResources.add(parent.getResources(name));
}

return new Enumeration<URL>()
{
private int position = foundResources.size() - 1;

public boolean hasMoreElements()
{
while (position >= 0)
{
if (foundResources.get(position).hasMoreElements())
{
return true;
}
position--;
}
return false;
}

public URL nextElement()
{
while (position >= 0)
{
try
{
return (foundResources.get(position)).nextElement();
}
catch (NoSuchElementException e)
{
}
position--;
}
throw new NoSuchElementException();
}
};
}

@Override
public InputStream getResourceAsStream(final String name)
{
InputStream is = null;
if (parent != null)
{
is = parent.getResourceAsStream(name);
}
return (is == null && !skipSps.contains(name)) ? delegate.getResourceAsStream(name) : is;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,23 @@ public Object run()
});
}
}
static JAXPDelegateClassLoader createDelegateClassLoader(final ClassLoader delegate, final ClassLoader parent)
{
SecurityManager sm = System.getSecurityManager();
if (sm == null)
{
return new JAXPDelegateClassLoader(delegate, parent);
}
else
{
return AccessController.doPrivileged(new PrivilegedAction<JAXPDelegateClassLoader>()
{
@Override
public JAXPDelegateClassLoader run()
{
return new JAXPDelegateClassLoader(delegate, parent);
}
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.jboss.wsf.spi.deployment.Deployment;
import org.jboss.wsf.spi.deployment.ResourceResolver;
import org.jboss.wsf.spi.metadata.webservices.JBossWebservicesMetaData;
import org.jboss.wsf.stack.cxf.JAXPDelegateClassLoader;
import org.jboss.wsf.stack.cxf.client.configuration.JBossWSBusFactory;
import org.jboss.wsf.stack.cxf.configuration.BusHolder;
import org.jboss.wsf.stack.cxf.deployment.WSDLFilePublisher;
Expand Down Expand Up @@ -86,7 +87,7 @@ private void startDeploymentBus(final Deployment dep)
//use origClassLoader (which on AS7 is set to ASIL aggregation module's classloader by TCCLDeploymentProcessor) as
//parent to make sure user provided libs in the deployment do no mess up the WS endpoint's deploy if they duplicates
//libraries already available on the application server modules.
SecurityActions.setContextClassLoader(new DelegateClassLoader(dep.getClassLoader(), origClassLoader));
SecurityActions.setContextClassLoader(new JAXPDelegateClassLoader(dep.getClassLoader(), origClassLoader));
DDBeans metadata = dep.getAttachment(DDBeans.class);
BusHolder holder = new BusHolder(metadata);

Expand Down
18 changes: 18 additions & 0 deletions modules/testsuite/cxf-tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,24 @@
<outputDirectory>target/cxf-embedded</outputDirectory>
</configuration>
</execution>
<execution>
<!--The xerces 2.0.1 to package in test deployment-->
<id>copy-xerces</id>
<phase>process-test-resources</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>xerces</groupId>
<artifactId>xerces</artifactId>
<version>2.0.1</version>
</artifactItem>
</artifactItems>
<outputDirectory>target/xerces</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.jboss.test.ws.jaxws.cxf.jbws4385;

@jakarta.jws.WebService(wsdlLocation = "WEB-INF/wsdl/HelloWorld.wsdl")
public interface Hello {

@jakarta.jws.WebMethod
public String hello(String name);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.jboss.test.ws.jaxws.cxf.jbws4385;


import javax.xml.parsers.DocumentBuilderFactory;

@jakarta.jws.WebService(targetNamespace = "http://test.ws.jboss.org/",
wsdlLocation = "WEB-INF/wsdl/HelloWorld.wsdl")
public class HelloBean {
public HelloBean() {
}

@jakarta.jws.WebMethod
public String hello(String name) {
String xercesJar = DocumentBuilderFactory.newInstance().getClass().
getProtectionDomain().getCodeSource().getLocation().toString();
if (xercesJar.contains("WEB-INF")) {
xercesJar = xercesJar.substring(xercesJar.indexOf("WEB-INF"));
} else {
xercesJar = "WFLY modules";
}
return "Hello " + name + "and the DocumentBuilderFactory is loaded from " + xercesJar;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package org.jboss.test.ws.jaxws.cxf.jbws4385;

import jakarta.xml.ws.Service;
import java.io.File;
import java.net.URL;
import javax.xml.namespace.QName;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.jboss.wsf.test.JBossWSTest;
import org.jboss.wsf.test.JBossWSTestHelper;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(Arquillian.class)
public class JBWS4385TestCase extends JBossWSTest {
private static final String DEP = "jaxws-cxf-jbws4385";

@ArquillianResource
private URL baseURL;

@Deployment(name = DEP, testable = false)
public static WebArchive createDeployment() {
final File xercesDir = new File(new File(JBossWSTestHelper.getTestResourcesDir()).getParentFile(), "xerces");

WebArchive archive = ShrinkWrap.create(WebArchive.class, DEP + ".war");
archive.setManifest(new StringAsset("Manifest-Version: 1.0\n"
+ "Dependencies: org.apache.cxf\n"))
.addClass(org.jboss.test.ws.jaxws.cxf.jbws4385.HelloBean.class)
.addAsWebInfResource(new File(JBossWSTestHelper.getTestResourcesDir() + "/jaxws/cxf/jbws4385/WEB-INF/wsdl/HelloWorld.wsdl"), "wsdl/HelloWorld.wsdl")
.setWebXML(new File(JBossWSTestHelper.getTestResourcesDir() + "/jaxws/cxf/jbws4385/WEB-INF/web.xml"));
JBossWSTestHelper.addLibrary(xercesDir, archive);
return archive;
}

@Test
@RunAsClient
public void testWS() throws Exception {
QName serviceName = new QName("http://test.ws.jboss.org/", "HelloBeanService");
QName portName = new QName("http://test.ws.jboss.org/", "HelloBeanPort");

URL wsdlURL = new URL(baseURL + "?wsdl");

Service service = Service.create(wsdlURL, serviceName);
Hello proxy = (Hello) service.getPort(portName, Hello.class);

assertTrue("Xerces implementation is expected , but it is :" + proxy.hello("world"), proxy.hello("world").contains("WEB-INF/lib/xerces"));
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version='1.0' encoding='UTF-8'?>

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd"
version="2.5">

<servlet>
<servlet-name>HelloBean</servlet-name>
<servlet-class>org.jboss.test.ws.jaxws.cxf.jbws4385.HelloBean</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>HelloBean</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?xml version='1.0' encoding='UTF-8'?><wsdl:definitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://test.ws.jboss.org/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:ns1="http://schemas.xmlsoap.org/soap/http" name="HelloBeanService" targetNamespace="http://test.ws.jboss.org/">
<wsdl:types>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://test.ws.jboss.org/" elementFormDefault="unqualified" targetNamespace="http://test.ws.jboss.org/" version="1.0">

<xs:element name="hello" type="tns:hello"/>

<xs:element name="helloResponse" type="tns:helloResponse"/>

<xs:complexType name="hello">
<xs:sequence>
<xs:element minOccurs="0" name="arg0" type="xs:string"/>
</xs:sequence>
</xs:complexType>

<xs:complexType name="helloResponse">
<xs:sequence>
<xs:element minOccurs="0" name="return" type="xs:string"/>
</xs:sequence>
</xs:complexType>

</xs:schema>
</wsdl:types>
<wsdl:message name="hello">
<wsdl:part element="tns:hello" name="parameters">
</wsdl:part>
</wsdl:message>
<wsdl:message name="helloResponse">
<wsdl:part element="tns:helloResponse" name="parameters">
</wsdl:part>
</wsdl:message>
<wsdl:portType name="HelloBean">
<wsdl:operation name="hello">
<wsdl:input message="tns:hello" name="hello">
</wsdl:input>
<wsdl:output message="tns:helloResponse" name="helloResponse">
</wsdl:output>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="HelloBeanServiceSoapBinding" type="tns:HelloBean">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="hello">
<soap:operation soapAction="" style="document"/>
<wsdl:input name="hello">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="helloResponse">
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="HelloBeanService">
<wsdl:port binding="tns:HelloBeanServiceSoapBinding" name="HelloBeanPort">
<soap:address location="http://localhost:8080/helloWorld"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>

0 comments on commit 1c27976

Please sign in to comment.