All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
at.spardat.xma.boot.comp.data.XMLValidator Maven / Gradle / Ivy
/*
* @(#) $Id: $
*
* Copyright 2009/2010 by sIT Solutions,
* A-1110 Wien, Geiselbergstr.21-25.
* All rights reserved.
*
*/
package at.spardat.xma.boot.comp.data;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.util.Iterator;
import java.util.Properties;
import javax.xml.crypto.dsig.Reference;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
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.w3c.dom.NodeList;
import org.xml.sax.EntityResolver;
import at.spardat.xma.boot.Statics;
import at.spardat.xma.boot.comp.DTDStatics;
import at.spardat.xma.boot.logger.ILogger;
import at.spardat.xma.boot.logger.LogLevel;
public class XMLValidator {
private final ILogger log;
private final boolean enforceSignature;
private final boolean enableSignature;
private EntityResolver entityResolver;
private PublicKey publicKey;
/**
* @param log Logger
* @param enableSignature enable signature validation
* @param enforceSignature enforce signature validation
*/
protected XMLValidator(PublicKey publicKey, ILogger log, boolean enableSignature, boolean enforceSignature) {
this.publicKey = publicKey;
this.log = log;
this.enableSignature = enableSignature;
this.enforceSignature = enforceSignature;
}
public static XMLValidator create(ILogger log, Properties props) {
if( log == null ) throw new NullPointerException();
boolean enforce = false;
boolean enable = true;
String certificateAlias = Statics.strSignatureCertalias;
if (props != null) {
String strEnforceSignature = (String)props.get( Statics.CFG_PROP_XML_SIGNATURE_ENFORCE );
if( strEnforceSignature != null ) {
enforce = strEnforceSignature != null && Boolean.valueOf(strEnforceSignature).booleanValue();
}
if (!enforce) {
String strAllowSignature = (String)props.get( Statics.CFG_PROP_XML_SIGNATURE );
if( strAllowSignature!=null ) {
enable = Boolean.valueOf(strAllowSignature).booleanValue();
}
}
String strCertificateAlias = (String)props.get( Statics.CFG_PROP_XML_SIGNATURE_CERTALIAS );
if (strCertificateAlias != null) {
certificateAlias = strCertificateAlias;
}
}
PublicKey publicKey = null;
try {
publicKey = getPublicKey(log, certificateAlias);
} catch (Exception e) {
log.log(LogLevel.WARNING, "Error loading certificate for XML signature validation.", e);
}
if (publicKey == null && !enforce) {
log.log(LogLevel.CONFIG, "Unable to load certificate for XML signature validation, alias={0}", certificateAlias);
return null;
}
return new XMLValidator(publicKey, log, enable, enforce);
}
public void setEntityResolver(EntityResolver entityResolver) {
this.entityResolver = entityResolver;
}
private static PublicKey getPublicKey(ILogger log, String certificateAlias) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
String keyStore = System.getProperty("javax.net.ssl.trustStore");
if (keyStore == null) {
log.log(LogLevel.CONFIG, "No trust store defined. XML signature validation not available.");
return null;
}
String keyStorePassword = System.getProperty("javax.net.ssl.trustStorePassword");
if (keyStorePassword == null) {
keyStorePassword = "changeit";
}
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(new FileInputStream(keyStore), keyStorePassword.toCharArray());
Certificate certificate = ks.getCertificate(certificateAlias);
return certificate == null ? null : certificate.getPublicKey();
}
protected boolean validateSignature(InputStream is) throws Exception {
if (!enableSignature) {
return true;
}
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder docBuilder = dbf.newDocumentBuilder();
if (entityResolver != null) {
docBuilder.setEntityResolver(entityResolver);
}
Document doc = docBuilder.parse(is);
// Find Signature element
NodeList nl = doc.getElementsByTagNameNS(XMLSignature.XMLNS, DTDStatics.SIGNATURE);
if (nl.getLength() == 0) {
log.log(LogLevel.CONFIG, "Cannot find Signature element. Not verifying document.");
if (enforceSignature) {
logDocument(doc);
return false;
}
return true;
}
if (publicKey == null) {
log.log(LogLevel.SEVERE, "No key available to verify signature. Not verifying document.");
return false;
}
// Create a DOM XMLSignatureFactory that will be used to unmarshal the document containing the XMLSignature
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM"); //$NON-NLS-1$
DOMValidateContext valContext = new DOMValidateContext(publicKey, nl.item(0));
XMLSignature signature = fac.unmarshalXMLSignature(valContext);
// Validate the XMLSignature (generated above)
boolean coreValidity = signature.validate(valContext);
// Check core validation status
if (coreValidity == false) {
log.log(LogLevel.SEVERE, "Signature failed core validation");
boolean sv = signature.getSignatureValue().validate(valContext);
log.log(LogLevel.FINE, "signature validation status: " + sv);
// check the validation status of each Reference
Iterator i = signature.getSignedInfo().getReferences().iterator();
for (int j = 0; i.hasNext(); j++) {
boolean refValid = i.next().validate(valContext);
log.log(LogLevel.FINE, "ref[" + j + "] validity status: " + refValid);
}
logDocument(doc);
return false;
} else {
log.log(LogLevel.INFO, "Signature passed core validation");
return true;
}
}
public void logDocument(Document doc) throws IOException, TransformerException {
if (log.getLevel().intValue() <= LogLevel.FINE.intValue()) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
printDocument(doc, out);
log.log(LogLevel.FINE, out.toString());
}
}
public static void printDocument(Document doc, OutputStream out) throws IOException, TransformerException {
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
transformer.transform(new DOMSource(doc),
new StreamResult(new OutputStreamWriter(out, "UTF-8")));
}
}