se.swedenconnect.cert.extensions.utils.DOMUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cert-extensions Show documentation
Show all versions of cert-extensions Show documentation
X.509 Certificate extensions library extending BouncyCastle ASN.1
The newest version!
/*
* Copyright (c) 2023. Sweden Connect
*
* Licensed 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 se.swedenconnect.cert.extensions.utils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Objects;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
/**
* XML DOM Utils
*/
@Slf4j
public class DOMUtils {
private static Transformer plainTransformer;
@Getter private static Transformer styledTransformer;
@Getter private static Transformer noXMLDeclarationTransformer;
@Getter private static Transformer noXMLDeclarationStyledTransformer;
@Getter private static DocumentBuilderFactory safeDocBuilderFactory;
static {
/**
* This document builder factory is created in line with recommendations by OWASP
* https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#JAXP_DocumentBuilderFactory.2C_SAXParserFactory_and_DOM4J
* This Document builder disables the use of DTD and mitigates XEE attack threats
*/
safeDocBuilderFactory = DocumentBuilderFactory.newInstance();
safeDocBuilderFactory.setNamespaceAware(true);
try {
safeDocBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
safeDocBuilderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
safeDocBuilderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
safeDocBuilderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
safeDocBuilderFactory.setXIncludeAware(false);
safeDocBuilderFactory.setExpandEntityReferences(false);
}
catch (ParserConfigurationException e) {
e.printStackTrace();
}
TransformerFactory tf = TransformerFactory.newInstance();
try {
// Canonical XML transformer
plainTransformer = tf.newTransformer();
// Canonical XML with no XML declaration transformer
noXMLDeclarationTransformer = tf.newTransformer();
noXMLDeclarationTransformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
// Styled print transformer
styledTransformer = tf.newTransformer();
styledTransformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
//transformer.setOutputProperty(OutputKeys.STANDALONE, "no");
styledTransformer.setOutputProperty(OutputKeys.METHOD, "xml");
styledTransformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
styledTransformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
styledTransformer.setOutputProperty(OutputKeys.INDENT, "yes");
// No XML Declaration styled print transformer
noXMLDeclarationStyledTransformer = tf.newTransformer();
noXMLDeclarationStyledTransformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
noXMLDeclarationStyledTransformer.setOutputProperty(OutputKeys.METHOD, "xml");
noXMLDeclarationStyledTransformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
noXMLDeclarationStyledTransformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
noXMLDeclarationStyledTransformer.setOutputProperty(OutputKeys.INDENT, "yes");
}
catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* Generates a pretty XML print of an XML document based on java.xml
* functions.
*
* @param doc The doc being processed
* @param xmlDeclaration defines if an XML declaration prefix should be included
* @return Test representation of the XML document
* @throws TransformerException error processing the xml document
*/
public static String getStyledDocText(Document doc, boolean xmlDeclaration) throws TransformerException {
Objects.requireNonNull(doc, "Document must not be null");
DOMSource domSource = new DOMSource(doc);
java.io.StringWriter sw = new java.io.StringWriter();
StreamResult sr = new StreamResult(sw);
if (xmlDeclaration) {
styledTransformer.transform(domSource, sr);
} else {
noXMLDeclarationStyledTransformer.transform(domSource, sr);
}
return sw.toString();
}
/**
* Provides a canonical print of the XML document. The purpose of this print
* is to try to preserve integrity of an existing signature.
*
* @param doc The XML document being processed.
* @param xmlDeclaration true to include XML declaration prefix
* @return XML String
* @throws TransformerException error processing the xml document
*/
public static byte[] getCanonicalDocText(Document doc, boolean xmlDeclaration) throws TransformerException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
if (xmlDeclaration) {
plainTransformer.transform(new DOMSource(doc), new StreamResult(os));
} else {
noXMLDeclarationTransformer.transform(new DOMSource(doc), new StreamResult(os));
}
return os.toByteArray();
}
public static Document getNormalizedDocument(byte[] xmlData)
throws ParserConfigurationException, IOException, SAXException {
Document doc = safeDocBuilderFactory.newDocumentBuilder().parse(new ByteArrayInputStream(xmlData));
doc.getDocumentElement().normalize();
return doc;
}
public static Document getDocument(byte[] xmlData) throws IOException, SAXException, ParserConfigurationException {
return safeDocBuilderFactory.newDocumentBuilder().parse(new ByteArrayInputStream(xmlData));
}
/**
* Pare an XML file and returns an XML document
*
* @param xmlFile The XML file being parsed
* @return XML document
* @throws IOException IO data exception
* @throws ParserConfigurationException error setting up XML parser
* @throws SAXException xml processing error
*/
public static Document loadXMLContent(File xmlFile) throws IOException, ParserConfigurationException, SAXException {
Document doc;
InputStream is = new FileInputStream(xmlFile);
doc = safeDocBuilderFactory.newDocumentBuilder().parse(is);
doc.getDocumentElement().normalize();
return doc;
}
/**
* Create new empty XML document
*
* @return new empty XML document
*/
public static Document createNewDocument() {
try {
return DOMUtils.getSafeDocBuilderFactory().newDocumentBuilder().newDocument();
}
catch (ParserConfigurationException e) {
throw new RuntimeException("Failed to create XML document");
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy