Switching to use CXF's StaxUtils for DOM parsing. Still having problems with DTD parsing.
git-svn-id: https://svn.apache.org/repos/asf/santuario/xml-security-java/branches/staxutils@1847262 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/xml/security/c14n/Canonicalizer.java b/src/main/java/org/apache/xml/security/c14n/Canonicalizer.java
index 17c60de..7565799 100644
--- a/src/main/java/org/apache/xml/security/c14n/Canonicalizer.java
+++ b/src/main/java/org/apache/xml/security/c14n/Canonicalizer.java
@@ -26,6 +26,8 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import javax.xml.stream.XMLStreamException;
+
import org.apache.xml.security.c14n.implementations.Canonicalizer11_OmitComments;
import org.apache.xml.security.c14n.implementations.Canonicalizer11_WithComments;
import org.apache.xml.security.c14n.implementations.Canonicalizer20010315ExclOmitComments;
@@ -246,10 +248,11 @@
* @throws java.io.IOException
* @throws javax.xml.parsers.ParserConfigurationException
* @throws org.xml.sax.SAXException
+ * @throws XMLStreamException
*/
public byte[] canonicalize(byte[] inputBytes)
throws javax.xml.parsers.ParserConfigurationException,
- java.io.IOException, org.xml.sax.SAXException, CanonicalizationException {
+ java.io.IOException, org.xml.sax.SAXException, CanonicalizationException, XMLStreamException {
Document document = null;
try (InputStream bais = new ByteArrayInputStream(inputBytes)) {
InputSource in = new InputSource(bais);
diff --git a/src/main/java/org/apache/xml/security/c14n/CanonicalizerSpi.java b/src/main/java/org/apache/xml/security/c14n/CanonicalizerSpi.java
index be193eb..9734bb5 100644
--- a/src/main/java/org/apache/xml/security/c14n/CanonicalizerSpi.java
+++ b/src/main/java/org/apache/xml/security/c14n/CanonicalizerSpi.java
@@ -22,6 +22,8 @@
import java.io.OutputStream;
import java.util.Set;
+import javax.xml.stream.XMLStreamException;
+
import org.apache.xml.security.utils.XMLUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
@@ -48,10 +50,11 @@
* @throws java.io.IOException
* @throws javax.xml.parsers.ParserConfigurationException
* @throws org.xml.sax.SAXException
+ * @throws XMLStreamException
*/
public byte[] engineCanonicalize(byte[] inputBytes)
throws javax.xml.parsers.ParserConfigurationException, java.io.IOException,
- org.xml.sax.SAXException, CanonicalizationException {
+ org.xml.sax.SAXException, CanonicalizationException, XMLStreamException {
Document document = null;
try (java.io.InputStream bais = new ByteArrayInputStream(inputBytes)) {
diff --git a/src/main/java/org/apache/xml/security/c14n/implementations/Canonicalizer20010315.java b/src/main/java/org/apache/xml/security/c14n/implementations/Canonicalizer20010315.java
index 03c0548..954f640 100644
--- a/src/main/java/org/apache/xml/security/c14n/implementations/Canonicalizer20010315.java
+++ b/src/main/java/org/apache/xml/security/c14n/implementations/Canonicalizer20010315.java
@@ -26,6 +26,7 @@
import java.util.TreeSet;
import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
import org.apache.xml.security.c14n.CanonicalizationException;
import org.apache.xml.security.c14n.helper.C14nHelper;
@@ -296,7 +297,7 @@
}
protected void circumventBugIfNeeded(XMLSignatureInput input)
- throws CanonicalizationException, ParserConfigurationException, IOException, SAXException {
+ throws CanonicalizationException, ParserConfigurationException, IOException, SAXException, XMLStreamException {
if (!input.isNeedsToBeExpanded()) {
return;
}
diff --git a/src/main/java/org/apache/xml/security/c14n/implementations/Canonicalizer20010315Excl.java b/src/main/java/org/apache/xml/security/c14n/implementations/Canonicalizer20010315Excl.java
index fda565e..ef34f68 100644
--- a/src/main/java/org/apache/xml/security/c14n/implementations/Canonicalizer20010315Excl.java
+++ b/src/main/java/org/apache/xml/security/c14n/implementations/Canonicalizer20010315Excl.java
@@ -25,6 +25,7 @@
import java.util.SortedSet;
import java.util.TreeSet;
import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
import org.apache.xml.security.c14n.CanonicalizationException;
import org.apache.xml.security.c14n.helper.C14nHelper;
@@ -337,7 +338,7 @@
protected void circumventBugIfNeeded(XMLSignatureInput input)
throws CanonicalizationException, ParserConfigurationException,
- IOException, SAXException {
+ IOException, SAXException, XMLStreamException {
if (!input.isNeedsToBeExpanded() || inclusiveNSSet.isEmpty()) {
return;
}
diff --git a/src/main/java/org/apache/xml/security/c14n/implementations/CanonicalizerBase.java b/src/main/java/org/apache/xml/security/c14n/implementations/CanonicalizerBase.java
index 8a329cf..1bd60d4 100644
--- a/src/main/java/org/apache/xml/security/c14n/implementations/CanonicalizerBase.java
+++ b/src/main/java/org/apache/xml/security/c14n/implementations/CanonicalizerBase.java
@@ -31,6 +31,7 @@
import java.util.Set;
import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
import org.apache.xml.security.c14n.CanonicalizationException;
import org.apache.xml.security.c14n.CanonicalizerSpi;
@@ -160,11 +161,7 @@
}
}
return null;
- } catch (ParserConfigurationException ex) {
- throw new CanonicalizationException(ex);
- } catch (IOException ex) {
- throw new CanonicalizationException(ex);
- } catch (SAXException ex) {
+ } catch (ParserConfigurationException | IOException | SAXException | XMLStreamException ex) {
throw new CanonicalizationException(ex);
}
}
@@ -654,7 +651,7 @@
throws CanonicalizationException, DOMException, IOException;
abstract void circumventBugIfNeeded(XMLSignatureInput input)
- throws CanonicalizationException, ParserConfigurationException, IOException, SAXException;
+ throws CanonicalizationException, ParserConfigurationException, IOException, SAXException, XMLStreamException;
/**
* Outputs an Attribute to the internal Writer.
diff --git a/src/main/java/org/apache/xml/security/encryption/DocumentSerializer.java b/src/main/java/org/apache/xml/security/encryption/DocumentSerializer.java
index a35ff71..4c17e8b 100644
--- a/src/main/java/org/apache/xml/security/encryption/DocumentSerializer.java
+++ b/src/main/java/org/apache/xml/security/encryption/DocumentSerializer.java
@@ -24,6 +24,7 @@
import java.io.StringReader;
import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
import org.apache.xml.security.utils.XMLUtils;
import org.w3c.dom.Document;
@@ -89,12 +90,8 @@
child = fragElt.getFirstChild();
}
return result;
- } catch (SAXException se) {
- throw new XMLEncryptionException(se);
- } catch (ParserConfigurationException pce) {
- throw new XMLEncryptionException(pce);
- } catch (IOException ioe) {
- throw new XMLEncryptionException(ioe);
+ } catch (ParserConfigurationException | IOException | SAXException | XMLStreamException ex) {
+ throw new XMLEncryptionException(ex);
}
}
diff --git a/src/main/java/org/apache/xml/security/keys/keyresolver/KeyResolverSpi.java b/src/main/java/org/apache/xml/security/keys/keyresolver/KeyResolverSpi.java
index f5456a6..f55243c 100644
--- a/src/main/java/org/apache/xml/security/keys/keyresolver/KeyResolverSpi.java
+++ b/src/main/java/org/apache/xml/security/keys/keyresolver/KeyResolverSpi.java
@@ -28,6 +28,7 @@
import javax.crypto.SecretKey;
import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
import org.apache.xml.security.keys.storage.StorageResolver;
import org.apache.xml.security.utils.XMLUtils;
@@ -273,11 +274,7 @@
try (InputStream is = new ByteArrayInputStream(bytes)) {
Document doc = XMLUtils.read(is, secureValidation);
return doc.getDocumentElement();
- } catch (SAXException ex) {
- throw new KeyResolverException(ex);
- } catch (IOException ex) {
- throw new KeyResolverException(ex);
- } catch (ParserConfigurationException ex) {
+ } catch (ParserConfigurationException | IOException | SAXException | XMLStreamException ex) {
throw new KeyResolverException(ex);
}
}
diff --git a/src/main/java/org/apache/xml/security/keys/keyresolver/implementations/RetrievalMethodResolver.java b/src/main/java/org/apache/xml/security/keys/keyresolver/implementations/RetrievalMethodResolver.java
index 611e494..7f557f9 100644
--- a/src/main/java/org/apache/xml/security/keys/keyresolver/implementations/RetrievalMethodResolver.java
+++ b/src/main/java/org/apache/xml/security/keys/keyresolver/implementations/RetrievalMethodResolver.java
@@ -32,6 +32,7 @@
import java.util.Set;
import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
import org.apache.xml.security.c14n.CanonicalizationException;
import org.apache.xml.security.exceptions.XMLSecurityException;
@@ -126,7 +127,9 @@
LOG.debug("ParserConfigurationException", e);
} catch (SAXException e) {
LOG.debug("SAXException", e);
- }
+ } catch (XMLStreamException e) {
+ LOG.debug("XMLStreamException", e);
+ }
return null;
}
@@ -184,6 +187,8 @@
LOG.debug("ParserConfigurationException", e);
} catch (SAXException e) {
LOG.debug("SAXException", e);
+ } catch (XMLStreamException e) {
+ LOG.debug("XMLStreamException", e);
}
return null;
}
@@ -234,7 +239,7 @@
private static Element obtainReferenceElement(XMLSignatureInput resource, boolean secureValidation)
throws CanonicalizationException, ParserConfigurationException,
- IOException, SAXException, KeyResolverException {
+ IOException, SAXException, KeyResolverException, XMLStreamException {
Element e;
if (resource.isElement()){
e = (Element) resource.getSubNode();
diff --git a/src/main/java/org/apache/xml/security/signature/Manifest.java b/src/main/java/org/apache/xml/security/signature/Manifest.java
index 7eb83e5..240d93f 100644
--- a/src/main/java/org/apache/xml/security/signature/Manifest.java
+++ b/src/main/java/org/apache/xml/security/signature/Manifest.java
@@ -30,6 +30,7 @@
import java.util.Set;
import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
import org.apache.xml.security.c14n.CanonicalizationException;
import org.apache.xml.security.c14n.InvalidCanonicalizerException;
@@ -399,11 +400,7 @@
}
manifestReferences = referencedManifest.getVerificationResults();
- } catch (IOException ex) {
- throw new ReferenceNotInitializedException(ex);
- } catch (ParserConfigurationException ex) {
- throw new ReferenceNotInitializedException(ex);
- } catch (SAXException ex) {
+ } catch (ParserConfigurationException | IOException | SAXException | XMLStreamException ex) {
throw new ReferenceNotInitializedException(ex);
}
}
diff --git a/src/main/java/org/apache/xml/security/signature/SignedInfo.java b/src/main/java/org/apache/xml/security/signature/SignedInfo.java
index 28b553d..aa46878 100644
--- a/src/main/java/org/apache/xml/security/signature/SignedInfo.java
+++ b/src/main/java/org/apache/xml/security/signature/SignedInfo.java
@@ -26,6 +26,7 @@
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
import org.apache.xml.security.algorithms.SignatureAlgorithm;
import org.apache.xml.security.c14n.CanonicalizationException;
@@ -218,11 +219,7 @@
element.getParentNode().replaceChild(imported, element);
return (Element) imported;
}
- } catch (ParserConfigurationException ex) {
- throw new XMLSecurityException(ex);
- } catch (IOException ex) {
- throw new XMLSecurityException(ex);
- } catch (SAXException ex) {
+ } catch (ParserConfigurationException | IOException | SAXException | XMLStreamException ex) {
throw new XMLSecurityException(ex);
}
}
diff --git a/src/main/java/org/apache/xml/security/signature/XMLSignatureInput.java b/src/main/java/org/apache/xml/security/signature/XMLSignatureInput.java
index e8f82fa..b8ba860 100644
--- a/src/main/java/org/apache/xml/security/signature/XMLSignatureInput.java
+++ b/src/main/java/org/apache/xml/security/signature/XMLSignatureInput.java
@@ -30,6 +30,7 @@
import java.util.Set;
import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
import org.apache.xml.security.c14n.CanonicalizationException;
import org.apache.xml.security.c14n.implementations.Canonicalizer11_OmitComments;
@@ -191,9 +192,10 @@
* @throws IOException
* @throws ParserConfigurationException
* @throws CanonicalizationException
+ * @throws XMLStreamException
*/
public Set<Node> getNodeSet() throws CanonicalizationException, ParserConfigurationException,
- IOException, SAXException {
+ IOException, SAXException, XMLStreamException {
return getNodeSet(false);
}
@@ -215,9 +217,10 @@
* @throws IOException
* @throws ParserConfigurationException
* @throws CanonicalizationException
+ * @throws XMLStreamException
*/
public Set<Node> getNodeSet(boolean circumvent) throws ParserConfigurationException,
- IOException, SAXException, CanonicalizationException {
+ IOException, SAXException, CanonicalizationException, XMLStreamException {
if (inputNodeSet != null) {
return inputNodeSet;
}
@@ -568,7 +571,7 @@
}
void convertToNodes() throws CanonicalizationException,
- ParserConfigurationException, IOException, SAXException {
+ ParserConfigurationException, IOException, SAXException, XMLStreamException {
// select all nodes, also the comments.
try {
Document doc = XMLUtils.read(this.getOctetStream(), secureValidation);
diff --git a/src/main/java/org/apache/xml/security/staxutils/AbstractDOMStreamReader.java b/src/main/java/org/apache/xml/security/staxutils/AbstractDOMStreamReader.java
new file mode 100644
index 0000000..9484c89
--- /dev/null
+++ b/src/main/java/org/apache/xml/security/staxutils/AbstractDOMStreamReader.java
@@ -0,0 +1,361 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.xml.security.staxutils;
+
+import java.util.Collections;
+import java.util.List;
+
+import javax.xml.stream.Location;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+
+/**
+ * Abstract logic for creating XMLStreamReader from DOM documents. Its works
+ * using adapters for Element, Node and Attribute.
+ */
+public abstract class AbstractDOMStreamReader<T, I> implements XMLStreamReader {
+ protected int currentEvent = XMLStreamConstants.START_DOCUMENT;
+
+ private FastStack<ElementFrame<T, I>> frames = new FastStack<>();
+
+ private ElementFrame<T, I> frame;
+
+
+ /**
+ *
+ */
+ public static class ElementFrame<T, I> {
+ T element;
+ I currentChild;
+
+ boolean started;
+ boolean ended;
+
+ List<String> uris;
+ List<String> prefixes;
+ List<Object> attributes;
+
+ final ElementFrame<T, I> parent;
+
+ public ElementFrame(T element, ElementFrame<T, I> parent) {
+ this.element = element;
+ this.parent = parent;
+ }
+
+ public ElementFrame(T element, ElementFrame<T, I> parent, I ch) {
+ this.element = element;
+ this.parent = parent;
+ this.currentChild = ch;
+ }
+ public ElementFrame(T doc, boolean s) {
+ this.element = doc;
+ parent = null;
+ started = s;
+ attributes = Collections.emptyList();
+ prefixes = Collections.emptyList();
+ uris = Collections.emptyList();
+ }
+ public ElementFrame(T doc) {
+ this(doc, true);
+ }
+ public T getElement() {
+ return element;
+ }
+
+ public I getCurrentChild() {
+ return currentChild;
+ }
+ public void setCurrentChild(I o) {
+ currentChild = o;
+ }
+ public boolean isDocument() {
+ return false;
+ }
+ public boolean isDocumentFragment() {
+ return false;
+ }
+ }
+
+ /**
+ * @param frame
+ */
+ public AbstractDOMStreamReader(ElementFrame<T, I> frame) {
+ this.frame = frame;
+ frames.push(this.frame);
+ }
+
+ protected ElementFrame<T, I> getCurrentFrame() {
+ return frame;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.xml.stream.XMLStreamReader#getProperty(java.lang.String)
+ */
+ public Object getProperty(String key) throws IllegalArgumentException {
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.xml.stream.XMLStreamReader#next()
+ */
+ public int next() throws XMLStreamException {
+ if (frame.ended) {
+ frames.pop();
+ if (!frames.empty()) {
+ frame = frames.peek();
+ } else {
+ currentEvent = END_DOCUMENT;
+ return currentEvent;
+ }
+ }
+
+ if (!frame.started) {
+ frame.started = true;
+ currentEvent = frame.isDocument() ? START_DOCUMENT : START_ELEMENT;
+ } else if (hasMoreChildren()) {
+ currentEvent = nextChild();
+
+ if (currentEvent == START_ELEMENT) {
+ ElementFrame<T, I> newFrame = getChildFrame();
+ newFrame.started = true;
+ frame = newFrame;
+ frames.push(this.frame);
+ currentEvent = START_ELEMENT;
+
+ newFrame(newFrame);
+ }
+ } else {
+ frame.ended = true;
+ if (frame.isDocument()) {
+ currentEvent = END_DOCUMENT;
+ } else {
+ currentEvent = END_ELEMENT;
+ endElement();
+ }
+ }
+ return currentEvent;
+ }
+
+ protected void newFrame(ElementFrame<T, I> newFrame) {
+ }
+
+ protected void endElement() {
+ }
+
+ protected abstract boolean hasMoreChildren();
+ protected abstract int nextChild();
+ protected abstract ElementFrame<T, I> getChildFrame();
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.xml.stream.XMLStreamReader#require(int, java.lang.String,
+ * java.lang.String)
+ */
+ public void require(int arg0, String arg1, String arg2) throws XMLStreamException {
+ throw new UnsupportedOperationException();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.xml.stream.XMLStreamReader#getElementText()
+ */
+ public abstract String getElementText() throws XMLStreamException;
+
+ public void consumeFrame() {
+ frame.started = true;
+ frame.ended = true;
+ if (frame.isDocument()) {
+ currentEvent = END_DOCUMENT;
+ } else {
+ currentEvent = END_ELEMENT;
+ endElement();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.xml.stream.XMLStreamReader#nextTag()
+ */
+ public int nextTag() throws XMLStreamException {
+ while (hasNext()) {
+ if (START_ELEMENT == next()) {
+ return START_ELEMENT;
+ }
+ }
+
+ return currentEvent;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.xml.stream.XMLStreamReader#hasNext()
+ */
+ public boolean hasNext() throws XMLStreamException {
+
+ return !(frame.ended && (frames.isEmpty() || frame.isDocumentFragment()));
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.xml.stream.XMLStreamReader#close()
+ */
+ public void close() throws XMLStreamException {
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.xml.stream.XMLStreamReader#getNamespaceURI(java.lang.String)
+ */
+ public abstract String getNamespaceURI(String prefix);
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.xml.stream.XMLStreamReader#isStartElement()
+ */
+ public boolean isStartElement() {
+ return currentEvent == START_ELEMENT;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.xml.stream.XMLStreamReader#isEndElement()
+ */
+ public boolean isEndElement() {
+ return currentEvent == END_ELEMENT;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.xml.stream.XMLStreamReader#isCharacters()
+ */
+ public boolean isCharacters() {
+ return currentEvent == CHARACTERS;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.xml.stream.XMLStreamReader#isWhiteSpace()
+ */
+ public boolean isWhiteSpace() {
+ if (currentEvent == CHARACTERS || currentEvent == CDATA) {
+ String text = getText();
+ int len = text.length();
+ for (int i = 0; i < len; ++i) {
+ if (text.charAt(i) > 0x0020) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return currentEvent == SPACE;
+ }
+
+ public int getEventType() {
+ return currentEvent;
+ }
+
+ public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length)
+ throws XMLStreamException {
+ char[] src = getText().toCharArray();
+
+ if (sourceStart + length >= src.length) {
+ length = src.length - sourceStart;
+ }
+
+ for (int i = 0; i < length; i++) {
+ target[targetStart + i] = src[i + sourceStart];
+ }
+
+ return length;
+ }
+
+ public boolean hasText() {
+ return currentEvent == CHARACTERS || currentEvent == DTD || currentEvent == ENTITY_REFERENCE
+ || currentEvent == COMMENT || currentEvent == SPACE;
+ }
+
+ public String getSystemId() {
+ return null;
+ }
+ public String getPublicId() {
+ return null;
+ }
+ public Location getLocation() {
+ return new Location() {
+
+ public int getCharacterOffset() {
+ return 0;
+ }
+
+ public int getColumnNumber() {
+ return 0;
+ }
+
+ public int getLineNumber() {
+ return 0;
+ }
+
+ public String getPublicId() {
+ return AbstractDOMStreamReader.this.getPublicId();
+ }
+
+ public String getSystemId() {
+ return AbstractDOMStreamReader.this.getSystemId();
+ }
+
+ };
+ }
+
+ public boolean hasName() {
+ return currentEvent == START_ELEMENT || currentEvent == END_ELEMENT;
+ }
+
+ public String getVersion() {
+ return null;
+ }
+
+ public boolean isStandalone() {
+ return false;
+ }
+
+ public boolean standaloneSet() {
+ return false;
+ }
+
+ public String getCharacterEncodingScheme() {
+ return null;
+ }
+}
diff --git a/src/main/java/org/apache/xml/security/staxutils/DOMUtils.java b/src/main/java/org/apache/xml/security/staxutils/DOMUtils.java
new file mode 100644
index 0000000..a833a62
--- /dev/null
+++ b/src/main/java/org/apache/xml/security/staxutils/DOMUtils.java
@@ -0,0 +1,142 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.xml.security.staxutils;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Collections;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+
+/**
+ * Few simple utils to read DOM. This is originally from the Jakarta Commons Modeler.
+ */
+public final class DOMUtils {
+ private static final Map<ClassLoader, DocumentBuilder> DOCUMENT_BUILDERS
+ = Collections.synchronizedMap(new WeakHashMap<ClassLoader, DocumentBuilder>());
+ private static final Map<ClassLoader, DocumentBuilder> DOCUMENT_BUILDERS_DISALLOW_DOCTYPE
+ = Collections.synchronizedMap(new WeakHashMap<ClassLoader, DocumentBuilder>());
+
+ private DOMUtils() {
+ }
+
+ private static DocumentBuilder getDocumentBuilder(boolean disAllowDocTypeDeclarations) throws ParserConfigurationException {
+ ClassLoader loader = getContextClassLoader();
+ if (loader == null) {
+ loader = getClassLoader(DOMUtils.class);
+ }
+ if (loader == null) {
+ DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
+ f.setNamespaceAware(true);
+ f.setFeature(javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING, true);
+ f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", disAllowDocTypeDeclarations);
+ return f.newDocumentBuilder();
+ }
+ DocumentBuilder factory =
+ disAllowDocTypeDeclarations ? DOCUMENT_BUILDERS_DISALLOW_DOCTYPE.get(loader) : DOCUMENT_BUILDERS.get(loader);
+ if (factory == null) {
+ DocumentBuilderFactory f2 = DocumentBuilderFactory.newInstance();
+ f2.setNamespaceAware(true);
+ f2.setFeature(javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING, true);
+ f2.setFeature("http://apache.org/xml/features/disallow-doctype-decl", disAllowDocTypeDeclarations);
+ factory = f2.newDocumentBuilder();
+ if (disAllowDocTypeDeclarations) {
+ DOCUMENT_BUILDERS_DISALLOW_DOCTYPE.put(loader, factory);
+ } else {
+ DOCUMENT_BUILDERS.put(loader, factory);
+ }
+ }
+ return factory;
+ }
+
+ private static ClassLoader getContextClassLoader() {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+ public ClassLoader run() {
+ return Thread.currentThread().getContextClassLoader();
+ }
+ });
+ }
+ return Thread.currentThread().getContextClassLoader();
+ }
+
+ private static ClassLoader getClassLoader(final Class<?> clazz) {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+ public ClassLoader run() {
+ return clazz.getClassLoader();
+ }
+ });
+ }
+ return clazz.getClassLoader();
+ }
+
+ /**
+ * Creates a new Document object
+ * @throws ParserConfigurationException
+ */
+ public static Document newDocument(boolean disAllowDocTypeDeclarations) {
+ try {
+ return getDocumentBuilder(disAllowDocTypeDeclarations).newDocument();
+ } catch (ParserConfigurationException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Get the raw text content of a node or null if there is no text
+ */
+ public static String getRawContent(Node n) {
+ if (n == null) {
+ return null;
+ }
+ StringBuilder b = null;
+ String s = null;
+ Node n1 = n.getFirstChild();
+ while (n1 != null) {
+ if (n1.getNodeType() == Node.TEXT_NODE || n1.getNodeType() == Node.CDATA_SECTION_NODE) {
+ if (b != null) {
+ b.append(((Text)n1).getNodeValue());
+ } else if (s == null) {
+ s = ((Text)n1).getNodeValue();
+ } else {
+ b = new StringBuilder(s).append(((Text)n1).getNodeValue());
+ s = null;
+ }
+ }
+ n1 = n1.getNextSibling();
+ }
+ if (b != null) {
+ return b.toString();
+ }
+ return s;
+ }
+
+}
diff --git a/src/main/java/org/apache/xml/security/staxutils/DepthExceededStaxException.java b/src/main/java/org/apache/xml/security/staxutils/DepthExceededStaxException.java
new file mode 100644
index 0000000..5886a20
--- /dev/null
+++ b/src/main/java/org/apache/xml/security/staxutils/DepthExceededStaxException.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.xml.security.staxutils;
+
+public class DepthExceededStaxException extends RuntimeException {
+
+ private static final long serialVersionUID = 4750070687283463619L;
+
+ public DepthExceededStaxException() {
+
+ }
+
+ public DepthExceededStaxException(String message) {
+ super(message);
+ }
+
+}
diff --git a/src/main/java/org/apache/xml/security/staxutils/DepthRestrictingStreamReader.java b/src/main/java/org/apache/xml/security/staxutils/DepthRestrictingStreamReader.java
new file mode 100644
index 0000000..6e493ae
--- /dev/null
+++ b/src/main/java/org/apache/xml/security/staxutils/DepthRestrictingStreamReader.java
@@ -0,0 +1,84 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.xml.security.staxutils;
+
+import java.util.Stack;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+/**
+ * XMLStreamReader implementation which can be used to enforce a number of
+ * depth-restricting policies. The following properties are currently supported:
+ * - total number of elements in the document
+ * - the maximum depth of the given element; the root element will be checked by default
+ * - the maximum number of immediate child nodes for individual elements
+ *
+ * More sophisticated policies can be supported in the future.
+ */
+public class DepthRestrictingStreamReader extends DepthXMLStreamReader {
+
+ private DocumentDepthProperties props;
+ private int totalElementCount;
+ private Stack<Integer> stack = new Stack<>();
+
+ public DepthRestrictingStreamReader(XMLStreamReader reader,
+ int elementCountThreshold,
+ int innerElementLevelThreshold,
+ int innerElementCountThreshold) {
+ this(reader, new DocumentDepthProperties(elementCountThreshold,
+ innerElementLevelThreshold,
+ innerElementCountThreshold));
+ }
+
+ public DepthRestrictingStreamReader(XMLStreamReader reader,
+ DocumentDepthProperties props) {
+ super(reader);
+ this.props = props;
+ }
+
+ @Override
+ public int next() throws XMLStreamException {
+ int next = super.next();
+ if (next == START_ELEMENT) {
+ if (props.getInnerElementLevelThreshold() != -1
+ && getDepth() >= props.getInnerElementLevelThreshold()) {
+ throw new DepthExceededStaxException();
+ }
+ if (props.getElementCountThreshold() != -1
+ && ++totalElementCount >= props.getElementCountThreshold()) {
+ throw new DepthExceededStaxException();
+ }
+ if (props.getInnerElementCountThreshold() != -1) {
+ if (!stack.empty()) {
+ int currentCount = stack.pop();
+ if (++currentCount >= props.getInnerElementCountThreshold()) {
+ throw new DepthExceededStaxException();
+ }
+ stack.push(currentCount);
+ }
+ stack.push(0);
+ }
+
+ } else if (next == END_ELEMENT && props.getInnerElementCountThreshold() != -1) {
+ stack.pop();
+ }
+ return next;
+ }
+}
diff --git a/src/main/java/org/apache/xml/security/staxutils/DepthXMLStreamReader.java b/src/main/java/org/apache/xml/security/staxutils/DepthXMLStreamReader.java
new file mode 100644
index 0000000..3d7f14c
--- /dev/null
+++ b/src/main/java/org/apache/xml/security/staxutils/DepthXMLStreamReader.java
@@ -0,0 +1,266 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.xml.security.staxutils;
+
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import javax.xml.stream.Location;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+public class DepthXMLStreamReader implements XMLStreamReader {
+
+ protected XMLStreamReader reader;
+ private int depth;
+
+ public DepthXMLStreamReader(XMLStreamReader r) {
+ this.reader = r;
+ }
+
+ public XMLStreamReader getReader() {
+ return this.reader;
+ }
+
+ public int getDepth() {
+ return depth;
+ }
+
+ public void close() throws XMLStreamException {
+ reader.close();
+ }
+
+ public int getAttributeCount() {
+ return reader.getAttributeCount();
+ }
+
+ public String getAttributeLocalName(int arg0) {
+ return reader.getAttributeLocalName(arg0);
+ }
+
+ public QName getAttributeName(int arg0) {
+ return reader.getAttributeName(arg0);
+ }
+
+ public String getAttributeNamespace(int arg0) {
+ return reader.getAttributeNamespace(arg0);
+ }
+
+ public String getAttributePrefix(int arg0) {
+ return reader.getAttributePrefix(arg0);
+ }
+
+ public String getAttributeType(int arg0) {
+ return reader.getAttributeType(arg0);
+ }
+
+ public String getAttributeValue(int arg0) {
+ return reader.getAttributeValue(arg0);
+ }
+
+ public String getAttributeValue(String namespace, String localName) {
+ return reader.getAttributeValue(namespace, localName);
+ }
+
+ public String getCharacterEncodingScheme() {
+ return reader.getCharacterEncodingScheme();
+ }
+
+ public String getElementText() throws XMLStreamException {
+ String ret = reader.getElementText();
+ //workaround bugs in some readers that aren't properly advancing to
+ //the END_ELEMENT (*cough*jettison*cough*)
+ while (reader.getEventType() != XMLStreamConstants.END_ELEMENT) {
+ reader.next();
+ }
+ depth--;
+ return ret;
+ }
+
+ public String getEncoding() {
+ return reader.getEncoding();
+ }
+
+ public int getEventType() {
+ return reader.getEventType();
+ }
+
+ public String getLocalName() {
+ return reader.getLocalName();
+ }
+
+ public Location getLocation() {
+ return reader.getLocation();
+ }
+
+ public QName getName() {
+ return reader.getName();
+ }
+
+ public NamespaceContext getNamespaceContext() {
+ return reader.getNamespaceContext();
+ }
+
+ public int getNamespaceCount() {
+ return reader.getNamespaceCount();
+ }
+
+ public String getNamespacePrefix(int arg0) {
+ return reader.getNamespacePrefix(arg0);
+ }
+
+ public String getNamespaceURI() {
+ return reader.getNamespaceURI();
+ }
+
+ public String getNamespaceURI(int arg0) {
+
+ return reader.getNamespaceURI(arg0);
+ }
+
+ public String getNamespaceURI(String arg0) {
+ return reader.getNamespaceURI(arg0);
+ }
+
+ public String getPIData() {
+ return reader.getPIData();
+ }
+
+ public String getPITarget() {
+ return reader.getPITarget();
+ }
+
+ public String getPrefix() {
+ return reader.getPrefix();
+ }
+
+ public Object getProperty(String arg0) throws IllegalArgumentException {
+
+ return reader.getProperty(arg0);
+ }
+
+ public String getText() {
+ return reader.getText();
+ }
+
+ public char[] getTextCharacters() {
+ return reader.getTextCharacters();
+ }
+
+ public int getTextCharacters(int arg0, char[] arg1, int arg2, int arg3) throws XMLStreamException {
+ return reader.getTextCharacters(arg0, arg1, arg2, arg3);
+ }
+
+ public int getTextLength() {
+ return reader.getTextLength();
+ }
+
+ public int getTextStart() {
+ return reader.getTextStart();
+ }
+
+ public String getVersion() {
+ return reader.getVersion();
+ }
+
+ public boolean hasName() {
+ return reader.hasName();
+ }
+
+ public boolean hasNext() throws XMLStreamException {
+ return reader.hasNext();
+ }
+
+ public boolean hasText() {
+ return reader.hasText();
+ }
+
+ public boolean isAttributeSpecified(int arg0) {
+ return reader.isAttributeSpecified(arg0);
+ }
+
+ public boolean isCharacters() {
+ return reader.isCharacters();
+ }
+
+ public boolean isEndElement() {
+ return reader.isEndElement();
+ }
+
+ public boolean isStandalone() {
+ return reader.isStandalone();
+ }
+
+ public boolean isStartElement() {
+ return reader.isStartElement();
+ }
+
+ public boolean isWhiteSpace() {
+ return reader.isWhiteSpace();
+ }
+
+ public int next() throws XMLStreamException {
+ int next = reader.next();
+
+ if (next == START_ELEMENT) {
+ depth++;
+ } else if (next == END_ELEMENT) {
+ depth--;
+ }
+
+ return next;
+ }
+
+ public int nextTag() throws XMLStreamException {
+ int eventType = next();
+ while (eventType == XMLStreamConstants.CHARACTERS && isWhiteSpace()
+ || eventType == XMLStreamConstants.CDATA && isWhiteSpace()
+ // skip whitespace
+ || eventType == XMLStreamConstants.SPACE
+ || eventType == XMLStreamConstants.PROCESSING_INSTRUCTION
+ || eventType == XMLStreamConstants.COMMENT) {
+ eventType = next();
+ }
+ if (eventType != XMLStreamConstants.START_ELEMENT && eventType != XMLStreamConstants.END_ELEMENT) {
+ throw new XMLStreamException("expected start or end tag", getLocation());
+ }
+ return eventType;
+ }
+
+ public void require(int arg0, String arg1, String arg2) throws XMLStreamException {
+ reader.require(arg0, arg1, arg2);
+ }
+
+ public boolean standaloneSet() {
+ return reader.standaloneSet();
+ }
+
+ public int hashCode() {
+ return reader.hashCode();
+ }
+
+ public boolean equals(Object arg0) {
+ return reader.equals(arg0);
+ }
+
+ public String toString() {
+ return reader.toString();
+ }
+}
diff --git a/src/main/java/org/apache/xml/security/staxutils/DocumentDepthProperties.java b/src/main/java/org/apache/xml/security/staxutils/DocumentDepthProperties.java
new file mode 100644
index 0000000..cdd9f4b
--- /dev/null
+++ b/src/main/java/org/apache/xml/security/staxutils/DocumentDepthProperties.java
@@ -0,0 +1,64 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.xml.security.staxutils;
+
+public class DocumentDepthProperties {
+
+ public static final String TOTAL_ELEMENT_COUNT = "depthTotalElementCountThreshold";
+ public static final String INNER_ELEMENT_COUNT = "depthInnerElementCountThreshold";
+ public static final String INNER_ELEMENT_LEVEL = "depthInnerElementLevelThreshold";
+
+ private int elementCountThreshold = -1;
+ private int innerElementLevelThreshold = -1;
+ private int innerElementCountThreshold = -1;
+ public DocumentDepthProperties() {
+
+ }
+ public DocumentDepthProperties(int elementCountThreshold,
+ int innerElementLevelThreshold,
+ int innerElementCountThreshold) {
+ this.elementCountThreshold = elementCountThreshold;
+ this.innerElementLevelThreshold = innerElementLevelThreshold;
+ this.innerElementCountThreshold = innerElementCountThreshold;
+ }
+
+ public boolean isEffective() {
+ return elementCountThreshold != -1 || innerElementLevelThreshold != -1
+ || innerElementCountThreshold != -1;
+ }
+
+ public void setElementCountThreshold(int elementCountThreshold) {
+ this.elementCountThreshold = elementCountThreshold;
+ }
+ public int getElementCountThreshold() {
+ return elementCountThreshold;
+ }
+ public void setInnerElementLevelThreshold(int innerElementLevelThreshold) {
+ this.innerElementLevelThreshold = innerElementLevelThreshold;
+ }
+ public int getInnerElementLevelThreshold() {
+ return innerElementLevelThreshold;
+ }
+ public void setInnerElementCountThreshold(int innerElementCountThreshold) {
+ this.innerElementCountThreshold = innerElementCountThreshold;
+ }
+ public int getInnerElementCountThreshold() {
+ return innerElementCountThreshold;
+ }
+}
diff --git a/src/main/java/org/apache/xml/security/staxutils/FastStack.java b/src/main/java/org/apache/xml/security/staxutils/FastStack.java
new file mode 100644
index 0000000..8a48a3d
--- /dev/null
+++ b/src/main/java/org/apache/xml/security/staxutils/FastStack.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.xml.security.staxutils;
+
+import java.util.ArrayList;
+import java.util.EmptyStackException;
+
+public class FastStack<T> extends ArrayList<T> {
+ private static final long serialVersionUID = -6459503295618120689L;
+
+ public void push(T o) {
+ add(o);
+ }
+
+ public T pop() {
+ if (empty()) {
+ throw new EmptyStackException();
+ }
+
+ return remove(size() - 1);
+ }
+
+ public boolean empty() {
+ return size() == 0;
+ }
+
+ public T peek() {
+ if (empty()) {
+ throw new EmptyStackException();
+ }
+
+ return get(size() - 1);
+ }
+}
diff --git a/src/main/java/org/apache/xml/security/staxutils/StaxUtils.java b/src/main/java/org/apache/xml/security/staxutils/StaxUtils.java
new file mode 100644
index 0000000..756f6e9
--- /dev/null
+++ b/src/main/java/org/apache/xml/security/staxutils/StaxUtils.java
@@ -0,0 +1,592 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.xml.security.staxutils;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.util.Stack;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.stream.Location;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLResolver;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.transform.Source;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.stax.StAXSource;
+import javax.xml.transform.stream.StreamSource;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.UserDataHandler;
+import org.xml.sax.InputSource;
+
+public final class StaxUtils {
+
+ private static final org.slf4j.Logger LOG =
+ org.slf4j.LoggerFactory.getLogger(StaxUtils.class);
+
+ private static final String XML_NS = "http://www.w3.org/2000/xmlns/";
+
+ private static final BlockingQueue<XMLInputFactory> DISALLOW_DOCTYPE_INPUT_FACTORY_POOL = new ArrayBlockingQueue<>(20);
+ private static final BlockingQueue<XMLInputFactory> ALLOW_DOCTYPE_INPUT_FACTORY_POOL = new ArrayBlockingQueue<>(20);
+
+ private StaxUtils() {
+ }
+
+ /**
+ * Return a cached, namespace-aware, factory.
+ */
+ private static XMLInputFactory getXMLInputFactory(boolean disAllowDocTypeDeclarations) {
+ XMLInputFactory f = disAllowDocTypeDeclarations
+ ? DISALLOW_DOCTYPE_INPUT_FACTORY_POOL.poll() : ALLOW_DOCTYPE_INPUT_FACTORY_POOL.poll();
+ if (f == null) {
+ f = createXMLInputFactory(disAllowDocTypeDeclarations);
+ }
+ return f;
+ }
+
+ private static void returnXMLInputFactory(XMLInputFactory factory, boolean disAllowDocTypeDeclarations) {
+ if (disAllowDocTypeDeclarations) {
+ DISALLOW_DOCTYPE_INPUT_FACTORY_POOL.offer(factory);
+ } else {
+ ALLOW_DOCTYPE_INPUT_FACTORY_POOL.offer(factory);
+ }
+ }
+
+ /**
+ * Return a new factory so that the caller can set sticky parameters.
+ * @param disAllowDocTypeDeclarations
+ * @throws XMLStreamException
+ */
+ private static XMLInputFactory createXMLInputFactory(boolean disAllowDocTypeDeclarations) {
+ XMLInputFactory factory = null;
+ try {
+ factory = XMLInputFactory.newInstance();
+ } catch (Throwable t) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("XMLInputFactory.newInstance() failed with: ", t);
+ }
+ throw new RuntimeException("Failed to create XMLInputFactory.");
+ }
+
+ setProperty(factory, XMLInputFactory.IS_NAMESPACE_AWARE, true);
+
+ if (disAllowDocTypeDeclarations) {
+ setProperty(factory, XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
+ setProperty(factory, XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, Boolean.FALSE);
+ setProperty(factory, XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE);
+ factory.setXMLResolver(new XMLResolver() {
+ public Object resolveEntity(String publicID, String systemID,
+ String baseURI, String namespace)
+ throws XMLStreamException {
+ throw new XMLStreamException("Reading external entities is disabled");
+ }
+ });
+ }
+
+ return factory;
+ }
+
+ private static boolean setProperty(XMLInputFactory f, String p, Object o) {
+ try {
+ f.setProperty(p, o);
+ return true;
+ } catch (Throwable t) {
+ //ignore
+ }
+ return false;
+ }
+
+ public static Document read(Source s, boolean disAllowDocTypeDeclarations) throws XMLStreamException {
+ XMLStreamReader reader = createXMLStreamReader(s, disAllowDocTypeDeclarations);
+ try {
+ return read(reader);
+ } finally {
+ try {
+ reader.close();
+ } catch (Exception ex) {
+ //ignore
+ }
+ }
+ }
+ public static Document read(InputStream s, boolean disAllowDocTypeDeclarations) throws XMLStreamException {
+ XMLStreamReader reader = createXMLStreamReader(s, disAllowDocTypeDeclarations);
+ try {
+ return read(reader);
+ } finally {
+ try {
+ reader.close();
+ } catch (Exception ex) {
+ //ignore
+ }
+ }
+ }
+ public static Document read(Reader s, boolean disAllowDocTypeDeclarations) throws XMLStreamException {
+ XMLStreamReader reader = createXMLStreamReader(s, disAllowDocTypeDeclarations);
+ try {
+ return read(reader);
+ } finally {
+ try {
+ reader.close();
+ } catch (Exception ex) {
+ //ignore
+ }
+ }
+ }
+ public static Document read(File is, boolean disAllowDocTypeDeclarations) throws XMLStreamException, IOException {
+ try (InputStream fin = Files.newInputStream(is.toPath())) {
+ return read(fin, disAllowDocTypeDeclarations);
+ }
+ }
+ public static Document read(InputSource s, boolean disAllowDocTypeDeclarations) throws XMLStreamException {
+ XMLStreamReader reader = createXMLStreamReader(s, disAllowDocTypeDeclarations);
+ try {
+ return read(reader);
+ } finally {
+ try {
+ reader.close();
+ } catch (Exception ex) {
+ //ignore
+ }
+ }
+ }
+ public static Document read(XMLStreamReader reader) throws XMLStreamException {
+ return read(reader, false);
+ }
+ public static Document read(XMLStreamReader reader, boolean recordLoc) throws XMLStreamException {
+ Document doc = DOMUtils.newDocument(true);
+ if (reader.getLocation().getSystemId() != null) {
+ try {
+ doc.setDocumentURI(reader.getLocation().getSystemId());
+ } catch (Exception e) {
+ //ignore - probably not DOM level 3
+ }
+ }
+ readDocElements(doc, doc, reader, true, recordLoc);
+ return doc;
+ }
+
+ public static Document read(DocumentBuilder builder, XMLStreamReader reader, boolean repairing)
+ throws XMLStreamException {
+
+ Document doc = builder == null ? DOMUtils.newDocument(true) : builder.newDocument();
+ if (reader.getLocation().getSystemId() != null) {
+ try {
+ doc.setDocumentURI(reader.getLocation().getSystemId());
+ } catch (Exception e) {
+ //ignore - probably not DOM level 3
+ }
+ }
+ readDocElements(doc, reader, repairing);
+ return doc;
+ }
+
+ /**
+ * @param parent
+ */
+ private static Document getDocument(Node parent) {
+ return parent instanceof Document ? (Document)parent : parent.getOwnerDocument();
+ }
+
+ private static boolean isDeclared(Element e, String namespaceURI, String prefix) {
+ while (e != null) {
+ Attr att;
+ if (prefix != null && prefix.length() > 0) {
+ att = e.getAttributeNodeNS(XML_NS, prefix);
+ } else {
+ att = e.getAttributeNode("xmlns");
+ }
+
+ if (att != null && att.getNodeValue().equals(namespaceURI)) {
+ return true;
+ }
+
+ if (e.getParentNode() instanceof Element) {
+ e = (Element)e.getParentNode();
+ } else if (isEmpty(prefix) && isEmpty(namespaceURI)) {
+ //A document that probably doesn't have any namespace qualifies elements
+ return true;
+ } else {
+ e = null;
+ }
+ }
+ return false;
+ }
+
+ public static void readDocElements(Node parent, XMLStreamReader reader, boolean repairing)
+ throws XMLStreamException {
+ Document doc = getDocument(parent);
+ readDocElements(doc, parent, reader, repairing, false);
+ }
+
+ public static void readDocElements(Node parent, XMLStreamReader reader, boolean repairing,
+ boolean isThreshold)
+ throws XMLStreamException {
+ Document doc = getDocument(parent);
+ readDocElements(doc, parent, reader, repairing, false, isThreshold);
+ }
+
+ /**
+ * @param parent
+ * @param reader
+ * @throws XMLStreamException
+ */
+ public static void readDocElements(Document doc, Node parent,
+ XMLStreamReader reader, boolean repairing, boolean recordLoc)
+ throws XMLStreamException {
+ readDocElements(doc, parent, reader, repairing, recordLoc, false);
+ }
+
+ /**
+ * @param parent
+ * @param reader
+ * @throws XMLStreamException
+ */
+ public static void readDocElements(Document doc, Node parent,
+ XMLStreamReader reader, boolean repairing, boolean recordLoc,
+ boolean isThreshold)
+ throws XMLStreamException {
+ Stack<Node> stack = new Stack<Node>();
+ int event = reader.getEventType();
+ while (reader.hasNext()) {
+ switch (event) {
+ case XMLStreamConstants.START_ELEMENT: {
+ Element e;
+ if (!isEmpty(reader.getPrefix())) {
+ e = doc.createElementNS(reader.getNamespaceURI(),
+ reader.getPrefix() + ":" + reader.getLocalName());
+ } else {
+ e = doc.createElementNS(reader.getNamespaceURI(), reader.getLocalName());
+ }
+ e = (Element)parent.appendChild(e);
+ recordLoc = addLocation(doc, e, reader, recordLoc);
+
+ for (int ns = 0; ns < reader.getNamespaceCount(); ns++) {
+ String uri = reader.getNamespaceURI(ns);
+ String prefix = reader.getNamespacePrefix(ns);
+
+ declare(e, uri, prefix);
+ }
+
+ for (int att = 0; att < reader.getAttributeCount(); att++) {
+ String name = reader.getAttributeLocalName(att);
+ String prefix = reader.getAttributePrefix(att);
+ if (prefix != null && prefix.length() > 0) {
+ name = prefix + ":" + name;
+ }
+
+ Attr attr = doc.createAttributeNS(reader.getAttributeNamespace(att), name);
+ attr.setValue(reader.getAttributeValue(att));
+ e.setAttributeNode(attr);
+ }
+
+ if (repairing && !isDeclared(e, reader.getNamespaceURI(), reader.getPrefix())) {
+ declare(e, reader.getNamespaceURI(), reader.getPrefix());
+ }
+ stack.push(parent);
+ parent = e;
+ break;
+ }
+ case XMLStreamConstants.END_ELEMENT:
+ if (stack.isEmpty()) {
+ return;
+ }
+ parent = stack.pop();
+ //if (parent instanceof Document || parent instanceof DocumentFragment) {
+ // return;
+ //}
+ break;
+ case XMLStreamConstants.NAMESPACE:
+ break;
+ case XMLStreamConstants.ATTRIBUTE:
+ break;
+ case XMLStreamConstants.CHARACTERS:
+ if (parent != null) {
+ recordLoc = addLocation(doc,
+ parent.appendChild(doc.createTextNode(reader.getText())),
+ reader, recordLoc);
+ }
+ break;
+ case XMLStreamConstants.COMMENT:
+ if (parent != null) {
+ parent.appendChild(doc.createComment(reader.getText()));
+ }
+ break;
+ case XMLStreamConstants.CDATA:
+ recordLoc = addLocation(doc,
+ parent.appendChild(doc.createCDATASection(reader.getText())),
+ reader, recordLoc);
+ break;
+ case XMLStreamConstants.PROCESSING_INSTRUCTION:
+ parent.appendChild(doc.createProcessingInstruction(reader.getPITarget(), reader.getPIData()));
+ break;
+ case XMLStreamConstants.ENTITY_REFERENCE:
+ parent.appendChild(doc.createProcessingInstruction(reader.getPITarget(), reader.getPIData()));
+ break;
+ default:
+ break;
+ }
+
+ if (reader.hasNext()) {
+ event = reader.next();
+ }
+ }
+ }
+
+ private static boolean addLocation(Document doc, Node node,
+ Location loc,
+ boolean recordLoc) {
+ if (recordLoc && loc != null && (loc.getColumnNumber() != 0 || loc.getLineNumber() != 0)) {
+ try {
+ final int charOffset = loc.getCharacterOffset();
+ final int colNum = loc.getColumnNumber();
+ final int linNum = loc.getLineNumber();
+ final String pubId = loc.getPublicId() == null ? doc.getDocumentURI() : loc.getPublicId();
+ final String sysId = loc.getSystemId() == null ? doc.getDocumentURI() : loc.getSystemId();
+ Location loc2 = new Location() {
+ public int getCharacterOffset() {
+ return charOffset;
+ }
+ public int getColumnNumber() {
+ return colNum;
+ }
+ public int getLineNumber() {
+ return linNum;
+ }
+ public String getPublicId() {
+ return pubId;
+ }
+ public String getSystemId() {
+ return sysId;
+ }
+ };
+ node.setUserData("location", loc2, LocationUserDataHandler.INSTANCE);
+ } catch (Throwable ex) {
+ //possibly not DOM level 3, won't be able to record this then
+ return false;
+ }
+ }
+ return recordLoc;
+ }
+
+ private static boolean addLocation(Document doc, Node node,
+ XMLStreamReader reader,
+ boolean recordLoc) {
+ return addLocation(doc, node, reader.getLocation(), recordLoc);
+ }
+
+ private static class LocationUserDataHandler implements UserDataHandler {
+ public static final LocationUserDataHandler INSTANCE = new LocationUserDataHandler();
+
+ public void handle(short operation, String key, Object data, Node src, Node dst) {
+ if (operation == NODE_CLONED) {
+ dst.setUserData(key, data, this);
+ }
+ }
+ }
+
+ private static void declare(Element node, String uri, String prefix) {
+ String qualname;
+ if (prefix != null && prefix.length() > 0) {
+ qualname = "xmlns:" + prefix;
+ } else {
+ qualname = "xmlns";
+ }
+ Attr attr = node.getOwnerDocument().createAttributeNS(XML_NS, qualname);
+ attr.setValue(uri);
+ node.setAttributeNodeNS(attr);
+ }
+
+ public static XMLStreamReader createXMLStreamReader(InputSource src, boolean disAllowDocTypeDeclarations) {
+ String sysId = src.getSystemId() == null ? null : src.getSystemId();
+ String pubId = src.getPublicId() == null ? null : src.getPublicId();
+ if (src.getByteStream() != null) {
+ if (src.getEncoding() == null) {
+ StreamSource ss = new StreamSource(src.getByteStream(), sysId);
+ ss.setPublicId(pubId);
+ return createXMLStreamReader(ss, disAllowDocTypeDeclarations);
+ }
+ return createXMLStreamReader(src.getByteStream(), src.getEncoding(), disAllowDocTypeDeclarations);
+ } else if (src.getCharacterStream() != null) {
+ StreamSource ss = new StreamSource(src.getCharacterStream(), sysId);
+ ss.setPublicId(pubId);
+ return createXMLStreamReader(ss, disAllowDocTypeDeclarations);
+ } else {
+ try {
+ URL url = new URL(sysId);
+ StreamSource ss = new StreamSource(url.openStream(), sysId);
+ ss.setPublicId(pubId);
+ return createXMLStreamReader(ss, disAllowDocTypeDeclarations);
+ } catch (Exception ex) {
+ //ignore - not a valid URL
+ }
+ }
+ throw new IllegalArgumentException("InputSource must have a ByteStream or CharacterStream");
+ }
+ /**
+ * @param in
+ * @param encoding
+ */
+ public static XMLStreamReader createXMLStreamReader(InputStream in, String encoding, boolean disAllowDocTypeDeclarations) {
+ if (encoding == null) {
+ encoding = StandardCharsets.UTF_8.name();
+ }
+
+ XMLInputFactory factory = getXMLInputFactory(disAllowDocTypeDeclarations);
+ try {
+ return factory.createXMLStreamReader(in, encoding);
+ } catch (XMLStreamException e) {
+ throw new RuntimeException("Couldn't parse stream.", e);
+ } finally {
+ returnXMLInputFactory(factory, disAllowDocTypeDeclarations);
+ }
+ }
+
+ /**
+ * @param in
+ */
+ public static XMLStreamReader createXMLStreamReader(InputStream in, boolean disAllowDocTypeDeclarations) {
+ XMLInputFactory factory = getXMLInputFactory(disAllowDocTypeDeclarations);
+ try {
+ return factory.createXMLStreamReader(in);
+ } catch (XMLStreamException e) {
+ throw new RuntimeException("Couldn't parse stream.", e);
+ } finally {
+ returnXMLInputFactory(factory, disAllowDocTypeDeclarations);
+ }
+ }
+ public static XMLStreamReader createXMLStreamReader(String systemId, InputStream in, boolean disAllowDocTypeDeclarations) {
+ XMLInputFactory factory = getXMLInputFactory(disAllowDocTypeDeclarations);
+ try {
+ return factory.createXMLStreamReader(systemId, in);
+ } catch (XMLStreamException e) {
+ throw new RuntimeException("Couldn't parse stream.", e);
+ } finally {
+ returnXMLInputFactory(factory, disAllowDocTypeDeclarations);
+ }
+ }
+
+ public static XMLStreamReader createXMLStreamReader(Element el) {
+ return new W3CDOMStreamReader(el);
+ }
+ public static XMLStreamReader createXMLStreamReader(Document doc) {
+ return new W3CDOMStreamReader(doc.getDocumentElement());
+ }
+ public static XMLStreamReader createXMLStreamReader(Element el, String sysId) {
+ return new W3CDOMStreamReader(el, sysId);
+ }
+ public static XMLStreamReader createXMLStreamReader(Document doc, String sysId) {
+ return new W3CDOMStreamReader(doc.getDocumentElement(), sysId);
+ }
+
+ public static XMLStreamReader createXMLStreamReader(Source source, boolean disAllowDocTypeDeclarations) {
+ try {
+ if (source instanceof DOMSource) {
+ DOMSource ds = (DOMSource)source;
+ Node nd = ds.getNode();
+ Element el = null;
+ if (nd instanceof Document) {
+ el = ((Document)nd).getDocumentElement();
+ } else if (nd instanceof Element) {
+ el = (Element)nd;
+ }
+
+ if (null != el) {
+ return new W3CDOMStreamReader(el, source.getSystemId());
+ }
+ } else if (source instanceof StAXSource) {
+ return ((StAXSource)source).getXMLStreamReader();
+ } else if (source instanceof SAXSource) {
+ SAXSource ss = (SAXSource)source;
+ if (ss.getXMLReader() == null) {
+ return createXMLStreamReader(((SAXSource)source).getInputSource(), disAllowDocTypeDeclarations);
+ }
+ }
+
+ XMLInputFactory factory = getXMLInputFactory(disAllowDocTypeDeclarations);
+ try {
+ XMLStreamReader reader = null;
+
+ try {
+ reader = factory.createXMLStreamReader(source);
+ } catch (UnsupportedOperationException e) {
+ //ignore
+ }
+ if (reader == null && source instanceof StreamSource) {
+ //createXMLStreamReader from Source is optional, we'll try and map it
+ StreamSource ss = (StreamSource)source;
+ if (ss.getInputStream() != null) {
+ reader = factory.createXMLStreamReader(ss.getSystemId(),
+ ss.getInputStream());
+ } else {
+ reader = factory.createXMLStreamReader(ss.getSystemId(),
+ ss.getReader());
+ }
+ }
+ return reader;
+ } finally {
+ returnXMLInputFactory(factory, disAllowDocTypeDeclarations);
+ }
+ } catch (XMLStreamException e) {
+ throw new RuntimeException("Couldn't parse stream.", e);
+ }
+ }
+
+ /**
+ * @param reader
+ */
+ public static XMLStreamReader createXMLStreamReader(Reader reader, boolean disAllowDocTypeDeclarations) {
+ XMLInputFactory factory = getXMLInputFactory(disAllowDocTypeDeclarations);
+ try {
+ return factory.createXMLStreamReader(reader);
+ } catch (XMLStreamException e) {
+ throw new RuntimeException("Couldn't parse stream.", e);
+ } finally {
+ returnXMLInputFactory(factory, disAllowDocTypeDeclarations);
+ }
+ }
+
+ private static boolean isEmpty(String str) {
+ if (str != null) {
+ int len = str.length();
+ for (int x = 0; x < len; ++x) {
+ if (str.charAt(x) > ' ') {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+
+}
diff --git a/src/main/java/org/apache/xml/security/staxutils/SystemPropertyAction.java b/src/main/java/org/apache/xml/security/staxutils/SystemPropertyAction.java
new file mode 100644
index 0000000..5757e60
--- /dev/null
+++ b/src/main/java/org/apache/xml/security/staxutils/SystemPropertyAction.java
@@ -0,0 +1,97 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.xml.security.staxutils;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ *
+ */
+public final class SystemPropertyAction implements PrivilegedAction<String> {
+ private static final org.slf4j.Logger LOG =
+ org.slf4j.LoggerFactory.getLogger(SystemPropertyAction.class);
+ private final String property;
+ private final String def;
+ private SystemPropertyAction(String name) {
+ property = name;
+ def = null;
+ }
+ private SystemPropertyAction(String name, String d) {
+ property = name;
+ def = d;
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.PrivilegedAction#run()
+ */
+ public String run() {
+ if (def != null) {
+ return System.getProperty(property, def);
+ }
+ return System.getProperty(property);
+ }
+
+ public static String getProperty(String name) {
+ return AccessController.doPrivileged(new SystemPropertyAction(name));
+ }
+
+ public static String getProperty(String name, String def) {
+ try {
+ return AccessController.doPrivileged(new SystemPropertyAction(name, def));
+ } catch (SecurityException ex) {
+ LOG.debug("SecurityException raised getting property " + name, ex);
+ return def;
+ }
+ }
+
+ /**
+ * Get the system property via the AccessController, but if a SecurityException is
+ * raised, just return null;
+ * @param name
+ */
+ public static String getPropertyOrNull(String name) {
+ try {
+ return AccessController.doPrivileged(new SystemPropertyAction(name));
+ } catch (SecurityException ex) {
+ LOG.debug("SecurityException raised getting property " + name, ex);
+ return null;
+ }
+ }
+
+ /**
+ * Get the integer system property via the AccessController, but if a SecurityException is
+ * raised, just return the default;
+ * @param name - system property name
+ * @param def - the default value if the system property does not exist or cannot be acquired
+ */
+ public static int getInteger(String name, int def) {
+ try {
+ return AccessController.doPrivileged(new PrivilegedAction<Integer>() {
+ @Override
+ public Integer run() {
+ return Integer.getInteger(name, def);
+ } });
+ } catch (SecurityException ex) {
+ LOG.debug("SecurityException raised getting property " + name, ex);
+ return def;
+ }
+ }
+}
diff --git a/src/main/java/org/apache/xml/security/staxutils/W3CDOMStreamReader.java b/src/main/java/org/apache/xml/security/staxutils/W3CDOMStreamReader.java
new file mode 100644
index 0000000..9596d74
--- /dev/null
+++ b/src/main/java/org/apache/xml/security/staxutils/W3CDOMStreamReader.java
@@ -0,0 +1,419 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.xml.security.staxutils;
+
+import java.util.ArrayList;
+
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import javax.xml.stream.Location;
+import javax.xml.stream.XMLStreamException;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Comment;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.ProcessingInstruction;
+import org.w3c.dom.Text;
+import org.w3c.dom.TypeInfo;
+
+public class W3CDOMStreamReader extends AbstractDOMStreamReader<Node, Node> {
+ private Node content;
+
+ private Document document;
+
+ private W3CNamespaceContext context;
+
+ private String sysId;
+
+ /**
+ * @param element
+ */
+ public W3CDOMStreamReader(Element element) {
+ super(new ElementFrame<Node, Node>(element, null));
+ content = element;
+ newFrame(getCurrentFrame());
+
+ this.document = element.getOwnerDocument();
+ }
+ public W3CDOMStreamReader(Element element, String systemId) {
+ this(element);
+ sysId = systemId;
+ }
+ public W3CDOMStreamReader(Document doc) {
+ super(new ElementFrame<Node, Node>(doc, false) {
+ public boolean isDocument() {
+ return true;
+ }
+ });
+ this.document = doc;
+ }
+ public W3CDOMStreamReader(DocumentFragment docfrag) {
+ super(new ElementFrame<Node, Node>(docfrag, true) {
+ public boolean isDocumentFragment() {
+ return true;
+ }
+ });
+ this.document = docfrag.getOwnerDocument();
+ }
+
+ /**
+ * Get the document associated with this stream.
+ */
+ public Document getDocument() {
+ return document;
+ }
+ public String getSystemId() {
+ try {
+ return sysId == null ? document.getDocumentURI() : sysId;
+ } catch (Throwable ex) {
+ //ignore, probably not DOM level 3
+ }
+ return sysId;
+ }
+ /**
+ * Find name spaces declaration in atrributes and move them to separate
+ * collection.
+ */
+ @Override
+ protected final void newFrame(ElementFrame<Node, Node> frame) {
+ Node element = getCurrentNode();
+ frame.uris = new ArrayList<>();
+ frame.prefixes = new ArrayList<>();
+ frame.attributes = new ArrayList<>();
+
+ if (context == null) {
+ context = new W3CNamespaceContext();
+ }
+ if (element instanceof Element) {
+ context.setElement((Element)element);
+ }
+
+ NamedNodeMap nodes = element.getAttributes();
+
+ String ePrefix = element.getPrefix();
+ if (ePrefix == null) {
+ ePrefix = "";
+ }
+
+ if (nodes != null) {
+ for (int i = 0; i < nodes.getLength(); i++) {
+ Node node = nodes.item(i);
+ String prefix = node.getPrefix();
+ String localName = node.getLocalName();
+ String value = node.getNodeValue();
+ String name = node.getNodeName();
+
+ if (prefix == null) {
+ prefix = "";
+ }
+
+ if (name != null && "xmlns".equals(name)) {
+ frame.uris.add(value);
+ frame.prefixes.add("");
+ } else if (prefix.length() > 0 && "xmlns".equals(prefix)) {
+ frame.uris.add(value);
+ frame.prefixes.add(localName);
+ } else if (name.startsWith("xmlns:")) {
+ prefix = name.substring(6);
+ frame.uris.add(value);
+ frame.prefixes.add(prefix);
+ } else {
+ frame.attributes.add(node);
+ }
+ }
+ }
+ }
+
+ public final Node getCurrentNode() {
+ return getCurrentFrame().element;
+ }
+ public final Element getCurrentElement() {
+ return (Element)getCurrentFrame().element;
+ }
+
+ @Override
+ protected ElementFrame<Node, Node> getChildFrame() {
+ return new ElementFrame<Node, Node>(getCurrentFrame().currentChild,
+ getCurrentFrame());
+ }
+
+ @Override
+ protected boolean hasMoreChildren() {
+ if (getCurrentFrame().currentChild == null) {
+ return getCurrentNode().getFirstChild() != null;
+ }
+ return getCurrentFrame().currentChild.getNextSibling() != null;
+ }
+
+ @Override
+ protected int nextChild() {
+ ElementFrame<Node, Node> frame = getCurrentFrame();
+ if (frame.currentChild == null) {
+ content = getCurrentNode().getFirstChild();
+ } else {
+ content = frame.currentChild.getNextSibling();
+ }
+
+ frame.currentChild = content;
+ switch (content.getNodeType()) {
+ case Node.ELEMENT_NODE:
+ return START_ELEMENT;
+ case Node.TEXT_NODE:
+ return CHARACTERS;
+ case Node.COMMENT_NODE:
+ return COMMENT;
+ case Node.CDATA_SECTION_NODE:
+ return CDATA;
+ case Node.ENTITY_REFERENCE_NODE:
+ return ENTITY_REFERENCE;
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ return PROCESSING_INSTRUCTION;
+ default:
+ throw new IllegalStateException("Found type: " + content.getClass().getName());
+ }
+ }
+
+ @Override
+ public String getElementText() throws XMLStreamException {
+ String result = DOMUtils.getRawContent(content);
+
+ ElementFrame<Node, Node> frame = getCurrentFrame();
+ frame.ended = true;
+ currentEvent = END_ELEMENT;
+ endElement();
+
+ // we should not return null according to the StAx API javadoc
+ return result != null ? result : "";
+ }
+
+ @Override
+ public String getNamespaceURI(String prefix) {
+ ElementFrame<Node, Node> frame = getCurrentFrame();
+
+ while (null != frame) {
+ int index = frame.prefixes.indexOf(prefix);
+ if (index != -1) {
+ return frame.uris.get(index);
+ }
+
+ if (frame.parent == null && frame.getElement() instanceof Element) {
+ return ((Element)frame.getElement()).lookupNamespaceURI(prefix);
+ }
+ frame = frame.parent;
+ }
+
+ return null;
+ }
+
+ public String getAttributeValue(String ns, String local) {
+ Attr at;
+ if (ns == null || ns.equals("")) {
+ at = getCurrentElement().getAttributeNode(local);
+ } else {
+ at = getCurrentElement().getAttributeNodeNS(ns, local);
+ }
+
+ if (at == null) {
+ return null;
+ }
+ return at.getNodeValue();
+ }
+
+ public int getAttributeCount() {
+ return getCurrentFrame().attributes.size();
+ }
+
+ Attr getAttribute(int i) {
+ return (Attr)getCurrentFrame().attributes.get(i);
+ }
+
+ private String getLocalName(Attr attr) {
+
+ String name = attr.getLocalName();
+ if (name == null) {
+ name = attr.getNodeName();
+ }
+ return name;
+ }
+
+ public QName getAttributeName(int i) {
+ Attr at = getAttribute(i);
+
+ String prefix = at.getPrefix();
+ String ln = getLocalName(at);
+ // at.getNodeName();
+ String ns = at.getNamespaceURI();
+
+ if (prefix == null) {
+ return new QName(ns, ln);
+ }
+ return new QName(ns, ln, prefix);
+ }
+
+ public String getAttributeNamespace(int i) {
+ return getAttribute(i).getNamespaceURI();
+ }
+
+ public String getAttributeLocalName(int i) {
+ Attr attr = getAttribute(i);
+ return getLocalName(attr);
+ }
+
+ public String getAttributePrefix(int i) {
+ return getAttribute(i).getPrefix();
+ }
+
+ public String getAttributeType(int i) {
+ Attr attr = getAttribute(i);
+ if (attr.isId()) {
+ return "ID";
+ }
+ TypeInfo schemaType = null;
+ try {
+ schemaType = attr.getSchemaTypeInfo();
+ } catch (Throwable t) {
+ //DOM level 2?
+ schemaType = null;
+ }
+ return (schemaType == null) ? "CDATA"
+ : schemaType.getTypeName() == null ? "CDATA" : schemaType.getTypeName();
+ }
+
+
+ public String getAttributeValue(int i) {
+ return getAttribute(i).getValue();
+ }
+
+ public boolean isAttributeSpecified(int i) {
+ return getAttribute(i).getValue() != null;
+ }
+
+ public int getNamespaceCount() {
+ return getCurrentFrame().prefixes.size();
+ }
+
+ public String getNamespacePrefix(int i) {
+ return getCurrentFrame().prefixes.get(i);
+ }
+
+ public String getNamespaceURI(int i) {
+ return getCurrentFrame().uris.get(i);
+ }
+
+ public NamespaceContext getNamespaceContext() {
+ return context;
+ }
+
+ public String getText() {
+ if (content instanceof Text) {
+ return ((Text)content).getData();
+ } else if (content instanceof Comment) {
+ return ((Comment)content).getData();
+ }
+ return DOMUtils.getRawContent(getCurrentNode());
+ }
+
+ public char[] getTextCharacters() {
+ return getText().toCharArray();
+ }
+
+ public int getTextStart() {
+ return 0;
+ }
+
+ public int getTextLength() {
+ return getText().length();
+ }
+
+ public String getEncoding() {
+ return null;
+ }
+
+ public QName getName() {
+ Node el = getCurrentNode();
+
+ String prefix = getPrefix();
+ String ln = getLocalName();
+
+ return new QName(el.getNamespaceURI(), ln, prefix);
+ }
+
+ public String getLocalName() {
+ String ln = getCurrentNode().getLocalName();
+ if (ln == null) {
+ ln = getCurrentNode().getNodeName();
+ if (ln.indexOf(":") != -1) {
+ ln = ln.substring(ln.indexOf(":") + 1);
+ }
+ }
+ return ln;
+ }
+
+ public String getNamespaceURI() {
+ String ln = getCurrentNode().getLocalName();
+ if (ln == null) {
+ ln = getCurrentNode().getNodeName();
+ if (ln.indexOf(":") == -1) {
+ ln = getNamespaceURI("");
+ } else {
+ ln = getNamespaceURI(ln.substring(0, ln.indexOf(":")));
+ }
+ return ln;
+ }
+ return getCurrentNode().getNamespaceURI();
+ }
+
+ public String getPrefix() {
+ String prefix = getCurrentNode().getPrefix();
+ if (prefix == null) {
+ String nodeName = getCurrentNode().getNodeName();
+ if (nodeName.indexOf(":") != -1) {
+ prefix = nodeName.substring(0, nodeName.indexOf(":"));
+ } else {
+ prefix = "";
+ }
+ }
+ return prefix;
+ }
+
+ public String getPITarget() {
+ return ((ProcessingInstruction)content).getTarget();
+ }
+
+ public String getPIData() {
+ return ((ProcessingInstruction)content).getData();
+ }
+ public Location getLocation() {
+ try {
+ Object o = getCurrentNode().getUserData("location");
+ if (o instanceof Location) {
+ return (Location)o;
+ }
+ } catch (Throwable ex) {
+ //ignore, probably not DOM level 3
+ }
+ return super.getLocation();
+ }
+
+
+}
diff --git a/src/main/java/org/apache/xml/security/staxutils/W3CNamespaceContext.java b/src/main/java/org/apache/xml/security/staxutils/W3CNamespaceContext.java
new file mode 100644
index 0000000..647e6dc
--- /dev/null
+++ b/src/main/java/org/apache/xml/security/staxutils/W3CNamespaceContext.java
@@ -0,0 +1,141 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.xml.security.staxutils;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.namespace.NamespaceContext;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+public class W3CNamespaceContext implements NamespaceContext {
+ private Element currentNode;
+ private NamespaceContext outNamespaceContext;
+
+ public W3CNamespaceContext() {
+ }
+ public W3CNamespaceContext(Element el) {
+ currentNode = el;
+ }
+
+ public void setOutNamespaceContext(NamespaceContext context) {
+ outNamespaceContext = context;
+ }
+
+ public String getNamespaceURI(String prefix) {
+ String name = prefix;
+ if (name.length() == 0) {
+ name = "xmlns";
+ } else {
+ name = "xmlns:" + prefix;
+ }
+
+ return getNamespaceURI(currentNode, name);
+ }
+
+ private String getNamespaceURI(Element e, String name) {
+ if (e == null) {
+ return null;
+ }
+ // check the outside namespace URI
+ if (outNamespaceContext != null) {
+ String result = outNamespaceContext.getNamespaceURI(name);
+ if (result != null) {
+ return result;
+ }
+ }
+
+ Attr attr = e.getAttributeNode(name);
+ if (attr == null) {
+ Node n = e.getParentNode();
+ if (n instanceof Element && n != e) {
+ return getNamespaceURI((Element)n, name);
+ }
+ } else {
+ return attr.getValue();
+ }
+
+ return null;
+ }
+
+ public String getPrefix(String uri) {
+ return getPrefix(currentNode, uri);
+ }
+
+ private String getPrefix(Element e, String uri) {
+ if (e == null) {
+ return null;
+ }
+ // check the outside namespace URI
+ if (outNamespaceContext != null) {
+ String result = outNamespaceContext.getPrefix(uri);
+ if (result != null) {
+ return result;
+ }
+ }
+
+ NamedNodeMap attributes = e.getAttributes();
+ if (attributes != null) {
+ for (int i = 0; i < attributes.getLength(); i++) {
+ Attr a = (Attr)attributes.item(i);
+
+ String val = a.getValue();
+ if (val != null && val.equals(uri)) {
+ String name = a.getLocalName();
+ if ("xmlns".equals(name)) {
+ return "";
+ }
+ return name;
+ }
+ }
+ }
+
+ Node n = e.getParentNode();
+ if (n instanceof Element && n != e) {
+ return getPrefix((Element)n, uri);
+ }
+
+ return null;
+ }
+
+ public Iterator<String> getPrefixes(String uri) {
+ List<String> prefixes = new ArrayList<>();
+
+ String prefix = getPrefix(uri);
+ if (prefix != null) {
+ prefixes.add(prefix);
+ }
+
+ return prefixes.iterator();
+ }
+
+ public Element getElement() {
+ return currentNode;
+ }
+
+ public void setElement(Element node) {
+ this.currentNode = node;
+ }
+}
diff --git a/src/main/java/org/apache/xml/security/transforms/implementations/TransformBase64Decode.java b/src/main/java/org/apache/xml/security/transforms/implementations/TransformBase64Decode.java
index 0c1b3c6..e94e115 100644
--- a/src/main/java/org/apache/xml/security/transforms/implementations/TransformBase64Decode.java
+++ b/src/main/java/org/apache/xml/security/transforms/implementations/TransformBase64Decode.java
@@ -22,6 +22,7 @@
import java.io.OutputStream;
import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
import org.apache.xml.security.c14n.CanonicalizationException;
import org.apache.xml.security.signature.XMLSignatureInput;
@@ -156,6 +157,8 @@
throw new TransformationException(e, "c14n.Canonicalizer.Exception");
} catch (SAXException e) {
throw new TransformationException(e, "SAX exception");
+ } catch (XMLStreamException e) {
+ throw new TransformationException(e, "SAX exception");
}
}
diff --git a/src/main/java/org/apache/xml/security/transforms/implementations/TransformXPath2Filter.java b/src/main/java/org/apache/xml/security/transforms/implementations/TransformXPath2Filter.java
index 9844670..3726a8f 100644
--- a/src/main/java/org/apache/xml/security/transforms/implementations/TransformXPath2Filter.java
+++ b/src/main/java/org/apache/xml/security/transforms/implementations/TransformXPath2Filter.java
@@ -26,6 +26,7 @@
import java.util.Set;
import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
import javax.xml.transform.TransformerException;
import org.apache.xml.security.c14n.CanonicalizationException;
@@ -144,11 +145,7 @@
throw new TransformationException(ex);
} catch (XMLSecurityException ex) {
throw new TransformationException(ex);
- } catch (SAXException ex) {
- throw new TransformationException(ex);
- } catch (IOException ex) {
- throw new TransformationException(ex);
- } catch (ParserConfigurationException ex) {
+ } catch (ParserConfigurationException | IOException | SAXException | XMLStreamException ex) {
throw new TransformationException(ex);
}
}
diff --git a/src/main/java/org/apache/xml/security/utils/XMLUtils.java b/src/main/java/org/apache/xml/security/utils/XMLUtils.java
index 2cc91f4..5f964a1 100644
--- a/src/main/java/org/apache/xml/security/utils/XMLUtils.java
+++ b/src/main/java/org/apache/xml/security/utils/XMLUtils.java
@@ -31,14 +31,15 @@
import java.util.List;
import java.util.Set;
-import javax.xml.XMLConstants;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
import org.apache.xml.security.c14n.CanonicalizationException;
import org.apache.xml.security.c14n.Canonicalizer;
import org.apache.xml.security.c14n.InvalidCanonicalizerException;
+import org.apache.xml.security.staxutils.DOMUtils;
+import org.apache.xml.security.staxutils.StaxUtils;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@@ -59,13 +60,6 @@
AccessController.doPrivileged(
(PrivilegedAction<Boolean>) () -> Boolean.getBoolean("org.apache.xml.security.ignoreLineBreaks"));
- @SuppressWarnings("unchecked")
- private static final WeakObjectPool<DocumentBuilder, ParserConfigurationException> pools[] = new WeakObjectPool[2];
- static {
- pools[0] = new DocumentBuilderPool(false);
- pools[1] = new DocumentBuilderPool(true);
- }
-
private static volatile String dsPrefix = "ds";
private static volatile String ds11Prefix = "dsig11";
private static volatile String xencPrefix = "xenc";
@@ -1004,55 +998,61 @@
}
public static Document newDocument() throws ParserConfigurationException {
- DocumentBuilder documentBuilder = createDocumentBuilder(true);
- Document doc = documentBuilder.newDocument();
- repoolDocumentBuilder(documentBuilder, true);
- return doc;
+ return DOMUtils.newDocument(true);
}
- public static Document read(InputStream inputStream) throws ParserConfigurationException, SAXException, IOException {
+ public static Document read(InputStream inputStream) throws ParserConfigurationException, SAXException, IOException, XMLStreamException {
return read(inputStream, true);
}
- public static Document read(InputStream inputStream, boolean disAllowDocTypeDeclarations) throws ParserConfigurationException, SAXException, IOException {
- DocumentBuilder documentBuilder = createDocumentBuilder(disAllowDocTypeDeclarations);
- Document doc = documentBuilder.parse(inputStream);
- repoolDocumentBuilder(documentBuilder, disAllowDocTypeDeclarations);
- return doc;
+ public static Document read(InputStream inputStream, boolean disAllowDocTypeDeclarations)
+ throws ParserConfigurationException, SAXException, IOException, XMLStreamException {
+ XMLStreamReader reader = StaxUtils.createXMLStreamReader(inputStream, disAllowDocTypeDeclarations);
+ try {
+ Document doc = DOMUtils.newDocument(disAllowDocTypeDeclarations);
+ if (reader.getLocation().getSystemId() != null) {
+ try {
+ doc.setDocumentURI(reader.getLocation().getSystemId());
+ } catch (Exception e) {
+ //ignore - probably not DOM level 3
+ }
+ }
+ StaxUtils.readDocElements(doc, doc, reader, true, false);
+ return doc;
+ } finally {
+ try {
+ reader.close();
+ } catch (Exception ex) {
+ //ignore
+ }
+ }
}
- public static Document read(String uri, boolean disAllowDocTypeDeclarations)
- throws ParserConfigurationException, SAXException, IOException {
- DocumentBuilder documentBuilder = createDocumentBuilder(disAllowDocTypeDeclarations);
- Document doc = documentBuilder.parse(uri);
- repoolDocumentBuilder(documentBuilder, disAllowDocTypeDeclarations);
- return doc;
- }
-
- public static Document read(InputSource inputSource) throws ParserConfigurationException, SAXException, IOException {
+ public static Document read(InputSource inputSource) throws ParserConfigurationException, SAXException, IOException, XMLStreamException {
return read(inputSource, true);
}
public static Document read(InputSource inputSource, boolean disAllowDocTypeDeclarations)
- throws ParserConfigurationException, SAXException, IOException {
- DocumentBuilder documentBuilder = createDocumentBuilder(disAllowDocTypeDeclarations);
- Document doc = documentBuilder.parse(inputSource);
- repoolDocumentBuilder(documentBuilder, disAllowDocTypeDeclarations);
- return doc;
- }
-
- private static DocumentBuilder createDocumentBuilder(
- boolean disAllowDocTypeDeclarations
- ) throws ParserConfigurationException {
- int idx = getPoolsIndex(disAllowDocTypeDeclarations);
- return pools[idx].getObject();
- }
-
-
- private static boolean repoolDocumentBuilder(DocumentBuilder db, boolean disAllowDocTypeDeclarations) {
- db.reset();
- int idx = getPoolsIndex(disAllowDocTypeDeclarations);
- return pools[idx].repool(db);
+ throws ParserConfigurationException, SAXException, IOException, XMLStreamException {
+ XMLStreamReader reader = StaxUtils.createXMLStreamReader(inputSource, disAllowDocTypeDeclarations);
+ try {
+ Document doc = DOMUtils.newDocument(disAllowDocTypeDeclarations);
+ if (reader.getLocation().getSystemId() != null) {
+ try {
+ doc.setDocumentURI(reader.getLocation().getSystemId());
+ } catch (Exception e) {
+ //ignore - probably not DOM level 3
+ }
+ }
+ StaxUtils.readDocElements(doc, doc, reader, true, false);
+ return doc;
+ } finally {
+ try {
+ reader.close();
+ } catch (Exception ex) {
+ //ignore
+ }
+ }
}
/**
@@ -1100,34 +1100,4 @@
return resizedBytes;
}
- private static final class DocumentBuilderPool
- extends WeakObjectPool<DocumentBuilder, ParserConfigurationException> {
-
- private final boolean disAllowDocTypeDeclarations;
-
- public DocumentBuilderPool(boolean disAllowDocTypeDeclarations) {
- this.disAllowDocTypeDeclarations = disAllowDocTypeDeclarations;
- }
-
- @Override
- protected DocumentBuilder createObject() throws ParserConfigurationException {
- DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
- dfactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
- if (disAllowDocTypeDeclarations) {
- dfactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
- }
- dfactory.setNamespaceAware(true);
- return dfactory.newDocumentBuilder();
- }
- }
-
- /**
- * Maps the boolean configuration options for the factories to the array index for the WeakObjectPool
- * @param disAllowDocTypeDeclarations
- * @return the index to the {@link #pools}
- */
- private static int getPoolsIndex(boolean disAllowDocTypeDeclarations) {
- return (disAllowDocTypeDeclarations ? 1 : 0);
- }
-
}
diff --git a/src/test/java/org/apache/xml/security/test/dom/TestUtils.java b/src/test/java/org/apache/xml/security/test/dom/TestUtils.java
index 8bdacc2..53f9484 100644
--- a/src/test/java/org/apache/xml/security/test/dom/TestUtils.java
+++ b/src/test/java/org/apache/xml/security/test/dom/TestUtils.java
@@ -18,9 +18,19 @@
*/
package org.apache.xml.security.test.dom;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.xml.security.staxutils.DOMUtils;
+import org.apache.xml.security.staxutils.StaxUtils;
import org.apache.xml.security.utils.Constants;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
public class TestUtils {
@@ -42,4 +52,27 @@
return ctx;
}
+ public static Document read(String uri, String systemId, boolean disAllowDocTypeDeclarations)
+ throws ParserConfigurationException, SAXException, IOException, XMLStreamException {
+ XMLStreamReader reader = StaxUtils.createXMLStreamReader(systemId, new FileInputStream(uri), disAllowDocTypeDeclarations);
+ try {
+ Document doc = DOMUtils.newDocument(disAllowDocTypeDeclarations);
+ if (reader.getLocation().getSystemId() != null) {
+ try {
+ doc.setDocumentURI(reader.getLocation().getSystemId());
+ } catch (Exception e) {
+ //ignore - probably not DOM level 3
+ }
+ }
+ StaxUtils.readDocElements(doc, doc, reader, true, false);
+ return doc;
+ } finally {
+ try {
+ reader.close();
+ } catch (Exception ex) {
+ //ignore
+ }
+ }
+ }
+
}
diff --git a/src/test/java/org/apache/xml/security/test/dom/c14n/implementations/Canonicalizer11Test.java b/src/test/java/org/apache/xml/security/test/dom/c14n/implementations/Canonicalizer11Test.java
index 3522a8b..3a75bab 100644
--- a/src/test/java/org/apache/xml/security/test/dom/c14n/implementations/Canonicalizer11Test.java
+++ b/src/test/java/org/apache/xml/security/test/dom/c14n/implementations/Canonicalizer11Test.java
@@ -32,8 +32,8 @@
import org.apache.xml.security.c14n.Canonicalizer;
import org.apache.xml.security.test.dom.DSNamespaceContext;
+import org.apache.xml.security.test.dom.TestUtils;
import org.apache.xml.security.utils.JavaUtils;
-import org.apache.xml.security.utils.XMLUtils;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
@@ -244,7 +244,8 @@
Map<String, String> namespaces
) throws Exception {
- Document doc = XMLUtils.read(fileIn, false);
+ String systemId = "target/test-classes/org/apache/xml/security/c14n/in/xyz";
+ Document doc = TestUtils.read(fileIn, systemId, false);
Canonicalizer c14n = Canonicalizer.getInstance(c14nURI);
byte[] c14nBytes = null;
diff --git a/src/test/java/org/apache/xml/security/test/dom/c14n/implementations/Canonicalizer20010315Test.java b/src/test/java/org/apache/xml/security/test/dom/c14n/implementations/Canonicalizer20010315Test.java
index 3116d51..f2d810e 100644
--- a/src/test/java/org/apache/xml/security/test/dom/c14n/implementations/Canonicalizer20010315Test.java
+++ b/src/test/java/org/apache/xml/security/test/dom/c14n/implementations/Canonicalizer20010315Test.java
@@ -42,6 +42,7 @@
import org.apache.xml.security.c14n.CanonicalizationException;
import org.apache.xml.security.c14n.Canonicalizer;
import org.apache.xml.security.test.dom.DSNamespaceContext;
+import org.apache.xml.security.test.dom.TestUtils;
import org.apache.xml.security.utils.JavaUtils;
import org.apache.xml.security.utils.XMLUtils;
import org.w3c.dom.Document;
@@ -710,7 +711,8 @@
Map<String, String> namespaces
) throws Exception {
- Document doc = XMLUtils.read(fileIn, false);
+ String systemId = "target/test-classes/org/apache/xml/security/c14n/in/xyz";
+ Document doc = TestUtils.read(fileIn, systemId, false);
Canonicalizer c14n = Canonicalizer.getInstance(c14nURI);
diff --git a/src/test/java/org/apache/xml/security/test/dom/interop/InteropTestBase.java b/src/test/java/org/apache/xml/security/test/dom/interop/InteropTestBase.java
index 7eaf26b..8dabaec 100644
--- a/src/test/java/org/apache/xml/security/test/dom/interop/InteropTestBase.java
+++ b/src/test/java/org/apache/xml/security/test/dom/interop/InteropTestBase.java
@@ -36,6 +36,7 @@
import org.apache.xml.security.signature.reference.ReferenceNodeSetData;
import org.apache.xml.security.signature.reference.ReferenceOctetStreamData;
import org.apache.xml.security.test.dom.DSNamespaceContext;
+import org.apache.xml.security.test.dom.TestUtils;
import org.apache.xml.security.utils.XMLUtils;
import org.apache.xml.security.utils.resolver.ResourceResolverSpi;
import org.w3c.dom.Element;
@@ -91,8 +92,13 @@
public boolean verify(String filename, ResourceResolverSpi resolver,
boolean followManifests, boolean secureValidation)
throws Exception {
- File f = new File(filename);
- org.w3c.dom.Document doc = XMLUtils.read(new FileInputStream(f), false);
+ return verify(filename, resolver, null, followManifests, secureValidation);
+ }
+
+ public boolean verify(String filename, ResourceResolverSpi resolver, String systemId,
+ boolean followManifests, boolean secureValidation)
+ throws Exception {
+ org.w3c.dom.Document doc = TestUtils.read(filename, systemId, false);
XPathFactory xpf = XPathFactory.newInstance();
XPath xpath = xpf.newXPath();
@@ -101,6 +107,7 @@
String expression = "//ds:Signature[1]";
Element sigElement =
(Element) xpath.evaluate(expression, doc, XPathConstants.NODE);
+ File f = new File(filename);
XMLSignature signature = new XMLSignature(sigElement, f.toURI().toURL().toString(), secureValidation);
if (resolver != null) {