/**
* **************************************************************************
* Contributor(s):
* C. Heazel (WiSC): Added Fortify adjudication changes
*
* **************************************************************************
*/
package com.occamlab.te.util;
import java.io.File;
import java.io.StringWriter;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.XMLConstants; // Addition for Fortify modifications
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
import org.w3c.dom.Comment;
import org.w3c.dom.Element;
import org.w3c.dom.Attr;
/**
* Allows for manipulating of a DOM Document by adding/removing/etc elements and
* attributes.
*
* @author jparrpearson
*/
public class DomUtils {
/**
* Adds the attribute to each node in the Document with the given name.
*
* @param doc
* the Document to add attributes to
* @param tagName
* the local name of the nodes to add the attribute to
* @param tagNamespaceURI
* the namespace uri of the nodes to add the attribute to
* @param attrName
* the name of the attribute to add
* @param attrValue
* the value of the attribute to add
*
* @return the original Document with the update attribute nodes
*/
public static Node addDomAttr(Document doc, String tagName,
String tagNamespaceURI, String attrName, String attrValue) {
// Create a Document to work on
Document newDoc = null;
try {
System.setProperty("javax.xml.parsers.DocumentBuilderFactory",
"org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
newDoc = db.newDocument();
} catch (Exception e) {
e.printStackTrace();
}
Transformer identity = null;
try {
TransformerFactory TF = TransformerFactory.newInstance();
// Fortify Mod: disable external entity injection
TF.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
identity = TF.newTransformer();
// End Fortify Mod
identity.transform(new DOMSource(doc), new DOMResult(newDoc));
} catch (Exception ex) {
System.out.println("ERROR: " + ex.getMessage());
}
// Get all named nodes in the doucment
NodeList namedTags = newDoc.getElementsByTagNameNS(tagNamespaceURI,
tagName);
for (int i = 0; i < namedTags.getLength(); i++) {
// Add the attribute to each one
Element element = (Element) namedTags.item(i);
element.setAttribute(attrName, attrValue);
}
// displayNode(newDoc);
return (Node) newDoc;
}
/**
* Determines if there is a comment Node that contains the given string.
*
* @param node
* the Node to look in
* @param str
* the string value to match in the comment nodes
*
* CTL declaration, if we ever want to use it <!--Sample Usage:
* ctl:checkCommentNodes($xml.resp, 'complexContent')-->
* <ctl:function name="ctl:checkCommentNodes"> <ctl:param
* name="node"/> <ctl:param name="string"/>
* <ctl:description>Checks a Node for comments that contain the
* given string.</ctl:description> <ctl:java
* class="com.occamlab.te.util.DomUtils"
* method="checkCommentNodes"/> </ctl:function>
*
* @return the original Document with the update attribute nodes
*/
public static boolean checkCommentNodes(Node node, String str) {
// Get nodes of node and go through them
NodeList children = node.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
NodeList childChildren = child.getChildNodes();
if (childChildren.getLength() > 0) {
// Recurse for all children
boolean okDownThere = checkCommentNodes(child, str);
if (okDownThere == true) {
return true;
}
}
// Investigate comments
if (child.getNodeType() == Node.COMMENT_NODE) {
// If we got a comment that contains the string we are happy
Comment comment = (Comment) child;
if (comment.getNodeValue().contains(str)) {
return true;
}
}
}
return false;
}
/**
* Serializes a Node to a String
*/
public static String serializeNode(Node node) {
return serializeSource(new DOMSource(node));
}
public static String serializeSource(Source source) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
TransformerFactory factory = TransformerFactory.newInstance();
// Fortify Mod: disable external entity injection
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
Transformer transformer = factory.newTransformer();
// End Fortify Mod
StreamResult dest = new StreamResult(baos);
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,
"yes");
transformer.transform(source, dest);
} catch (Exception e) {
System.out.println("Error serializing node. " + e.getMessage());
}
try {
return baos.toString("UTF-8");
} catch (UnsupportedEncodingException e) {
return baos.toString();
}
}
/**
* Serializes a Node to a String
*/
public static String serializeNoNS(Node node) {
StringBuffer buf = new StringBuffer();
buf.append("<");
buf.append(node.getLocalName());
for (Entry<QName, String> entry : getAttributes(node).entrySet()) {
QName name = entry.getKey();
if (name.getNamespaceURI() != null) {
buf.append(" ");
buf.append(name.getLocalPart());
buf.append("=\"");
buf.append(entry.getValue());
buf.append("\"");
}
}
boolean tagOpen = true;
NodeList children = node.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node n = children.item(i);
short type = node.getNodeType();
if (type == Node.TEXT_NODE) {
if (tagOpen) {
buf.append(">\n");
tagOpen = false;
}
buf.append(node.getTextContent());
} else if (type == Node.ELEMENT_NODE) {
if (tagOpen) {
buf.append(">\n");
tagOpen = false;
}
buf.append(serializeNoNS(n));
buf.append("\n");
}
}
if (tagOpen) {
buf.append("/>\n");
} else {
buf.append("</");
buf.append(node.getLocalName());
buf.append(">\n");
}
return buf.toString();
// ByteArrayOutputStream baos = new ByteArrayOutputStream();
// try {
// TransformerFactory factory = TransformerFactory.newInstance();
// File f = Misc.getResourceAsFile("com/occamlab/te/drop-ns.xsl");
// Transformer transformer = factory.newTransformer(new
// StreamSource(f));
//
// DOMSource src = new DOMSource(node);
// StreamResult dest = new StreamResult(baos);
// transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,
// "yes");
// transformer.transform(src, dest);
// } catch (Exception e) {
// System.out.println("Error serializing node. "+e.getMessage());
// }
//
// return baos.toString();
}
/** HELPER METHOD TO PRINT A DOM TO STDOUT */
static public void displayNode(Node node) {
try {
TransformerFactory TF = TransformerFactory.newInstance();
// Fortify Mod: disable external entity injection
TF.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
Transformer identity = TF.newTransformer();
// End Fortify Mod
identity.transform(new DOMSource(node),
new StreamResult(System.out));
} catch (Exception ex) {
System.out.println("ERROR: " + ex.getMessage());
}
}
static public Element getElement(Node node) {
if (node.getNodeType() == Node.DOCUMENT_NODE) {
return ((Document) node).getDocumentElement();
} else if (node.getNodeType() == Node.ELEMENT_NODE) {
return (Element) node;
}
return null;
}
static public Map<QName, String> getAttributes(Node node) {
Map<QName, String> atts = new HashMap<QName, String>();
NamedNodeMap nnm = node.getAttributes();
if (nnm != null) {
for (int i = 0; i < nnm.getLength(); i++) {
Attr att = (Attr) nnm.item(i);
String uri = att.getBaseURI();
String localname = att.getLocalName();
String prefix = att.getPrefix();
QName name;
if (uri == null) {
name = new QName(localname);
} else if (prefix == null) {
name = new QName(uri, localname);
} else {
name = new QName(uri, localname, prefix);
}
if (prefix == null
|| !(prefix.equals("xmlns") || prefix.equals("xml"))) {
atts.put(name, att.getValue());
}
}
}
return atts;
}
static public Document createDocument(Node node) throws Exception {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
// Fortify Mod: Disable entity expansion to foil External Entity Injections
dbf.setExpandEntityReferences(false);
Document doc = dbf.newDocumentBuilder().newDocument();
if (node != null) {
// Fortify Mod: disable external entity injection
TransformerFactory tf = TransformerFactory.newInstance();
tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
Transformer t = tf.newTransformer();
// End Fortify Mod
t.transform(new DOMSource(node), new DOMResult(doc));
}
return doc;
}
static public Element getChildElement(Node node) {
NodeList nl = node.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node n = nl.item(i);
if (n.getNodeType() == Node.ELEMENT_NODE) {
return (Element) n;
}
}
return null;
}
static public List<Element> getChildElements(Node node) {
ArrayList<Element> list = new ArrayList<Element>();
NodeList nl = node.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node n = nl.item(i);
if (n.getNodeType() == Node.ELEMENT_NODE) {
list.add((Element) nl.item(i));
}
}
return list;
}
static public Element getElementByTagName(Node node, String tagname) {
NodeList nl;
if (node.getNodeType() == Node.DOCUMENT_NODE) {
nl = ((Document) node).getElementsByTagName(tagname);
} else if (node.getNodeType() == Node.ELEMENT_NODE) {
nl = ((Element) node).getElementsByTagName(tagname);
} else {
return null;
}
if (nl.getLength() >= 0) {
return (Element) nl.item(0);
} else {
return null;
}
}
static public Element getElementByTagNameNS(Node node, String namespaceURI,
String localName) {
NodeList nl;
if (node.getNodeType() == Node.DOCUMENT_NODE) {
nl = ((Document) node).getElementsByTagNameNS(namespaceURI,
localName);
} else if (node.getNodeType() == Node.ELEMENT_NODE) {
nl = ((Element) node).getElementsByTagNameNS(namespaceURI,
localName);
} else {
return null;
}
if (nl.getLength() > 0) {
return (Element) nl.item(0);
} else {
return null;
}
}
static public List<Element> getElementsByTagName(Node node, String tagname) {
ArrayList<Element> list = new ArrayList<Element>();
NodeList nl;
if (node.getNodeType() == Node.DOCUMENT_NODE) {
nl = ((Document) node).getElementsByTagName(tagname);
} else if (node.getNodeType() == Node.ELEMENT_NODE) {
nl = ((Element) node).getElementsByTagName(tagname);
} else {
return null;
}
for (int i = 0; i < nl.getLength(); i++) {
list.add((Element) nl.item(i));
}
return list;
}
static public List<Element> getElementsByTagNameNS(Node node,
String namespaceURI, String localName) {
ArrayList<Element> list = new ArrayList<Element>();
NodeList nl;
if (node.getNodeType() == Node.DOCUMENT_NODE) {
nl = ((Document) node).getElementsByTagNameNS(namespaceURI,
localName);
} else if (node.getNodeType() == Node.ELEMENT_NODE) {
nl = ((Element) node).getElementsByTagNameNS(namespaceURI,
localName);
} else {
return null;
}
for (int i = 0; i < nl.getLength(); i++) {
list.add((Element) nl.item(i));
}
return list;
}
}