diff --git a/src/main/java/digital/slovensko/autogram/core/eforms/EFormResources.java b/src/main/java/digital/slovensko/autogram/core/eforms/EFormResources.java index 54d149f8f..7816e2a27 100644 --- a/src/main/java/digital/slovensko/autogram/core/eforms/EFormResources.java +++ b/src/main/java/digital/slovensko/autogram/core/eforms/EFormResources.java @@ -15,10 +15,12 @@ import eu.europa.esig.dss.enumerations.ASiCContainerType; import eu.europa.esig.dss.enumerations.DigestAlgorithm; import eu.europa.esig.dss.model.DSSDocument; +import eu.europa.esig.dss.model.InMemoryDocument; + import org.w3c.dom.Node; public class EFormResources { - private static final String SOURCE_URL = "https://test-autogram-eforms-marek.s3.eu-central-1.amazonaws.com/v1/eforms/"; + private static final String SOURCE_URL = "https://data.gov.sk/doc/egov/eform/"; private static final Charset ENCODING = StandardCharsets.UTF_8; private final String url; @@ -41,8 +43,11 @@ public static EFormAttributes tryToLoadEFormAttributes(DSSDocument document, Str if (eformResources == null) return null; - var transformation = eformResources.findTransformation(); - var schema = eformResources.findSchema(); + var transformation = eformResources.getTransformation(); + var schema = eformResources.getSchema(); + if (transformation == null || schema == null) + throw new XMLValidationException("Zlyhala príprava elektronického formulára", "Nepodarilo sa nájsť XSLT transformáciu alebo XSD schému"); + var identifier = eformResources.getIdentifier(); var containerXmlns = "http://data.gov.sk/def/container/xmldatacontainer+xml/1.1"; var container = ASiCContainerType.ASiC_E; @@ -79,7 +84,7 @@ private static EFormResources buildEFormResourcesFromEformXml(Node xml, String c var parts = formUri.split("/"); var formVersion = parts[parts.length - 1]; var formIdentifier = parts[parts.length - 2]; - var formDirectory = formIdentifier + "/" + formVersion; + var formDirectory = SOURCE_URL + formIdentifier + "/" + formVersion; return new EFormResources(formDirectory, xsdDigest, xsltDigest); } @@ -90,12 +95,40 @@ private EFormResources(String url, String xsdDigest, String xsltDigest) { this.xsltDigest = xsltDigest; } - public String getIdentifier() { + private String getIdentifier() { return "http://data.gov.sk/doc/eform/" + url; } - public String findTransformation() throws XMLValidationException { - var xsltString = getTransformation(SOURCE_URL + url); + private String getTransformation() throws XMLValidationException { + var manifest_xml = getResource(url + "/META-INF/manifest.xml"); + if (manifest_xml == null) + return null; + + var fullPath = ""; + try { + var parsed_manifest_xml = getXmlFromDocument(new InMemoryDocument(manifest_xml, "manifest.xml")); + var nodes = parsed_manifest_xml.getElementsByTagName("manifest:file-entry"); + for (int i = 0; i < nodes.getLength(); i++) { + var node = nodes.item(i); + + var mediaDestination = node.getAttributes().getNamedItem("media-destination"); + if (mediaDestination != null && mediaDestination.getNodeValue().equals("sign")) { + fullPath = node.getAttributes().getNamedItem("full-path").getNodeValue(); + + fullPath = fullPath.replace("\\", "/"); + if (fullPath != null && fullPath.length() > 0) + break; + } + } + + } catch (XMLValidationException e) { + return null; + } + + if (fullPath == null || fullPath.length() == 0) + return null; + + var xsltString = getResource(url + "/" + fullPath); if (xsltString == null) return null; @@ -106,8 +139,8 @@ public String findTransformation() throws XMLValidationException { return new String(xsltString, ENCODING); } - public String findSchema() throws XMLValidationException { - var xsdString = getSchema(SOURCE_URL + url); + private String getSchema() throws XMLValidationException { + var xsdString = getResource(url + "/schema.xsd"); if (xsdString == null) return null; diff --git a/src/main/java/digital/slovensko/autogram/core/eforms/EFormUtils.java b/src/main/java/digital/slovensko/autogram/core/eforms/EFormUtils.java index 9b6a6eeff..c68b282fc 100644 --- a/src/main/java/digital/slovensko/autogram/core/eforms/EFormUtils.java +++ b/src/main/java/digital/slovensko/autogram/core/eforms/EFormUtils.java @@ -22,6 +22,7 @@ import org.w3c.dom.Node; import org.xml.sax.InputSource; import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; import digital.slovensko.autogram.core.errors.XMLValidationException; import digital.slovensko.autogram.core.errors.MultipleOriginalDocumentsFoundException; @@ -124,17 +125,9 @@ public static String getNamespaceFromEformXml(Node xml) { return xmlns.getNodeValue(); } - public static byte[] getTransformation(String url) { - return getResource(url + "/form.sb.xslt"); - } - - public static byte[] getSchema(String url) { - return getResource(url + "/form.xsd"); - } - - private static byte[] getResource(String url) { + public static byte[] getResource(String url) { var offlineFileLoader = new FileCacheDataLoader(); - offlineFileLoader.setCacheExpirationTime(21600000); + offlineFileLoader.setCacheExpirationTime(21600000); // 6 hours offlineFileLoader.setDataLoader(new CommonsDataLoader()); DSSDocument xsltDoc; @@ -194,6 +187,8 @@ public static Document getEformXmlFromXdcDocument(DSSDocument document) throws X throw new XMLValidationException("Zlyhala validácia XML Datacontainera", "Element XMLData je prázdny"); var idk = xmlData.getFirstChild(); + // In an indented XML, whitespaces between XMLData and its content are considered as text nodes. + // If there is a text node, validate it against all-whitespace regex and skip it. if (idk.getNodeType() == Node.TEXT_NODE) { if (!idk.getNodeValue().matches("\\s*")) throw new XMLValidationException("Zlyhala validácia XML Datacontainera", "XMLData obsahuje neplatný text"); diff --git a/src/main/java/digital/slovensko/autogram/core/eforms/XDCValidator.java b/src/main/java/digital/slovensko/autogram/core/eforms/XDCValidator.java index 576f46df6..f13839e77 100644 --- a/src/main/java/digital/slovensko/autogram/core/eforms/XDCValidator.java +++ b/src/main/java/digital/slovensko/autogram/core/eforms/XDCValidator.java @@ -31,7 +31,7 @@ public static boolean isXDCContent(DSSDocument document) { return validateXmlContentAgainstXsd(docString, new String(xdcSchema.readAllBytes(), ENCODING)); - } catch (IOException | NullPointerException e) { + } catch (IOException | NullPointerException | XMLValidationException e) { return false; } } diff --git a/src/test/java/digital/slovensko/autogram/SigningParametersTests.java b/src/test/java/digital/slovensko/autogram/SigningParametersTests.java index 4dcd23882..b30046bb7 100644 --- a/src/test/java/digital/slovensko/autogram/SigningParametersTests.java +++ b/src/test/java/digital/slovensko/autogram/SigningParametersTests.java @@ -168,7 +168,24 @@ void testThrowsAutogramExceptionWithUnknownEformXml(DSSDocument document) { @ParameterizedTest @MethodSource("digital.slovensko.autogram.TestMethodSources#unknownEfomXmlProvider") void testThrowsAutogramExceptionWithUnknownEformXmlWithAutoLoadEform(DSSDocument document) { - Assertions.assertThrows(SigningParametersException.class, + Assertions.assertThrows(XMLValidationException.class, + () -> SigningParameters.buildFromRequest(SignatureLevel.XAdES_BASELINE_B, null, null, null, null, + false, null, null, null, null, null, null, false, 800, true, document)); + } + + @ParameterizedTest + @MethodSource("digital.slovensko.autogram.TestMethodSources#mismatchedDigestsXmlProvider") + void testThrowsAutogramExceptionWithMismatchedDigestsXml(DSSDocument document) { + Assertions.assertThrows(XMLValidationException.class, + () -> SigningParameters.buildFromRequest(SignatureLevel.XAdES_BASELINE_B, asice, xdcXmlns, null, null, + false, null, null, null, xsdSchema, xsltTransformation, identifier, false, 800, false, + document)); + } + + @ParameterizedTest + @MethodSource("digital.slovensko.autogram.TestMethodSources#mismatchedDigestsXmlProvider") + void testThrowsAutogramExceptionWithMismatchedDigestsXmlWithAutoLoadEform(DSSDocument document) { + Assertions.assertThrows(XMLValidationException.class, () -> SigningParameters.buildFromRequest(SignatureLevel.XAdES_BASELINE_B, null, null, null, null, false, null, null, null, null, null, null, false, 800, true, document)); } diff --git a/src/test/java/digital/slovensko/autogram/TestMethodSources.java b/src/test/java/digital/slovensko/autogram/TestMethodSources.java index 46870a93c..cc3b7fe62 100644 --- a/src/test/java/digital/slovensko/autogram/TestMethodSources.java +++ b/src/test/java/digital/slovensko/autogram/TestMethodSources.java @@ -153,6 +153,60 @@ public static Stream validXadesDocumentsProvider() throws IOEx ); } + public static Stream xdcDocumentsProvider() throws IOException { + var generalAgendaXdcIndented = cls.getResourceAsStream("general_agenda_xdc_indented.xml").readAllBytes(); + var generalAgendaXdc = cls.getResourceAsStream("general_agenda_xdc.xml").readAllBytes(); + var mismatchedXsdGAXdc = cls.getResourceAsStream("mismatched_xsd_ga_xdc.xml").readAllBytes(); + var mismatchedXsltGAXdc = cls.getResourceAsStream("mismatched_xslt_ga_xdc.xml").readAllBytes(); + var unknownEfomXdc = cls.getResourceAsStream("unknown_eform_xdc.xml").readAllBytes(); + var wrongSchemaGAXdc = cls.getResourceAsStream("wrong_schema_ga_xdc.xml").readAllBytes(); + + return Stream.of( + new InMemoryDocument(generalAgendaXdcIndented, "generalAgendaXdcIndented.xml", AutogramMimeType.XML_DATACONTAINER), + new InMemoryDocument(generalAgendaXdc, "generalAgendaXdc.xml", AutogramMimeType.XML_DATACONTAINER), + new InMemoryDocument(mismatchedXsdGAXdc, "mismatchedXsdGAXdc.xml", AutogramMimeType.XML_DATACONTAINER), + new InMemoryDocument(mismatchedXsltGAXdc, "mismatchedXsltGAXdc.xml", AutogramMimeType.XML_DATACONTAINER), + new InMemoryDocument(unknownEfomXdc, "unknownEfomXdc.xml", AutogramMimeType.XML_DATACONTAINER), + new InMemoryDocument(wrongSchemaGAXdc, "wrongSchemaGAXdc.xml", AutogramMimeType.XML_DATACONTAINER) + ); + } + + public static Stream xdcDocumentsWithXmlMimetypeProvider() throws IOException { + var generalAgendaXdcIndented = cls.getResourceAsStream("general_agenda_xdc_indented.xml").readAllBytes(); + var generalAgendaXdc = cls.getResourceAsStream("general_agenda_xdc.xml").readAllBytes(); + var mismatchedXsdGAXdc = cls.getResourceAsStream("mismatched_xsd_ga_xdc.xml").readAllBytes(); + var mismatchedXsltGAXdc = cls.getResourceAsStream("mismatched_xslt_ga_xdc.xml").readAllBytes(); + var unknownEfomXdc = cls.getResourceAsStream("unknown_eform_xdc.xml").readAllBytes(); + var wrongSchemaGAXdc = cls.getResourceAsStream("wrong_schema_ga_xdc.xml").readAllBytes(); + + return Stream.of( + new InMemoryDocument(generalAgendaXdcIndented, "generalAgendaXdcIndented.xml", MimeTypeEnum.XML), + new InMemoryDocument(generalAgendaXdc, "generalAgendaXdc.xml", MimeTypeEnum.XML), + new InMemoryDocument(mismatchedXsdGAXdc, "mismatchedXsdGAXdc.xml", MimeTypeEnum.XML), + new InMemoryDocument(mismatchedXsltGAXdc, "mismatchedXsltGAXdc.xml", MimeTypeEnum.XML), + new InMemoryDocument(unknownEfomXdc, "unknownEfomXdc.xml", MimeTypeEnum.XML), + new InMemoryDocument(wrongSchemaGAXdc, "wrongSchemaGAXdc.xml", MimeTypeEnum.XML) + ); + } + + public static Stream nonXdcXmlDocumentsProvider() throws IOException { + var documentContentNoUsedXSDReference = cls.getResourceAsStream("document-content-no-UsedXSDReference.xml").readAllBytes(); + var documentContentUsedXSDReferenceNoAttributes = cls.getResourceAsStream("document-content-UsedXSDReference-no-attributes.xml").readAllBytes(); + var documentContentUsedXSDReferenceNoDigestValue = cls.getResourceAsStream("document-content-UsedXSDReference-no-DigestValue.xml").readAllBytes(); + var emptyXml = cls.getResourceAsStream("empty_xml.xml").readAllBytes(); + var nonEformXml = cls.getResourceAsStream("non_eform.xml").readAllBytes(); + var wrongSchemaXdcXml = cls.getResourceAsStream("wrong_schema_xdc.xml").readAllBytes(); + + return Stream.of( + new InMemoryDocument(documentContentNoUsedXSDReference, "documentContentNoUsedXSDReference.xml", MimeTypeEnum.XML), + new InMemoryDocument(documentContentUsedXSDReferenceNoAttributes, "documentContentUsedXSDReferenceNoAttributes.xml", MimeTypeEnum.XML), + new InMemoryDocument(documentContentUsedXSDReferenceNoDigestValue, "documentContentUsedXSDReferenceNoDigestValue.xml", MimeTypeEnum.XML), + new InMemoryDocument(emptyXml, "emptyXml.xml", MimeTypeEnum.XML), + new InMemoryDocument(nonEformXml, "nonEformXml.xml", MimeTypeEnum.XML), + new InMemoryDocument(wrongSchemaXdcXml, "wrongSchemaXdcXml.xml", MimeTypeEnum.XML) + ); + } + public static Stream validCadesDocumentsProvider() throws IOException { var samplePdfCadesAsice = cls.getResourceAsStream("sample_pdf_cades.asice").readAllBytes(); diff --git a/src/test/java/digital/slovensko/autogram/core/eforms/XDCValidatorTests.java b/src/test/java/digital/slovensko/autogram/core/eforms/XDCValidatorTests.java new file mode 100644 index 000000000..0605b2af1 --- /dev/null +++ b/src/test/java/digital/slovensko/autogram/core/eforms/XDCValidatorTests.java @@ -0,0 +1,22 @@ +package digital.slovensko.autogram.core.eforms; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import eu.europa.esig.dss.model.DSSDocument; + +public class XDCValidatorTests { + @ParameterizedTest + @MethodSource({"digital.slovensko.autogram.TestMethodSources#xdcDocumentsProvider", + "digital.slovensko.autogram.TestMethodSources#xdcDocumentsWithXmlMimetypeProvider"}) + void testReturnsTrueForAllXDCsRegerdlessOfMimeType(DSSDocument document) { + Assertions.assertTrue(XDCValidator.isXDCContent(document)); + } + + @ParameterizedTest + @MethodSource({"digital.slovensko.autogram.TestMethodSources#nonXdcXmlDocumentsProvider"}) + void testReturnsFalseForAllNonXDCsRegerdlessOfMimeType(DSSDocument document) { + Assertions.assertFalse(XDCValidator.isXDCContent(document)); + } +} diff --git a/src/test/resources/digital/slovensko/autogram/empty_xml.xml b/src/test/resources/digital/slovensko/autogram/empty_xml.xml new file mode 100644 index 000000000..e69de29bb diff --git a/src/test/resources/digital/slovensko/autogram/mismatched_xsd_ga_xdc.asice b/src/test/resources/digital/slovensko/autogram/mismatched_xsd_ga_xdc.asice index fd6e2844f..9175f91a2 100644 Binary files a/src/test/resources/digital/slovensko/autogram/mismatched_xsd_ga_xdc.asice and b/src/test/resources/digital/slovensko/autogram/mismatched_xsd_ga_xdc.asice differ diff --git a/src/test/resources/digital/slovensko/autogram/mismatched_xsd_ga_xdc.xml b/src/test/resources/digital/slovensko/autogram/mismatched_xsd_ga_xdc.xml index a2fb3977a..4816c5f98 100644 --- a/src/test/resources/digital/slovensko/autogram/mismatched_xsd_ga_xdc.xml +++ b/src/test/resources/digital/slovensko/autogram/mismatched_xsd_ga_xdc.xml @@ -8,7 +8,7 @@ - http://schemas.gov.sk/form/App.GeneralAgenda/1.9/form.xsd + http://schemas.gov.sk/form/App.GeneralAgenda/1.9/form.xsd http://schemas.gov.sk/form/App.GeneralAgenda/1.9/form.xslt diff --git a/src/test/resources/digital/slovensko/autogram/mismatched_xslt_ga_xdc.asice b/src/test/resources/digital/slovensko/autogram/mismatched_xslt_ga_xdc.asice index 4c20ff168..2ea670210 100644 Binary files a/src/test/resources/digital/slovensko/autogram/mismatched_xslt_ga_xdc.asice and b/src/test/resources/digital/slovensko/autogram/mismatched_xslt_ga_xdc.asice differ diff --git a/src/test/resources/digital/slovensko/autogram/mismatched_xslt_ga_xdc.xml b/src/test/resources/digital/slovensko/autogram/mismatched_xslt_ga_xdc.xml index 879fa211a..293e128ae 100644 --- a/src/test/resources/digital/slovensko/autogram/mismatched_xslt_ga_xdc.xml +++ b/src/test/resources/digital/slovensko/autogram/mismatched_xslt_ga_xdc.xml @@ -9,6 +9,6 @@ http://schemas.gov.sk/form/App.GeneralAgenda/1.9/form.xsd - http://schemas.gov.sk/form/App.GeneralAgenda/1.9/form.xslt + http://schemas.gov.sk/form/App.GeneralAgenda/1.9/form.xslt