Skip to content

Commit

Permalink
[CXF-8966] : fix validation of nil int in xsd
Browse files Browse the repository at this point in the history
  • Loading branch information
f2par0 committed Dec 7, 2023
1 parent fce94b8 commit 1b8d4e0
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXSource;
Expand Down Expand Up @@ -118,7 +117,7 @@ public Object read(final QName name, XMLStreamReader input, Class<?> type) {
if (type != null) {
Object retVal = null;
if (SAXSource.class.isAssignableFrom(type)
|| StaxSource.class.isAssignableFrom(type)) {
|| StaxSource.class.isAssignableFrom(type)) {
retVal = new StaxSource(resetForStreaming(input));
} else if (StreamSource.class.isAssignableFrom(type)) {
retVal = new StreamSource(getInputStream(input));
Expand Down Expand Up @@ -160,7 +159,7 @@ public OutputStream getOutputStream() throws IOException {
throw new Fault("COULD_NOT_READ_XML_STREAM", LOG, e);
} catch (XMLStreamException e) {
throw new Fault("COULD_NOT_READ_XML_STREAM_CAUSED_BY", LOG, e,
e.getMessage());
e.getMessage());
}
}

Expand Down Expand Up @@ -216,41 +215,44 @@ public void close() throws XMLStreamException {
}

private Element validate(XMLStreamReader input) throws XMLStreamException, IOException {
DOMSource ds = read(input);
final Element rootElement;
if (ds.getNode() instanceof Document) {
rootElement = ((Document)ds.getNode()).getDocumentElement();
} else {
rootElement = (Element)ds.getNode();
}

Element rootElement;
WoodstoxValidationImpl impl = new WoodstoxValidationImpl();
XMLStreamWriter nullWriter = null;
XMLStreamReader inputWithoutXop = null;
if (impl.canValidate()) {
nullWriter = StaxUtils.createXMLStreamWriter(new NUllOutputStream());
impl.setupValidation(nullWriter, message.getExchange().getEndpoint(),
message.getExchange().getService().getServiceInfos().get(0));
//filter xop node, which causes validation to fail
XMLStreamReader filteredReader =
StaxUtils.createFilteredReader(input, new StaxStreamFilter(XOP));
try (CachedOutputStream out = new CachedOutputStream()) {
StaxUtils.copy(filteredReader, out);
inputWithoutXop = StaxUtils.createXMLStreamReader(out.getInputStream());
impl.setupValidation(inputWithoutXop, message.getExchange().getEndpoint(),
message.getExchange().getService().getServiceInfos().get(0));
filteredReader.close();
}
}
//check if the impl can still validate after the setup, possible issue loading schemas or similar
if (impl.canValidate()) {
//Can use the MSV libs and woodstox to handle the schema validation during
//parsing and processing. Much faster and single traversal
//filter xop node
XMLStreamReader reader = StaxUtils.createXMLStreamReader(ds);
XMLStreamReader filteredReader =
StaxUtils.createFilteredReader(reader,
new StaxStreamFilter(new QName[] {XOP}));
//parsing and processing. Much faster and single traversal
rootElement = StaxUtils.read(inputWithoutXop).getDocumentElement();

StaxUtils.copy(filteredReader, nullWriter);
} else {

DOMSource ds = read(input);
if (ds.getNode() instanceof Document) {
rootElement = ((Document)ds.getNode()).getDocumentElement();
} else {
rootElement = (Element)ds.getNode();
}

//MSV not available, use a slower method of cloning the data, replace the xop's, validate
LOG.fine("NO_MSV_AVAILABLE");
Element newElement = rootElement;
if (DOMUtils.hasElementWithName(rootElement, "http://www.w3.org/2004/08/xop/include", "Include")) {
newElement = (Element)rootElement.cloneNode(true);
List<Element> elems = DOMUtils.findAllElementsByTagNameNS(newElement,
"http://www.w3.org/2004/08/xop/include",
"Include");
"http://www.w3.org/2004/08/xop/include",
"Include");
for (Element include : elems) {
Node parentNode = include.getParentNode();
parentNode.removeChild(include);
Expand All @@ -269,7 +271,7 @@ private Element validate(XMLStreamReader input) throws XMLStreamException, IOExc
}

private InputStream getInputStream(XMLStreamReader input)
throws XMLStreamException, IOException {
throws XMLStreamException, IOException {

try (CachedOutputStream out = new CachedOutputStream()) {
StaxUtils.copy(input, out);
Expand Down Expand Up @@ -298,7 +300,7 @@ public DOMSource read(XMLStreamReader reader) {
return new DOMSource(document);
} catch (XMLStreamException e) {
throw new Fault("COULD_NOT_READ_XML_STREAM_CAUSED_BY", LOG, e,
e.getMessage());
e.getMessage());
}
}

Expand All @@ -314,14 +316,4 @@ public void setProperty(String prop, Object value) {
message = (Message)value;
}
}

static class NUllOutputStream extends OutputStream {
public void write(byte[] b, int off, int len) {
}
public void write(int b) {
}

public void write(byte[] b) throws IOException {
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,27 +22,79 @@
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.dom.DOMSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import org.w3c.dom.Document;

import com.ctc.wstx.msv.W3CSchemaFactory;

import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.message.Exchange;
import org.apache.cxf.message.ExchangeImpl;
import org.apache.cxf.message.Message;
import org.apache.cxf.message.MessageImpl;
import org.apache.cxf.service.Service;
import org.apache.cxf.service.ServiceImpl;
import org.apache.cxf.service.model.MessageInfo;
import org.apache.cxf.service.model.MessagePartInfo;
import org.apache.cxf.service.model.ServiceInfo;
import org.apache.cxf.staxutils.StaxUtils;
import org.codehaus.stax2.XMLStreamReader2;
import org.codehaus.stax2.validation.XMLValidationSchema;

import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

/**
*
*/
public class XMLStreamDataReaderTest {
private static final byte[] DUMMY_DATA = "<ns:dummy xmlns:ns='http://www.apache.org/cxf'/>".getBytes();
private static final byte[] DUMMY_DATA_NULL_BYTE =
"<ns:dummy xmlns:ns='http://www.apache.org/cxf&#x00;'/>".getBytes();
"<ns:dummy xmlns:ns='http://www.apache.org/cxf&#x00;'/>".getBytes();

// Parse some XML with a null byte and check we don't return internal Woodstox package names in the error message
@Test
public void testParseNullByte() throws Exception {
XMLStreamDataReader reader = new XMLStreamDataReader();
Message msg = new MessageImpl();

TestInputStream in1 = new TestInputStream(DUMMY_DATA_NULL_BYTE);

msg.setContent(InputStream.class, in1);

reader.setProperty(Message.class.getName(), msg);

Object obj = reader.read(new QName("http://www.apache.org/cxf", "dummy"),
StaxUtils.createXMLStreamReader(in1), XMLStreamReader.class);

assertTrue(obj instanceof XMLStreamReader);

try {
reader.read((XMLStreamReader) obj);
} catch (Fault f) {
assertFalse(f.getMessage().contains("com.ctc.wstx"));
}

((XMLStreamReader)obj).close();
}

@Test
public void testCloseOriginalInputStream() throws Exception {
Expand All @@ -66,30 +118,76 @@ public void testCloseOriginalInputStream() throws Exception {
assertTrue(in1.isClosed());
}

// Parse some XML with a null byte and check we don't return internal Woodstox package names in the error message
@Test
public void testParseNullByte() throws Exception {
public void testValid() throws Exception {
testValidate("resources/schema.xsd", "resources/test-valid.xml", false);
}

@Test
public void testInValid() throws Exception {
testValidate("resources/schema.xsd", "resources/test-invalid.xml", true);
}


private void testValidate(String schemaPath, String xmlPath, boolean exceptionExpected) throws Exception {

//create schema
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
URL schemaURI = getClass().getResource(schemaPath);
Document wsdl = documentBuilder.parse(schemaURI.openStream());
String wsdlSystemId = schemaURI.toExternalForm();
DOMSource source = new DOMSource(wsdl);
source.setSystemId(wsdlSystemId);
source.setSystemId(wsdlSystemId);

XMLValidationSchema schemaw3c =
W3CSchemaFactory.newInstance(XMLValidationSchema.SCHEMA_ID_W3C_SCHEMA).createSchema(schemaURI);
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(schemaURI);

XMLStreamDataReader reader = new XMLStreamDataReader();
reader.setSchema(schema);


InputStream testIS = getClass().getResourceAsStream(xmlPath);
Message msg = new MessageImpl();
Exchange exchange = new ExchangeImpl();

TestInputStream in1 = new TestInputStream(DUMMY_DATA_NULL_BYTE);
ServiceInfo serviceInfo = new ServiceInfo();

msg.setContent(InputStream.class, in1);
Endpoint endpoint = mock(Endpoint.class);
when(endpoint.get(XMLValidationSchema.class.getName())).thenReturn(schemaw3c);

reader.setProperty(Message.class.getName(), msg);
Service svc = new ServiceImpl(serviceInfo);

Object obj = reader.read(new QName("http://www.apache.org/cxf", "dummy"),
StaxUtils.createXMLStreamReader(in1), XMLStreamReader.class);
exchange.put(Service.class, svc);
exchange.put(Endpoint.class, endpoint);

assertTrue(obj instanceof XMLStreamReader);
msg.setExchange(exchange);
msg.setContent(InputStream.class, testIS);
reader.setProperty(Message.class.getName(), msg);

XMLInputFactory xmlFactory = XMLInputFactory.newInstance();
XMLStreamReader2 xmlStreamReader = (XMLStreamReader2) xmlFactory.createXMLStreamReader(testIS, "utf-8");

MessageInfo messageInfo = new MessageInfo(null,
MessageInfo.Type.INPUT,
new QName("http://www.test.org/services",
"NullTestOperationRequest"));
MessagePartInfo messagePartInfo = new MessagePartInfo(new QName(
"http://www.test.org/services", "NullTestOperationRequest"), messageInfo);
messagePartInfo.setElement(true);
boolean exceptionCaught = false;
try {
reader.read((XMLStreamReader) obj);
} catch (Fault f) {
assertFalse(f.getMessage().contains("com.ctc.wstx"));
reader.read(messagePartInfo, xmlStreamReader);
} catch (Fault fault) {
exceptionCaught = true;
} catch (Exception exc) {
fail(exc.getMessage());
}

((XMLStreamReader)obj).close();
assertEquals(exceptionExpected, exceptionCaught);
}

private static class TestInputStream extends ByteArrayInputStream {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.test.org/service/">
<xsd:element name="NullTestOperationRequest" nillable="true">
<xsd:complexType>
<xsd:sequence>
<xsd:element nillable="true" name="inInt" type="xsd:int" maxOccurs="1" minOccurs="0" ></xsd:element>
<xsd:element nillable="true" name="inInteger" type="xsd:integer" maxOccurs="1" minOccurs="0" ></xsd:element>
<xsd:element nillable="true" name="inString" type="xsd:string" maxOccurs="1" minOccurs="0" ></xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<ser:NullTestOperationRequest xmlns:ser="http://www.test.org/service/">

<inInt xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="false"/>

</ser:NullTestOperationRequest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<ser:NullTestOperationRequest xmlns:ser="http://www.test.org/service/">

<inInt xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<inInteger xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<inString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>

</ser:NullTestOperationRequest>

0 comments on commit 1b8d4e0

Please sign in to comment.