package com.zenika.xml.signature; import org.w3c.dom.Document; import org.w3c.dom.Node; import javax.xml.crypto.MarshalException; import javax.xml.crypto.dom.DOMStructure; import javax.xml.crypto.dsig.*; import javax.xml.crypto.dsig.dom.DOMSignContext; import javax.xml.crypto.dsig.keyinfo.KeyInfo; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import java.security.Key; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * A builder for generating an xml signature document. Easier to use than the java xml signature API... */ public class XmlSignatureBuilder { private final XMLSignatureFactory xmlSignatureFactory; private SignedInfo signedInfo; private KeyInfo keyInfo; private List<XMLObject> objects = new ArrayList<XMLObject>(); /** * Instantiate an XmlSignatureBuilder */ public XmlSignatureBuilder() { xmlSignatureFactory = XMLSignatureFactory.getInstance(); } /** * Return the XMLSignatureFactory used by the builder * @return */ public XMLSignatureFactory getXmlSignatureFactory() { return xmlSignatureFactory; } /** * Generate the XMLSignature with the parameters set with this builder. * @return */ public XMLSignature build() { return xmlSignatureFactory.newXMLSignature(signedInfo, keyInfo, objects, null, null); } /** * Generate the XMLSignature with the parameters set with this builder, sign the given document and insert the signature inside it. * @param privateKey * @param document * @return the document containing the XML signature * @throws MarshalException * @throws XMLSignatureException */ public Document buildAndSign(Key privateKey, Document document) throws MarshalException, XMLSignatureException { build().sign(new DOMSignContext(privateKey, document.getDocumentElement())); return document; } /** * Generate the XMLSignature with the parameters set with this builder and insert the result inside a new document. * @param privateKey * @return the document containing the XML signature * @throws MarshalException * @throws XMLSignatureException * @throws ParserConfigurationException */ public Document buildAndSign(Key privateKey) throws MarshalException, XMLSignatureException, ParserConfigurationException { DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); documentBuilderFactory.setNamespaceAware(true); Document document = documentBuilderFactory.newDocumentBuilder().newDocument(); build().sign(new DOMSignContext(privateKey, document)); return document; } /** * Instantiate and return a KeyInfoBuilder used to set the KeyInfo node of the xml signature document. * @return */ public KeyInfoBuilder withKeyInfo() { return new KeyInfoBuilder(this); } /** * Instantiate and return a SignedInfoBuilder used to set the SignedInfo node of the xml signature document. * @return */ public SignedInfoBuilder withSignedInfo() { return new SignedInfoBuilder(this); } /** * Set the KeyInfo that will be used to generate the KeyInfo node of the xml signature document. * @param keyInfo * @return */ protected XmlSignatureBuilder withKeyInfo(KeyInfo keyInfo) { this.keyInfo = keyInfo; return this; } /** * Set the SignedInfo that will be used to generate the SignedInfo node of the xml signature document. * @param signedInfo * @return */ protected XmlSignatureBuilder withSignedInfo(SignedInfo signedInfo) { this.signedInfo = signedInfo; return this; } /** * Add to the XMLSignature to build an Object node with the given id * @param node * @param id * @return */ public XmlSignatureBuilder withObject(Node node, String id) { return withObject(node, id, null, null); } /** * Add to the XMLSignature to build an Object node with the given id, mime type and encoding * @param node * @param id * @param mimeType * @param encoding * @return */ public XmlSignatureBuilder withObject(Node node, String id, String mimeType, String encoding) { objects.add(xmlSignatureFactory.newXMLObject(Collections.singletonList(new DOMStructure(node)), id, mimeType, encoding)); return this; } }