XmlProcessingService.java
package io.mersel.dss.signer.api.services.signature.xades;
import eu.europa.esig.dss.model.DSSDocument;
import io.mersel.dss.signer.api.exceptions.SignatureException;
import io.mersel.dss.signer.api.util.xml.SecureXmlFactories;
import org.springframework.stereotype.Service;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.parsers.DocumentBuilder;
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 java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
* XML ayrıştırma ve dönüştürme işlemleri için servis.
* Tüm XML işleme mantığını merkezileştirir.
*/
@Service
public class XmlProcessingService {
private final DocumentBuilderFactory documentBuilderFactory;
public XmlProcessingService() {
// XXE-güvenli (hardened) factory; SecureXmlFactories merkezi olarak
// DOCTYPE/external entity/DTD/XInclude vektörlerini kapatır.
this.documentBuilderFactory = SecureXmlFactories.newDocumentBuilderFactory();
}
/**
* XML byte'larını DOM Document'e ayrıştırır.
*/
public Document parseDocument(byte[] xmlBytes) {
try {
DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder();
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(xmlBytes)) {
return builder.parse(inputStream);
}
} catch (ParserConfigurationException | SAXException | IOException e) {
throw new SignatureException("XML belgesi ayrıştırılamadı", e);
}
}
/**
* DOM Document'i byte dizisine dönüştürür.
*/
public byte[] documentToBytes(Document document) {
try {
TransformerFactory transformerFactory = SecureXmlFactories.newTransformerFactory();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
transformer.transform(new DOMSource(document), new StreamResult(outputStream));
return outputStream.toByteArray();
} catch (TransformerException e) {
throw new SignatureException("Belge byte dizisine dönüştürülemedi", e);
}
}
/**
* DSS document'ten byte dizisi çıkarır.
*/
public byte[] dssDocumentToBytes(DSSDocument document) {
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
document.writeTo(outputStream);
return outputStream.toByteArray();
} catch (IOException e) {
throw new SignatureException("DSS document'ten byte'lar çıkarılamadı", e);
}
}
/**
* XML belgesinde Signature elemanını bulur.
*/
public Element findSignatureElement(Document document) {
// Önce namespace ile dene
NodeList nodeList = document.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
// Yerel isim ile yedekleme
if (nodeList == null || nodeList.getLength() == 0) {
nodeList = document.getElementsByTagName("ds:Signature");
}
if (nodeList != null && nodeList.getLength() > 0) {
return (Element) nodeList.item(0);
}
return null;
}
}