org.digidoc4j.impl.asic.manifest.ManifestValidator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of digidoc4j Show documentation
Show all versions of digidoc4j Show documentation
DigiDoc4j is a Java library for digitally signing documents and creating digital signature containers
of signed documents
The newest version!
/* DigiDoc4J library
*
* This software is released under either the GNU Library General Public
* License (see LICENSE.LGPL).
*
* Note that the only valid version of the LGPL license as far as this
* project is concerned is the original GNU Library General Public License
* Version 2.1, February 1999
*/
package org.digidoc4j.impl.asic.manifest;
import eu.europa.esig.dss.model.DSSDocument;
import eu.europa.esig.dss.xml.utils.DomUtils;
import org.apache.xml.security.signature.Reference;
import org.digidoc4j.Signature;
import org.digidoc4j.exceptions.DigiDoc4JException;
import org.digidoc4j.impl.asic.AsicSignature;
import org.digidoc4j.impl.asic.xades.XadesSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* For validating meta data within the manifest file and signature files.
*/
public class ManifestValidator {
public static final String MANIFEST_PATH = "META-INF/manifest.xml";
public static final String MIMETYPE_PATH = "mimetype";
private static final Logger logger = LoggerFactory.getLogger(ManifestValidator.class);
private final List detachedContents;
private final ManifestParser manifestParser;
private final Collection signatures;
public ManifestValidator(ManifestParser manifestParser, List detachedContents,
Collection signatures) {
this.manifestParser = manifestParser;
this.detachedContents = detachedContents;
this.signatures = signatures;
}
public static List validateEntries(Map manifestEntries,
Set signatureEntries,
String signatureId) {
ArrayList errorMessages = new ArrayList<>();
if (signatureEntries.size() == 0)
return errorMessages;
Set one = new HashSet<>(manifestEntries.values());
Set onePrim = new HashSet<>(manifestEntries.values());
Set two = new HashSet<>(signatureEntries);
Set twoPrim = new HashSet<>();
for (ManifestEntry manifestEntry : signatureEntries) {
String mimeType = manifestEntry.getMimeType();
String alterName = manifestEntry.getFileName().replaceAll("\\+", " ");
twoPrim.add(new ManifestEntry(alterName, mimeType));
}
one.removeAll(signatureEntries);
onePrim.removeAll(twoPrim);
two.removeAll(manifestEntries.values());
twoPrim.removeAll(manifestEntries.values());
if (one.size() > 0 && onePrim.size() > 0) {
for (ManifestEntry manifestEntry : one) {
String fileName = manifestEntry.getFileName();
ManifestEntry signatureEntry = signatureEntryForFile(fileName, signatureEntries);
if (signatureEntry != null) {
errorMessages.add(new ManifestErrorMessage("Manifest file has an entry for file <"
+ fileName + "> with mimetype <"
+ manifestEntry.getMimeType() + "> but the signature file for signature " + signatureId
+ " indicates the mimetype is <" + signatureEntry.getMimeType() + ">", signatureId));
two.remove(signatureEntry);
} else {
errorMessages.add(new ManifestErrorMessage("Manifest file has an entry for file <"
+ fileName + "> with mimetype <"
+ manifestEntry.getMimeType() + "> but the signature file for signature " + signatureId
+ " does not have an entry for this file", signatureId));
}
}
}
if (two.size() > 0 && twoPrim.size() > 0) {
for (ManifestEntry manifestEntry : two) {
errorMessages.add(new ManifestErrorMessage("The signature file for signature "
+ signatureId + " has an entry for file <"
+ manifestEntry.getFileName() + "> with mimetype <" + manifestEntry.getMimeType()
+ "> but the manifest file does not have an entry for this file", signatureId));
}
}
return errorMessages;
}
private static ManifestEntry signatureEntryForFile(String fileName, Set signatureEntries) {
logger.debug("File name: " + fileName);
for (ManifestEntry signatureEntry : signatureEntries) {
if (fileName.equals(signatureEntry.getFileName())) {
return signatureEntry;
}
}
return null;
}
/**
* Validate the container.
*
* @return list of error messages
*/
public List validateDocument() {
if (!manifestParser.containsManifestFile()) {
String errorMessage = "Container does not contain manifest file.";
logger.error(errorMessage);
throw new DigiDoc4JException(errorMessage);
}
List errorMessages = new ArrayList<>();
Map manifestEntries = manifestParser.getManifestFileItems();
Set signatureEntries = new HashSet<>();
for (Signature signature : signatures) {
signatureEntries = getSignatureEntries(signature);
errorMessages.addAll(validateEntries(manifestEntries, signatureEntries, signature.getId()));
}
errorMessages.addAll(validateFilesInContainer(signatureEntries));
logger.info("Validation of meta data within the manifest file and signature files error count: "
+ errorMessages.size());
return errorMessages;
}
private List validateFilesInContainer(Set signatureEntries) {
List errorMessages = new ArrayList<>();
if (signatureEntries.size() == 0) {
return errorMessages;
}
Set signatureEntriesFileNames = this.getFileNamesFromManifestEntrySet(signatureEntries);
List filesInContainer = getFilesInContainer();
for (String fileInContainer : filesInContainer) {
String alterName = fileInContainer.replaceAll("\\ ", "+");
if (!signatureEntriesFileNames.contains(fileInContainer) && !signatureEntriesFileNames.contains(alterName)) {
errorMessages.add(new ManifestErrorMessage(String.format("Container contains a file named <%s> which is not "
+ "found in the signature file", fileInContainer)));
}
}
return errorMessages;
}
private Set getFileNamesFromManifestEntrySet(Set signatureEntries) {
Set signatureEntriesFileNames = new HashSet<>(signatureEntries.size());
for (ManifestEntry entry : signatureEntries) {
signatureEntriesFileNames.add(entry.getFileName());
}
return signatureEntriesFileNames;
}
private Set getSignatureEntries(Signature signature) {
Set signatureEntries = new HashSet<>();
XadesSignature origin = ((AsicSignature) signature).getOrigin();
List references = origin.getReferences();
for (Reference reference : references) {
if (reference.getType().equals("")) {
String mimeTypeString = null;
Node signatureNode = origin.getDssSignature().getSignatureElement();
Node node = DomUtils.getNode(signatureNode, "./ds:SignedInfo/ds:Reference[@URI=\""
+ reference.getURI() + "\"]");
if (node != null) {
String referenceId = node.getAttributes().getNamedItem("Id").getNodeValue();
String xAdESPrefix = origin.getDssSignature().getXAdESPaths().getNamespace().getPrefix();
mimeTypeString = DomUtils.getValue(signatureNode,
"./ds:Object/" + xAdESPrefix + ":QualifyingProperties/" + xAdESPrefix + ":SignedProperties/"
+ xAdESPrefix + ":SignedDataObjectProperties/" + xAdESPrefix + ":DataObjectFormat"
+ "[@ObjectReference=\"#" + referenceId + "\"]/" + xAdESPrefix + ":MimeType");
}
// TODO: mimeTypeString == null ? node == null?
String uri = getFileURI(reference);
signatureEntries.add(new ManifestEntry(uri, mimeTypeString));
}
}
return signatureEntries;
}
private String getFileURI(Reference reference) {
String uri = reference.getURI();
try {
uri = new URI(uri).getPath();
} catch (URISyntaxException e) {
logger.warn("Does not parse as an URI, therefore assuming it's not encoded: '" + uri + "'");
}
return uri;
}
private List getFilesInContainer() {
List fileEntries = new ArrayList<>();
for (DSSDocument detachedContent : detachedContents) {
String name = detachedContent.getName();
fileEntries.add(name);
}
return fileEntries;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy