From 8aba1b4f18f5fbfebdf239b4b4945b628e439905 Mon Sep 17 00:00:00 2001 From: Christof Rabensteiner Date: Tue, 9 Jul 2019 14:11:47 +0200 Subject: Refactor Needles Interfaces and Rename "process" to "backend" Reason: - Interfaces with a single method can be replaced with interfaces from java.util.function. - Less interfaces = less code = less maintenance! - Spring can inject beans by name so we name dependencies correctly to prevent ambiguity. Others: - Rename process to backend since backend gives a better description of its components. --- .../egiz/moazs/backend/DeliveryRequestBackend.java | 112 +++++++++++ .../gv/egiz/moazs/backend/MsgResponseBackend.java | 75 ++++++++ .../egiz/moazs/backend/SaveResponseToFileSink.java | 89 +++++++++ .../gv/egiz/moazs/backend/SignatureVerifier.java | 116 ++++++++++++ .../java/at/gv/egiz/moazs/config/MoaSigConfig.java | 12 +- .../at/gv/egiz/moazs/config/PreprocessConfig.java | 7 +- .../at/gv/egiz/moazs/config/ServicesConfig.java | 3 +- .../at/gv/egiz/moazs/process/DeliveryPipeline.java | 17 -- .../gv/egiz/moazs/process/MsgResponseHandler.java | 7 - .../at/gv/egiz/moazs/process/MsgResponseSink.java | 11 -- .../egiz/moazs/process/SaveResponseToFileSink.java | 87 --------- .../moazs/process/SingleNodeResponseHandler.java | 26 --- .../process/SingleThreadedDeliveryPipeline.java | 103 ----------- .../java/at/gv/egiz/moazs/service/MsgService.java | 11 +- .../java/at/gv/egiz/moazs/service/MzsService.java | 10 +- .../moazs/verify/MoaSPSSSignatureVerifier.java | 111 ----------- .../gv/egiz/moazs/verify/MsgResponseVerifier.java | 54 ------ .../at/gv/egiz/moazs/verify/SignatureVerifier.java | 13 -- .../gv/egiz/moazs/DeliveryRequestBackendTest.java | 203 ++++++++++++++++++++ .../egiz/moazs/ITMoaSPSSSignatureVerifierTest.java | 9 +- .../java/at/gv/egiz/moazs/ITMzsServiceTest.java | 8 +- .../gv/egiz/moazs/SaveResponseToFileSinkTest.java | 4 +- .../moazs/SingleThreadedDeliveryPipelineTest.java | 204 --------------------- 23 files changed, 624 insertions(+), 668 deletions(-) create mode 100644 src/main/java/at/gv/egiz/moazs/backend/DeliveryRequestBackend.java create mode 100644 src/main/java/at/gv/egiz/moazs/backend/MsgResponseBackend.java create mode 100644 src/main/java/at/gv/egiz/moazs/backend/SaveResponseToFileSink.java create mode 100644 src/main/java/at/gv/egiz/moazs/backend/SignatureVerifier.java delete mode 100644 src/main/java/at/gv/egiz/moazs/process/DeliveryPipeline.java delete mode 100644 src/main/java/at/gv/egiz/moazs/process/MsgResponseHandler.java delete mode 100644 src/main/java/at/gv/egiz/moazs/process/MsgResponseSink.java delete mode 100644 src/main/java/at/gv/egiz/moazs/process/SaveResponseToFileSink.java delete mode 100644 src/main/java/at/gv/egiz/moazs/process/SingleNodeResponseHandler.java delete mode 100644 src/main/java/at/gv/egiz/moazs/process/SingleThreadedDeliveryPipeline.java delete mode 100644 src/main/java/at/gv/egiz/moazs/verify/MoaSPSSSignatureVerifier.java delete mode 100644 src/main/java/at/gv/egiz/moazs/verify/MsgResponseVerifier.java delete mode 100644 src/main/java/at/gv/egiz/moazs/verify/SignatureVerifier.java create mode 100644 src/test/java/at/gv/egiz/moazs/DeliveryRequestBackendTest.java delete mode 100644 src/test/java/at/gv/egiz/moazs/SingleThreadedDeliveryPipelineTest.java diff --git a/src/main/java/at/gv/egiz/moazs/backend/DeliveryRequestBackend.java b/src/main/java/at/gv/egiz/moazs/backend/DeliveryRequestBackend.java new file mode 100644 index 0000000..06eba80 --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/backend/DeliveryRequestBackend.java @@ -0,0 +1,112 @@ +package at.gv.egiz.moazs.backend; + + +import at.gv.egiz.moazs.MoaZSException; +import at.gv.egiz.moazs.client.ClientFactory; +import at.gv.egiz.moazs.client.TnvzHelper; +import at.gv.egiz.moazs.repository.DeliveryRepository; +import at.gv.egiz.moazs.scheme.Mzs2MsgConverter; +import at.gv.egiz.moazs.scheme.RequestStatusResponse; +import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType; +import at.gv.zustellung.msg.xsd.App2ZusePort; +import at.gv.zustellung.tnvz.xsd.TNVZServicePort; +import org.apache.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +import java.util.function.Consumer; + +import static at.gv.egiz.moazs.MoaZSException.moaZSExceptionBuilder; +import static at.gv.egiz.moazs.scheme.RequestStatusResponse.generateErrorFromException; +import static java.lang.String.format; + +@Component +@Profile("!cluster") +public class DeliveryRequestBackend implements Consumer { + + private static final Logger log = Logger.getLogger(DeliveryRequestBackend.class); + private static final String MZS_PIPELINE_ERROR_MSG = + "An error occured while processing the DeliveryRequest with AppDeliveryID=%s. "; + + private final DeliveryRepository repository; + private final TnvzHelper tnvzHelper; + private final Mzs2MsgConverter converter; + private final ClientFactory clientFactory; + private final Consumer signatureVerifier; + + @Autowired + public DeliveryRequestBackend(DeliveryRepository repository, + TnvzHelper tnvzHelper, + Mzs2MsgConverter converter, + ClientFactory clientFactory, + Consumer signatureVerifier) { + this.repository = repository; + this.tnvzHelper = tnvzHelper; + this.converter = converter; + this.clientFactory = clientFactory; + this.signatureVerifier = signatureVerifier; + } + + /** + * Performs all {@code DeliveryRequest}'s Back-End Tasks. + * + * Fetches {@code DeliveryRequest} referred by appDeliveryID from + * {@code DeliveryRepository}, makes sure that all necessary + * tasks (query tnvz, query msg, accept status) are executed and + * stores the response back to {@code DeliveryRepository}. + * @param appDeliveryID + */ + @Override + public void accept(String appDeliveryID) { + + var exceptionBuilder = moaZSExceptionBuilder(); + + try { + var mzsRequest = repository.retrieveDeliveryRequest(appDeliveryID).orElseThrow(); + exceptionBuilder.withDeliverySystem(mzsRequest); + + at.gv.zustellung.msg.xsd.DeliveryRequestType msgRequest = buildMsgRequest(mzsRequest, exceptionBuilder); + + var msgClientParams = mzsRequest.getConfig().getMSGClient(); + App2ZusePort client = clientFactory.create(msgClientParams, App2ZusePort.class); + var status = client.delivery(msgRequest); + + var response = new RequestStatusResponse(status); + exceptionBuilder.withAllParametersInAnswer(response.getAnswer()); + + verifySignedStatus(response.getResponseID(), appDeliveryID, exceptionBuilder); + repository.store(response); + + } catch (MoaZSException exception) { + log.error(format(MZS_PIPELINE_ERROR_MSG, appDeliveryID), exception); + var errorResponse = generateErrorFromException(exception); + repository.store(errorResponse); + } + } + + private void verifySignedStatus(String responseID, String appDeliveryID, MoaZSException.Builder exceptionBuilder) throws MoaZSException { + try { + var signedStatus = repository.retrieveBinaryResponse(responseID).get(); + signatureVerifier.accept(signedStatus); + } catch (MoaZSException ex) { + throw exceptionBuilder.withMessage(format(MsgResponseBackend.MOASP_SIGNATURE_INVALID_ERROR_MSG, appDeliveryID)) + .withErrorCode(MoaZSException.ERROR_MOASP_SIGNATURE_INVALID) + .withCause(ex) + .build(); + } + } + + private at.gv.zustellung.msg.xsd.DeliveryRequestType buildMsgRequest(DeliveryRequestType mzsRequest, + MoaZSException.Builder exceptionBuilder) throws MoaZSException { + if (mzsRequest.getConfig().isPerformQueryPersonRequest()) { + var tnvzClientParams = mzsRequest.getConfig().getTNVZClient(); + TNVZServicePort tvnzPort = clientFactory.create(tnvzClientParams, TNVZServicePort.class); + var identification = tnvzHelper.performQueryPersonRequest(mzsRequest, tvnzPort, exceptionBuilder); + return converter.convert(mzsRequest, identification); + } else { + return converter.convert(mzsRequest); + } + } + +} diff --git a/src/main/java/at/gv/egiz/moazs/backend/MsgResponseBackend.java b/src/main/java/at/gv/egiz/moazs/backend/MsgResponseBackend.java new file mode 100644 index 0000000..414c2dc --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/backend/MsgResponseBackend.java @@ -0,0 +1,75 @@ +package at.gv.egiz.moazs.backend; + +import at.gv.egiz.moazs.MoaZSException; +import at.gv.egiz.moazs.repository.DeliveryRepository; +import at.gv.egiz.moazs.scheme.MsgResponse; +import at.gv.egiz.moazs.service.MsgService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import java.util.function.Function; + +import static at.gv.egiz.moazs.MoaZSException.moaZSExceptionBuilder; +import static java.lang.String.format; +import static java.util.concurrent.CompletableFuture.supplyAsync; + +@Component +public class MsgResponseBackend implements Consumer { + + private static final Logger log = LoggerFactory.getLogger(MsgService.class); + + public static final String MOASP_SIGNATURE_INVALID_ERROR_MSG = "Signature of Msg Response " + + "with AppDeliveryID=%s is not valid."; + + private final DeliveryRepository repository; + private final Consumer signatureVerifier; + private final Function> sink; + + @Autowired + public MsgResponseBackend(DeliveryRepository repository, + Consumer signatureVerifier, + Function> sink) { + this.repository = repository; + this.signatureVerifier = signatureVerifier; + this.sink = sink; + } + + /** + * Performs all {@code MsgResponse}'s Back-End Tasks, such as verifying + * its signature and archiving the response. + * + * @param responseID refers to MsgResponse Object. + */ + @Override + public void accept(String responseID) { + supplyAsync(() -> verify(responseID)).thenAcceptAsync(sink::apply); + } + + public MsgResponse verify(String responseID) { + + var response = repository.retrieveResponse(responseID).get(); + var builder = moaZSExceptionBuilder().withAllParametersInAnswer(response.getAnswer()); + + var binaryResponse = repository.retrieveBinaryResponse(responseID).get(); + + try { + signatureVerifier.accept(binaryResponse); + return response; + } catch (MoaZSException ex) { + log.error(ex.getMessage(), ex); + var wrappingEx = builder + .withMessage(format(MOASP_SIGNATURE_INVALID_ERROR_MSG, response.getAppDeliveryID())) + .withErrorCode(MoaZSException.ERROR_MOASP_SIGNATURE_INVALID) + .withCause(ex) + .build(); + + return response.generateError(wrappingEx); + } + + } + +} diff --git a/src/main/java/at/gv/egiz/moazs/backend/SaveResponseToFileSink.java b/src/main/java/at/gv/egiz/moazs/backend/SaveResponseToFileSink.java new file mode 100644 index 0000000..02771a9 --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/backend/SaveResponseToFileSink.java @@ -0,0 +1,89 @@ +package at.gv.egiz.moazs.backend; + +import at.gv.egiz.moazs.repository.DeliveryRepository; +import at.gv.egiz.moazs.scheme.Marshaller; +import at.gv.egiz.moazs.scheme.MsgResponse; +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; + +import static at.gv.egiz.moazs.MoaZSException.moaZSException; +import static java.lang.String.format; +import static java.util.concurrent.CompletableFuture.allOf; +import static java.util.concurrent.CompletableFuture.supplyAsync; + +@Component +public class SaveResponseToFileSink implements Function> { + + private static final Logger log = LoggerFactory.getLogger(SaveResponseToFileSink.class); + private static final String SAVING_FAILED_MSG = "Could not save response with AppDeliveryId=%s."; + + private final SimpleDateFormat isoFormatter; + private final Marshaller msgMarshaller; + private final DeliveryRepository repository; + private final String root; + + @Autowired + public SaveResponseToFileSink(Marshaller msgMarshaller, DeliveryRepository repository, String root) { + this.msgMarshaller = msgMarshaller; + this.repository = repository; + this.root = root; + this.isoFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); + } + + @Override + public CompletableFuture apply(MsgResponse response) { + + var responseID = response.getResponseID(); + + var responsePath = generatePath(responseID, "xml"); + var storeResponseToFileSystemFuture = supplyAsync(() -> msgMarshaller.marshallXml(response.getResponse())) + .thenApply(responseString -> responseString.getBytes(StandardCharsets.UTF_8)) + .thenAccept(responseByteArray -> storeToFile(responsePath, responseByteArray)) + .exceptionally(ex -> logException(ex, responseID)); + + var binaryResponsePath = generatePath(responseID, "binary.xml"); + var storeBinaryResponseToFileSystemFuture = supplyAsync(() -> repository.retrieveBinaryResponse(responseID).get()) + .thenAccept(binaryResponseByteArray -> storeToFile(binaryResponsePath, binaryResponseByteArray)) + .exceptionally(ex -> logException(ex, responseID)); + + return allOf(storeResponseToFileSystemFuture, storeBinaryResponseToFileSystemFuture); + + } + + private String generatePath(String id, String suffix) { + var folder = sanitizeFileString(id); + var nowInIso8601 = isoFormatter.format(new Date()); + return format("%s/%s/%s.%s", root, folder, nowInIso8601, suffix); + } + + private String sanitizeFileString(String fileString) { + return fileString.replaceAll("[^a-zA-Z0-9\\._\\-]", ""); + } + + private Void logException(Throwable ex, String appDeliveryID) { + if(log.isErrorEnabled()) { + log.error(format(SAVING_FAILED_MSG, appDeliveryID), ex); + } + return null; + } + + private void storeToFile(String path, byte[] content) { + try { + FileUtils.writeByteArrayToFile(new File(path), content); + } catch (IOException e) { + throw moaZSException(e.getMessage(), e); + } + } + +} diff --git a/src/main/java/at/gv/egiz/moazs/backend/SignatureVerifier.java b/src/main/java/at/gv/egiz/moazs/backend/SignatureVerifier.java new file mode 100644 index 0000000..e9c5387 --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/backend/SignatureVerifier.java @@ -0,0 +1,116 @@ +package at.gv.egiz.moazs.backend; + +import at.gv.egiz.eid.authhandler.modules.sigverify.moasig.api.ISignatureVerificationService; +import at.gv.egiz.eid.authhandler.modules.sigverify.moasig.api.data.IXMLSignatureVerificationResponse; +import at.gv.egiz.eid.authhandler.modules.sigverify.moasig.exceptions.MOASigServiceException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.function.Consumer; + +import static at.gv.egiz.moazs.MoaZSException.moaZSException; +import static at.gv.egiz.moazs.MoaZSException.moaZSExceptionBuilder; +import static java.lang.String.format; + +public class SignatureVerifier implements Consumer { + + private static final Logger log = LoggerFactory.getLogger(SignatureVerifier.class); + private static final int OK_CODE = 0; + + private final ISignatureVerificationService service; + private final String trustProfile; + private final boolean isManifestCheckActive; + + public SignatureVerifier(ISignatureVerificationService service, + String trustProfile, boolean isManifestCheckActive) { + this.service = service; + this.trustProfile = trustProfile; + this.isManifestCheckActive = isManifestCheckActive; + } + + /** + * Verifies the signature of a signed XML document. Throws a at.gv.egiz.moazs.MoaZSException exception + * if the validation fails. + * @param signedXMLdocument + * @throws at.gv.egiz.moazs.MoaZSException + */ + @Override + public void accept(byte[] signedXMLdocument) { + + try { + var response = service.verifyXMLSignature(signedXMLdocument, trustProfile); + + if (log.isDebugEnabled()) { + print(response); + } + + if (response == null) { + throw moaZSException("MOA SPSS could not find the signature. "); + } + + var builder = new StringBuilder(); + + if (response.getSignatureCheckCode() != OK_CODE) { + builder.append(format("Signature is not valid; SignatureCheckCode was %d. ", + response.getSignatureCheckCode())); + } + + if (response.getCertificateCheckCode() != OK_CODE) { + builder.append(format("Certificate chain is not valid; CertificateCheckCode was %d. ", + response.getCertificateCheckCode())); + } + + if (response.getSignatureManifestCheckCode() != OK_CODE) { + var signatureManifestErrorMsg = format("Signature Manifest is not valid; " + + "SignatureManifestCheckCode was %d. ", response.getSignatureManifestCheckCode()); + if (isManifestCheckActive) { + builder.append(signatureManifestErrorMsg); + } else { + log.warn(signatureManifestErrorMsg); + } + } + + if (response.isXmlDSIGManigest() && response.getXmlDSIGManifestCheckCode() != OK_CODE) { + var xmlDSIGManifestErrorMsg = format("XmlDSIGManifest Manifest is not valid; " + + "XmlDSIGManifest was %d. ", response.getXmlDSIGManifestCheckCode()); + if (isManifestCheckActive) { + builder.append(xmlDSIGManifestErrorMsg); + } else { + log.warn(xmlDSIGManifestErrorMsg); + } + } + + var msg = builder.toString(); + + if(msg.length() > 0) { + throw moaZSException(msg); + } + + } catch (MOASigServiceException e) { + throw moaZSExceptionBuilder("Could not accept the XML signature.") + .withCause(e) + .build(); + } + + } + + private void print(IXMLSignatureVerificationResponse response) { + log.debug("Response:"); + + if (response == null) { + log.debug("null"); + return; + } + + log.debug(" XmlDsigSubjectName: {}", response.getXmlDsigSubjectName()); + log.debug(" SignatureManifestCheckCode: {}", response.getSignatureManifestCheckCode()); + log.debug(" XmlDSIGManifestCheckCode: {}", response.getXmlDSIGManifestCheckCode()); + log.debug(" CertificateCheckCode: {}", response.getCertificateCheckCode()); + log.debug(" SignatureCheckCode: {}", response.getSignatureCheckCode()); + log.debug(" SigningDateTime: {}", response.getSigningDateTime()); + log.debug(" isXmlDSIGManigest: {}", response.isXmlDSIGManigest()); + log.debug(" isPublicAuthority: {}", response.isPublicAuthority()); + log.debug(" isQualifiedCertificate: {}", response.isQualifiedCertificate()); + log.debug(" getPublicAuthorityCode: {}", response.getPublicAuthorityCode()); + } +} diff --git a/src/main/java/at/gv/egiz/moazs/config/MoaSigConfig.java b/src/main/java/at/gv/egiz/moazs/config/MoaSigConfig.java index 0b7bdc7..e02c11d 100644 --- a/src/main/java/at/gv/egiz/moazs/config/MoaSigConfig.java +++ b/src/main/java/at/gv/egiz/moazs/config/MoaSigConfig.java @@ -3,8 +3,7 @@ package at.gv.egiz.moazs.config; import at.gv.egiz.eid.authhandler.modules.sigverify.moasig.api.ISignatureVerificationService; import at.gv.egiz.eid.authhandler.modules.sigverify.moasig.impl.SignatureVerificationService; import at.gv.egiz.moazs.util.FileUtils; -import at.gv.egiz.moazs.verify.MoaSPSSSignatureVerifier; -import at.gv.egiz.moazs.verify.SignatureVerifier; +import at.gv.egiz.moazs.backend.SignatureVerifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -14,6 +13,7 @@ import org.springframework.context.annotation.Configuration; import java.io.File; import java.io.FileNotFoundException; +import java.util.function.Consumer; @Configuration @@ -62,8 +62,6 @@ public class MoaSigConfig { } } - - private void fallBackToSpringEnvForJavaxNetSSLStoreTypeProperty() { if (System.getProperty(JAVAX_SSL_TRUSTSTORE_TYPE_PROPERTY) == null) { log.info(SET_PROPERTY_MSG_TEMPLATE, JAVAX_SSL_TRUSTSTORE_TYPE_PROPERTY, trustStoreType); @@ -87,11 +85,11 @@ public class MoaSigConfig { } @Bean - public SignatureVerifier signatureVerifier(@Value("${moa.spss.is-active}") boolean isMoaSPSSActive, - @Value("${moa.spss.is-manifest-check-active}") boolean isManifestCheckActive) { + public Consumer signatureVerifier(@Value("${moa.spss.is-active}") boolean isMoaSPSSActive, + @Value("${moa.spss.is-manifest-check-active}") boolean isManifestCheckActive) { if (isMoaSPSSActive) { log.info("Moa SPSS is active. Signatures in SOAP Messages will be verified."); - return new MoaSPSSSignatureVerifier(moaSigVerifyService(), defaultTrustProfile, isManifestCheckActive); + return new SignatureVerifier(moaSigVerifyService(), defaultTrustProfile, isManifestCheckActive); } else { log.warn("Moa SPSS is not active. Signatures in SOAP Messages will not be verified."); return signedXMLdocument -> {}; diff --git a/src/main/java/at/gv/egiz/moazs/config/PreprocessConfig.java b/src/main/java/at/gv/egiz/moazs/config/PreprocessConfig.java index 76bfb30..29797dd 100644 --- a/src/main/java/at/gv/egiz/moazs/config/PreprocessConfig.java +++ b/src/main/java/at/gv/egiz/moazs/config/PreprocessConfig.java @@ -21,15 +21,14 @@ public class PreprocessConfig { return generator.generate(); } - @Value("${verify-completeness-of-default-delivery-request-configuration:true}") - private boolean verifyCompletenessOfDefaultConfiguration; - @Bean @Autowired public ConfigProfileGenerator configProfileGenerator( SpringPropertiesFacade properties, MzsDeliveryRequestValidator validator, - ConfigUtil util) { + ConfigUtil util, + @Value("${verify-completeness-of-default-delivery-request-configuration:true}") + boolean verifyCompletenessOfDefaultConfiguration) { return configProfileGeneratorBuilder() .withProperties(properties) diff --git a/src/main/java/at/gv/egiz/moazs/config/ServicesConfig.java b/src/main/java/at/gv/egiz/moazs/config/ServicesConfig.java index 42019b1..c16dfd2 100644 --- a/src/main/java/at/gv/egiz/moazs/config/ServicesConfig.java +++ b/src/main/java/at/gv/egiz/moazs/config/ServicesConfig.java @@ -38,7 +38,8 @@ public class ServicesConfig { return new Zuse2AppPortService(); } - @Bean public App2Mzs app2mzs() { + @Bean + public App2Mzs app2mzs() { return new App2Mzs(); } diff --git a/src/main/java/at/gv/egiz/moazs/process/DeliveryPipeline.java b/src/main/java/at/gv/egiz/moazs/process/DeliveryPipeline.java deleted file mode 100644 index 506dd1f..0000000 --- a/src/main/java/at/gv/egiz/moazs/process/DeliveryPipeline.java +++ /dev/null @@ -1,17 +0,0 @@ -package at.gv.egiz.moazs.process; - - -public interface DeliveryPipeline { - - /** - * Performs all {@code DeliveryRequest}'s Back-End Tasks. - * - * Fetches {@code DeliveryRequest} referred by appDeliveryId from - * {@code DeliveryRepository}, makes sure that all necessary - * tasks (query tnvz, query msg, verify status) are executed and - * stores the response back to {@code DeliveryRepository}. - * @param appDeliveryId - */ - void processRequest(String appDeliveryId); - -} diff --git a/src/main/java/at/gv/egiz/moazs/process/MsgResponseHandler.java b/src/main/java/at/gv/egiz/moazs/process/MsgResponseHandler.java deleted file mode 100644 index 5a7d39b..0000000 --- a/src/main/java/at/gv/egiz/moazs/process/MsgResponseHandler.java +++ /dev/null @@ -1,7 +0,0 @@ -package at.gv.egiz.moazs.process; - -public interface MsgResponseHandler { - - void handle(String id); - -} diff --git a/src/main/java/at/gv/egiz/moazs/process/MsgResponseSink.java b/src/main/java/at/gv/egiz/moazs/process/MsgResponseSink.java deleted file mode 100644 index 67348fc..0000000 --- a/src/main/java/at/gv/egiz/moazs/process/MsgResponseSink.java +++ /dev/null @@ -1,11 +0,0 @@ -package at.gv.egiz.moazs.process; - -import at.gv.egiz.moazs.scheme.MsgResponse; - -import java.util.concurrent.CompletableFuture; - -public interface MsgResponseSink { - - CompletableFuture handle(MsgResponse response); - -} diff --git a/src/main/java/at/gv/egiz/moazs/process/SaveResponseToFileSink.java b/src/main/java/at/gv/egiz/moazs/process/SaveResponseToFileSink.java deleted file mode 100644 index 09d8570..0000000 --- a/src/main/java/at/gv/egiz/moazs/process/SaveResponseToFileSink.java +++ /dev/null @@ -1,87 +0,0 @@ -package at.gv.egiz.moazs.process; - -import at.gv.egiz.moazs.repository.DeliveryRepository; -import at.gv.egiz.moazs.scheme.Marshaller; -import at.gv.egiz.moazs.scheme.MsgResponse; -import org.apache.commons.io.FileUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.concurrent.CompletableFuture; - -import static at.gv.egiz.moazs.MoaZSException.moaZSException; -import static java.lang.String.format; -import static java.util.concurrent.CompletableFuture.allOf; -import static java.util.concurrent.CompletableFuture.supplyAsync; - -@Component -public class SaveResponseToFileSink implements MsgResponseSink { - - private static final Logger log = LoggerFactory.getLogger(SaveResponseToFileSink.class); - private static final String SAVING_FAILED_MSG = "Could not save response with AppDeliveryId=%s."; - - private final SimpleDateFormat isoFormatter; - private final Marshaller msgMarshaller; - private final DeliveryRepository repository; - private final String root; - - @Autowired - public SaveResponseToFileSink(Marshaller msgMarshaller, DeliveryRepository repository, String root) { - this.msgMarshaller = msgMarshaller; - this.repository = repository; - this.root = root; - this.isoFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); - } - - @Override - public CompletableFuture handle(MsgResponse response) { - - var responseID = response.getResponseID(); - - var responsePath = generatePath(responseID, "xml"); - var storeResponseToFileSystemFuture = supplyAsync(() -> msgMarshaller.marshallXml(response.getResponse())) - .thenApply(responseString -> responseString.getBytes(StandardCharsets.UTF_8)) - .thenAccept(responseByteArray -> storeToFile(responsePath, responseByteArray)) - .exceptionally(ex -> logException(ex, responseID)); - - var binaryResponsePath = generatePath(responseID, "binary.xml"); - var storeBinaryResponseToFileSystemFuture = supplyAsync(() -> repository.retrieveBinaryResponse(responseID).get()) - .thenAccept(binaryResponseByteArray -> storeToFile(binaryResponsePath, binaryResponseByteArray)) - .exceptionally(ex -> logException(ex, responseID)); - - return allOf(storeResponseToFileSystemFuture, storeBinaryResponseToFileSystemFuture); - - } - - private String generatePath(String id, String suffix) { - var folder = sanitizeFileString(id); - var nowInIso8601 = isoFormatter.format(new Date()); - return format("%s/%s/%s.%s", root, folder, nowInIso8601, suffix); - } - - private String sanitizeFileString(String fileString) { - return fileString.replaceAll("[^a-zA-Z0-9\\._\\-]", ""); - } - - private Void logException(Throwable ex, String appDeliveryID) { - if(log.isErrorEnabled()) { - log.error(format(SAVING_FAILED_MSG, appDeliveryID), ex); - } - return null; - } - - private void storeToFile(String path, byte[] content) { - try { - FileUtils.writeByteArrayToFile(new File(path), content); - } catch (IOException e) { - throw moaZSException(e.getMessage(), e); - } - } -} diff --git a/src/main/java/at/gv/egiz/moazs/process/SingleNodeResponseHandler.java b/src/main/java/at/gv/egiz/moazs/process/SingleNodeResponseHandler.java deleted file mode 100644 index 65f5eed..0000000 --- a/src/main/java/at/gv/egiz/moazs/process/SingleNodeResponseHandler.java +++ /dev/null @@ -1,26 +0,0 @@ -package at.gv.egiz.moazs.process; - -import at.gv.egiz.moazs.verify.MsgResponseVerifier; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import static java.util.concurrent.CompletableFuture.supplyAsync; - -@Component -public class SingleNodeResponseHandler implements MsgResponseHandler { - - private final MsgResponseVerifier verifier; - private final MsgResponseSink sink; - - @Autowired - public SingleNodeResponseHandler(MsgResponseVerifier verifier, MsgResponseSink sink) { - this.verifier = verifier; - this.sink = sink; - } - - @Override - public void handle(String responseID) { - supplyAsync(() -> verifier.verify(responseID)) - .thenAcceptAsync(response -> sink.handle(response)); - } -} diff --git a/src/main/java/at/gv/egiz/moazs/process/SingleThreadedDeliveryPipeline.java b/src/main/java/at/gv/egiz/moazs/process/SingleThreadedDeliveryPipeline.java deleted file mode 100644 index 445f386..0000000 --- a/src/main/java/at/gv/egiz/moazs/process/SingleThreadedDeliveryPipeline.java +++ /dev/null @@ -1,103 +0,0 @@ -package at.gv.egiz.moazs.process; - - -import at.gv.egiz.moazs.MoaZSException; -import at.gv.egiz.moazs.client.ClientFactory; -import at.gv.egiz.moazs.client.TnvzHelper; -import at.gv.egiz.moazs.repository.DeliveryRepository; -import at.gv.egiz.moazs.scheme.Mzs2MsgConverter; -import at.gv.egiz.moazs.scheme.RequestStatusResponse; -import at.gv.egiz.moazs.verify.MsgResponseVerifier; -import at.gv.egiz.moazs.verify.SignatureVerifier; -import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType; -import at.gv.zustellung.msg.xsd.App2ZusePort; -import at.gv.zustellung.tnvz.xsd.TNVZServicePort; -import org.apache.log4j.Logger; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Profile; -import org.springframework.stereotype.Component; - -import static at.gv.egiz.moazs.MoaZSException.moaZSExceptionBuilder; -import static at.gv.egiz.moazs.scheme.RequestStatusResponse.generateErrorFromException; -import static java.lang.String.format; - -@Component -@Profile("!cluster") -public class SingleThreadedDeliveryPipeline implements DeliveryPipeline { - - private static final Logger log = Logger.getLogger(SingleThreadedDeliveryPipeline.class); - private static final String MZS_PIPELINE_ERROR_MSG = - "An error occured while processing the DeliveryRequest with AppDeliveryID=%s. "; - - private final DeliveryRepository repository; - private final TnvzHelper tnvzHelper; - private final Mzs2MsgConverter converter; - private final ClientFactory clientFactory; - private final SignatureVerifier verifier; - - @Autowired - public SingleThreadedDeliveryPipeline(DeliveryRepository repository, - TnvzHelper tnvzHelper, - Mzs2MsgConverter converter, - ClientFactory clientFactory, - SignatureVerifier verifier) { - this.repository = repository; - this.tnvzHelper = tnvzHelper; - this.converter = converter; - this.clientFactory = clientFactory; - this.verifier = verifier; - } - - @Override - public void processRequest(String appDeliveryID) { - - var exceptionBuilder = moaZSExceptionBuilder(); - - try { - var mzsRequest = repository.retrieveDeliveryRequest(appDeliveryID).orElseThrow(); - exceptionBuilder.withDeliverySystem(mzsRequest); - - at.gv.zustellung.msg.xsd.DeliveryRequestType msgRequest = buildMsgRequest(mzsRequest, exceptionBuilder); - - var msgClientParams = mzsRequest.getConfig().getMSGClient(); - App2ZusePort client = clientFactory.create(msgClientParams, App2ZusePort.class); - var status = client.delivery(msgRequest); - - var response = new RequestStatusResponse(status); - exceptionBuilder.withAllParametersInAnswer(response.getAnswer()); - - verifySignedStatus(response.getResponseID(), appDeliveryID, exceptionBuilder); - repository.store(response); - - } catch (MoaZSException exception) { - log.error(format(MZS_PIPELINE_ERROR_MSG, appDeliveryID), exception); - var errorResponse = generateErrorFromException(exception); - repository.store(errorResponse); - } - } - - private void verifySignedStatus(String responseID, String appDeliveryID, MoaZSException.Builder exceptionBuilder) throws MoaZSException { - try { - var signedStatus = repository.retrieveBinaryResponse(responseID).get(); - verifier.verify(signedStatus); - } catch (MoaZSException ex) { - throw exceptionBuilder.withMessage(format(MsgResponseVerifier.MOASP_SIGNATURE_INVALID_ERROR_MSG, appDeliveryID)) - .withErrorCode(MoaZSException.ERROR_MOASP_SIGNATURE_INVALID) - .withCause(ex) - .build(); - } - } - - private at.gv.zustellung.msg.xsd.DeliveryRequestType buildMsgRequest(DeliveryRequestType mzsRequest, - MoaZSException.Builder exceptionBuilder) throws MoaZSException { - if (mzsRequest.getConfig().isPerformQueryPersonRequest()) { - var tnvzClientParams = mzsRequest.getConfig().getTNVZClient(); - TNVZServicePort tvnzPort = clientFactory.create(tnvzClientParams, TNVZServicePort.class); - var identification = tnvzHelper.performQueryPersonRequest(mzsRequest, tvnzPort, exceptionBuilder); - return converter.convert(mzsRequest, identification); - } else { - return converter.convert(mzsRequest); - } - } - -} diff --git a/src/main/java/at/gv/egiz/moazs/service/MsgService.java b/src/main/java/at/gv/egiz/moazs/service/MsgService.java index 87644a0..9f94cb3 100644 --- a/src/main/java/at/gv/egiz/moazs/service/MsgService.java +++ b/src/main/java/at/gv/egiz/moazs/service/MsgService.java @@ -1,5 +1,4 @@ package at.gv.egiz.moazs.service; -import at.gv.egiz.moazs.process.MsgResponseHandler; import at.gv.egiz.moazs.repository.DeliveryRepository; import at.gv.egiz.moazs.scheme.MsgResponse; import at.gv.egiz.moazs.scheme.NameSpace; @@ -10,6 +9,8 @@ import org.apache.cxf.annotations.SchemaValidation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.function.Consumer; + import static at.gv.zustellung.msg.xsd.DeliveryNotificationACKType.deliveryNotificationACKTypeBuilder; import static at.gv.zustellung.msg.xsd.DeliveryRequestStatusACKType.deliveryRequestStatusACKTypeBuilder; import static at.gv.zustellung.msg.xsd.GetVersionResponse.getVersionResponseBuilder; @@ -20,12 +21,12 @@ import static java.util.concurrent.CompletableFuture.runAsync; public class MsgService implements Zuse2AppPort { private final DeliveryRepository repository; - private final MsgResponseHandler handler; + private final Consumer backend; @Autowired - public MsgService(DeliveryRepository repository, MsgResponseHandler handler) { + public MsgService(DeliveryRepository repository, Consumer msgResponseBackend) { this.repository = repository; - this.handler = handler; + this.backend = msgResponseBackend; } @Override @@ -59,7 +60,7 @@ public class MsgService implements Zuse2AppPort { private void sendToWork(MsgResponse response) { runAsync(() -> repository.store(response)) - .thenRunAsync(() -> handler.handle(response.getResponseID())); + .thenRunAsync(() -> backend.accept(response.getResponseID())); } private DeliveryNotificationACKType notificationAck(String appDeliveryID, String zsDeliveryID) { diff --git a/src/main/java/at/gv/egiz/moazs/service/MzsService.java b/src/main/java/at/gv/egiz/moazs/service/MzsService.java index 2755a37..c8c0878 100644 --- a/src/main/java/at/gv/egiz/moazs/service/MzsService.java +++ b/src/main/java/at/gv/egiz/moazs/service/MzsService.java @@ -1,7 +1,6 @@ package at.gv.egiz.moazs.service; import at.gv.egiz.moazs.preprocess.DeliveryRequestAugmenter; -import at.gv.egiz.moazs.process.DeliveryPipeline; import at.gv.egiz.moazs.repository.DeliveryRepository; import at.gv.egiz.moazs.scheme.Msg2MzsConverter; import at.gv.egiz.moazs.client.MzsClient; @@ -19,6 +18,7 @@ import org.springframework.stereotype.Service; import javax.jws.WebParam; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.function.Consumer; import static at.gv.egiz.moazs.MoaZSException.moaZSException; import static at.gv.egiz.moazs.MoaZSException.moaZSExceptionBuilder; @@ -36,16 +36,16 @@ public class MzsService implements App2MzsPortType { private static final int TIMEOUT_FOR_ANWSER = 10; private final DeliveryRepository repository; - private final DeliveryPipeline pipeline; + private final Consumer backend; private final MzsClient appClient; private final DeliveryRequestAugmenter augmenter; private final Msg2MzsConverter converter; @Autowired - public MzsService(DeliveryRepository repository, DeliveryPipeline pipeline, MzsClient appClient, + public MzsService(DeliveryRepository repository, Consumer deliveryRequestBackend, MzsClient appClient, DeliveryRequestAugmenter augmenter, Msg2MzsConverter converter) { this.repository = repository; - this.pipeline = pipeline; + this.backend = deliveryRequestBackend; this.appClient = appClient; this.augmenter = augmenter; this.converter = converter; @@ -87,7 +87,7 @@ public class MzsService implements App2MzsPortType { logger.info("Receive request with appDeliveryID = {}.", appDeliveryID); repository.store(deliveryRequest); - pipeline.processRequest(appDeliveryID); + backend.accept(appDeliveryID); var statusId = RequestStatusResponse.getResponseID(appDeliveryID); var response = repository.retrieveResponse(statusId) diff --git a/src/main/java/at/gv/egiz/moazs/verify/MoaSPSSSignatureVerifier.java b/src/main/java/at/gv/egiz/moazs/verify/MoaSPSSSignatureVerifier.java deleted file mode 100644 index 5220c3b..0000000 --- a/src/main/java/at/gv/egiz/moazs/verify/MoaSPSSSignatureVerifier.java +++ /dev/null @@ -1,111 +0,0 @@ -package at.gv.egiz.moazs.verify; - -import at.gv.egiz.eid.authhandler.modules.sigverify.moasig.api.ISignatureVerificationService; -import at.gv.egiz.eid.authhandler.modules.sigverify.moasig.api.data.IXMLSignatureVerificationResponse; -import at.gv.egiz.eid.authhandler.modules.sigverify.moasig.exceptions.MOASigServiceException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import static at.gv.egiz.moazs.MoaZSException.moaZSException; -import static at.gv.egiz.moazs.MoaZSException.moaZSExceptionBuilder; -import static java.lang.String.*; - -public class MoaSPSSSignatureVerifier implements SignatureVerifier { - - private static final Logger log = LoggerFactory.getLogger(MoaSPSSSignatureVerifier.class); - - private final ISignatureVerificationService service; - - private final String trustProfile; - - private final boolean isManifestCheckActive; - - private static final int OK_CODE = 0; - - public MoaSPSSSignatureVerifier(ISignatureVerificationService service, - String trustProfile, boolean isManifestCheckActive) { - this.service = service; - this.trustProfile = trustProfile; - this.isManifestCheckActive = isManifestCheckActive; - } - - @Override - public void verify(byte[] signedXMLdocument) { - - try { - var response = service.verifyXMLSignature(signedXMLdocument, trustProfile); - - if (log.isDebugEnabled()) { - print(response); - } - - if (response == null) { - throw moaZSException("MOA SPSS could not find the signature. "); - } - - var builder = new StringBuilder(); - - if (response.getSignatureCheckCode() != OK_CODE) { - builder.append(format("Signature is not valid; SignatureCheckCode was %d. ", - response.getSignatureCheckCode())); - } - - if (response.getCertificateCheckCode() != OK_CODE) { - builder.append(format("Certificate chain is not valid; CertificateCheckCode was %d. ", - response.getCertificateCheckCode())); - } - - if (response.getSignatureManifestCheckCode() != OK_CODE) { - var signatureManifestErrorMsg = format("Signature Manifest is not valid; " + - "SignatureManifestCheckCode was %d. ", response.getSignatureManifestCheckCode()); - if (isManifestCheckActive) { - builder.append(signatureManifestErrorMsg); - } else { - log.warn(signatureManifestErrorMsg); - } - } - - if (response.isXmlDSIGManigest() && response.getXmlDSIGManifestCheckCode() != OK_CODE) { - var xmlDSIGManifestErrorMsg = format("XmlDSIGManifest Manifest is not valid; " + - "XmlDSIGManifest was %d. ", response.getXmlDSIGManifestCheckCode()); - if (isManifestCheckActive) { - builder.append(xmlDSIGManifestErrorMsg); - } else { - log.warn(xmlDSIGManifestErrorMsg); - } - } - - var msg = builder.toString(); - - if(msg.length() > 0) { - throw moaZSException(msg); - } - - } catch (MOASigServiceException e) { - throw moaZSExceptionBuilder("Could not verify the XML signature.") - .withCause(e) - .build(); - } - - } - - private void print(IXMLSignatureVerificationResponse response) { - log.debug("Response:"); - - if (response == null) { - log.debug("null"); - return; - } - - log.debug(" XmlDsigSubjectName: {}", response.getXmlDsigSubjectName()); - log.debug(" SignatureManifestCheckCode: {}", response.getSignatureManifestCheckCode()); - log.debug(" XmlDSIGManifestCheckCode: {}", response.getXmlDSIGManifestCheckCode()); - log.debug(" CertificateCheckCode: {}", response.getCertificateCheckCode()); - log.debug(" SignatureCheckCode: {}", response.getSignatureCheckCode()); - log.debug(" SigningDateTime: {}", response.getSigningDateTime()); - log.debug(" isXmlDSIGManigest: {}", response.isXmlDSIGManigest()); - log.debug(" isPublicAuthority: {}", response.isPublicAuthority()); - log.debug(" isQualifiedCertificate: {}", response.isQualifiedCertificate()); - log.debug(" getPublicAuthorityCode: {}", response.getPublicAuthorityCode()); - } -} diff --git a/src/main/java/at/gv/egiz/moazs/verify/MsgResponseVerifier.java b/src/main/java/at/gv/egiz/moazs/verify/MsgResponseVerifier.java deleted file mode 100644 index 9c8b17c..0000000 --- a/src/main/java/at/gv/egiz/moazs/verify/MsgResponseVerifier.java +++ /dev/null @@ -1,54 +0,0 @@ -package at.gv.egiz.moazs.verify; - -import at.gv.egiz.moazs.MoaZSException; -import at.gv.egiz.moazs.repository.DeliveryRepository; -import at.gv.egiz.moazs.scheme.MsgResponse; -import at.gv.egiz.moazs.service.MsgService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import static at.gv.egiz.moazs.MoaZSException.moaZSExceptionBuilder; -import static java.lang.String.format; - -@Component -public class MsgResponseVerifier { - - private static final Logger log = LoggerFactory.getLogger(MsgService.class); - public static final String MOASP_SIGNATURE_INVALID_ERROR_MSG = "Signature of Msg Response " + - "with AppDeliveryID=%s is not valid."; - - private final DeliveryRepository repository; - private final SignatureVerifier verifier; - - @Autowired - public MsgResponseVerifier(DeliveryRepository repository, SignatureVerifier verifier) { - this.repository = repository; - this.verifier = verifier; - } - - public MsgResponse verify(String responseID) { - - var response = repository.retrieveResponse(responseID).get(); - var builder = moaZSExceptionBuilder().withAllParametersInAnswer(response.getAnswer()); - - var binaryResponse = repository.retrieveBinaryResponse(responseID).get(); - - try { - verifier.verify(binaryResponse); - return response; - } catch (MoaZSException ex) { - log.error(ex.getMessage(), ex); - var wrappingEx = builder - .withMessage(format(MOASP_SIGNATURE_INVALID_ERROR_MSG, response.getAppDeliveryID())) - .withErrorCode(MoaZSException.ERROR_MOASP_SIGNATURE_INVALID) - .withCause(ex) - .build(); - - return response.generateError(wrappingEx); - } - - } - -} diff --git a/src/main/java/at/gv/egiz/moazs/verify/SignatureVerifier.java b/src/main/java/at/gv/egiz/moazs/verify/SignatureVerifier.java deleted file mode 100644 index a31c4cf..0000000 --- a/src/main/java/at/gv/egiz/moazs/verify/SignatureVerifier.java +++ /dev/null @@ -1,13 +0,0 @@ -package at.gv.egiz.moazs.verify; - -@FunctionalInterface -public interface SignatureVerifier { - - /** - * Verifies the signature of a signed XML document. Throws a at.gv.egiz.moazs.MoaZSException exception - * if the validation fails. - * @param signedXMLdocument - * @throws at.gv.egiz.moazs.MoaZSException - */ - void verify(byte[] signedXMLdocument); -} diff --git a/src/test/java/at/gv/egiz/moazs/DeliveryRequestBackendTest.java b/src/test/java/at/gv/egiz/moazs/DeliveryRequestBackendTest.java new file mode 100644 index 0000000..ed63489 --- /dev/null +++ b/src/test/java/at/gv/egiz/moazs/DeliveryRequestBackendTest.java @@ -0,0 +1,203 @@ +package at.gv.egiz.moazs; + +import at.gv.egiz.moazs.client.ClientFactory; +import at.gv.egiz.moazs.client.TnvzHelper; +import at.gv.egiz.moazs.backend.DeliveryRequestBackend; +import at.gv.egiz.moazs.backend.SignatureVerifier; +import at.gv.egiz.moazs.repository.DeliveryRepository; +import at.gv.egiz.moazs.repository.InMemoryDeliveryRepository; +import at.gv.egiz.moazs.scheme.Mzs2MsgConverter; +import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType; +import at.gv.zustellung.msg.xsd.App2ZusePort; +import at.gv.zustellung.msg.xsd.DeliveryRequestStatusType; +import at.gv.zustellung.msg.xsd.MetaData; +import at.gv.zustellung.msg.xsd.persondata.IdentificationType; +import at.gv.zustellung.tnvz.xsd.TNVZServicePort; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static at.gv.egiz.moazs.MoaZSException.moaZSException; +import static at.gv.egiz.moazs.MoaZSException.moaZSExceptionBuilder; +import static at.gv.egiz.moazs.scheme.RequestStatusResponse.getResponseID; +import static at.gv.zustellung.app2mzs.xsd.ClientType.clientTypeBuilder; +import static at.gv.zustellung.app2mzs.xsd.ConfigType.configTypeBuilder; +import static at.gv.zustellung.app2mzs.xsd.DeliveryRequestType.deliveryRequestTypeBuilder; +import static at.gv.zustellung.msg.xsd.DeliveryRequestStatusType.Success.successBuilder; +import static at.gv.zustellung.msg.xsd.DeliveryRequestStatusType.deliveryRequestStatusTypeBuilder; +import static at.gv.zustellung.msg.xsd.MetaData.metaDataBuilder; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.same; +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class DeliveryRequestBackendTest { + + private DeliveryRepository repository = new InMemoryDeliveryRepository(100); + + @Mock + private TnvzHelper tnvzHelper; + + @Mock + private ClientFactory clientFactory; + + @Mock + private App2ZusePort msgClient; + + @Mock + private TNVZServicePort tnvzClient; + + @Mock + private Mzs2MsgConverter converter; + + @Mock + private SignatureVerifier verifier; + + + private DeliveryRequestBackend pipeline; + + @Before + public void setup() { + pipeline = new DeliveryRequestBackend( + repository, + tnvzHelper, + converter, + clientFactory, + verifier); + } + + @Test + public void executePipelineWithoutTnvzRequest() { + var appDeliveryID = "no-tnvz-request"; + var expectedStatus = setupMocks(appDeliveryID, false); + + pipeline.accept(appDeliveryID); + + verifyZeroInteractions(tnvzHelper); + var response = repository.retrieveResponse(getResponseID(appDeliveryID)).get(); + var actualStatus = (DeliveryRequestStatusType) response.getResponse(); + + assertThat(actualStatus).isEqualTo(expectedStatus); + } + + @Test + public void rejectDeliveryWhenReceiverIsNotAddressable() { + var appDeliveryID = "not-addressable"; + setupMocks(appDeliveryID, true); + when(tnvzHelper.performQueryPersonRequest(any(), any(), any())) + .thenThrow(buildMzsException("400", appDeliveryID)); + + pipeline.accept(appDeliveryID); + + var responseID = getResponseID(appDeliveryID); + var response = repository.retrieveResponse(responseID).get(); + var status = (DeliveryRequestStatusType) response.getResponse(); + var actualCode = status.getError().getErrorInfo().getCode(); + + assertThat(actualCode).isEqualTo("400"); + verifyZeroInteractions(converter); + verify(tnvzHelper).performQueryPersonRequest(any(), any(), any()); + } + + @Test + public void executePipelineWithTnvzRequest() { + var appDeliveryID = "tnvz-request"; + var expectedStatus = setupMocks(appDeliveryID, true); + + pipeline.accept(appDeliveryID); + var response = repository.retrieveResponse(getResponseID(appDeliveryID)).get(); + var actualStatus = (DeliveryRequestStatusType) response.getResponse(); + + assertThat(actualStatus).isEqualTo(expectedStatus); + } + + @Test + public void rejectInvalidSignature() { + var appDeliveryID = "invalid-signature"; + setupMocks(appDeliveryID, true); + doThrow(moaZSException("Signature Invalid!")).when(verifier).accept(any()); + + pipeline.accept(appDeliveryID); + var response = repository.retrieveResponse(getResponseID(appDeliveryID)).get(); + var status = (DeliveryRequestStatusType) response.getResponse(); + var actualCode = status.getError().getErrorInfo().getCode(); + + assertThat(actualCode).isEqualTo(MoaZSException.ERROR_MOASP_SIGNATURE_INVALID); + + } + + private DeliveryRequestStatusType setupMocks(String appDeliveryId, boolean tnvzRequest) { + + var mzsRequest = setupMzsRequest(appDeliveryId, tnvzRequest); + var msgRequest = setupMsgRequest(appDeliveryId); + var status = setupStatus(appDeliveryId); + var signedStatus = new byte[0]; + var identification = IdentificationType.identificationTypeBuilder().build(); + repository.store(mzsRequest); + repository.store(getResponseID(appDeliveryId), signedStatus); + + when(converter.convert(eq(mzsRequest) )).thenReturn(msgRequest); + when(converter.convert(eq(mzsRequest), any())).thenReturn(msgRequest); + when(clientFactory.create(any(), same(App2ZusePort.class))).thenReturn(msgClient); + when(msgClient.delivery(msgRequest)).thenReturn(status); + + if (tnvzRequest) { + when(clientFactory.create(any(), same(TNVZServicePort.class))).thenReturn(tnvzClient); + when(tnvzHelper.performQueryPersonRequest(any(), any(), any())).thenReturn(identification); + } + return status; + + } + + private MoaZSException buildMzsException(String code, String appDeliveryID) { + return moaZSExceptionBuilder("") + .withErrorCode(code) + .withAppDeliveryID(appDeliveryID) + .build(); + } + + private DeliveryRequestStatusType setupStatus(String appDeliveryId) { + + var success = successBuilder() + .withAppDeliveryID(appDeliveryId) + .build(); + + return deliveryRequestStatusTypeBuilder() + .withSuccess(success) + .build(); + + } + + private DeliveryRequestType setupMzsRequest(String appDeliveryId, boolean tnvzRequest) { + + var msgClient = clientTypeBuilder() + .withURL("http://zuse") + .build(); + + var config = configTypeBuilder() + .withPerformQueryPersonRequest(tnvzRequest) + .withMSGClient(msgClient) + .build(); + + return deliveryRequestTypeBuilder() + .withMetaData(setupMetaData(appDeliveryId)) + .withConfig(config) + .build(); + } + + private at.gv.zustellung.msg.xsd.DeliveryRequestType setupMsgRequest(String appDeliveryId) { + return at.gv.zustellung.msg.xsd.DeliveryRequestType.deliveryRequestTypeBuilder() + .withMetaData(setupMetaData(appDeliveryId)) + .build(); + } + + private MetaData setupMetaData(String appDeliveryId) { + return metaDataBuilder() + .withAppDeliveryID(appDeliveryId) + .build(); + } + +} diff --git a/src/test/java/at/gv/egiz/moazs/ITMoaSPSSSignatureVerifierTest.java b/src/test/java/at/gv/egiz/moazs/ITMoaSPSSSignatureVerifierTest.java index 2c6b978..34f4e1b 100644 --- a/src/test/java/at/gv/egiz/moazs/ITMoaSPSSSignatureVerifierTest.java +++ b/src/test/java/at/gv/egiz/moazs/ITMoaSPSSSignatureVerifierTest.java @@ -1,8 +1,7 @@ package at.gv.egiz.moazs; import at.gv.egiz.eid.authhandler.modules.sigverify.moasig.api.ISignatureVerificationService; -import at.gv.egiz.moazs.verify.MoaSPSSSignatureVerifier; -import at.gv.egiz.moazs.verify.SignatureVerifier; +import at.gv.egiz.moazs.backend.SignatureVerifier; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -27,7 +26,7 @@ import java.nio.file.Files; @Bean public SignatureVerifier verifier(@Autowired ISignatureVerificationService service){ - return new MoaSPSSSignatureVerifier(service, "test-trust-profile", true); + return new SignatureVerifier(service, "test-trust-profile", true); } } @@ -41,7 +40,7 @@ import java.nio.file.Files; var path = resourcesPath + "valid-signed-delivery-response.xml"; var signature = Files.readAllBytes(new File(path).toPath()); - verifier.verify(signature); + verifier.accept(signature); } @Test(expected = MoaZSException.class) @@ -50,7 +49,7 @@ import java.nio.file.Files; var path = resourcesPath + "invalid-signed-delivery-response.xml"; var signature = Files.readAllBytes(new File(path).toPath()); - verifier.verify(signature); + verifier.accept(signature); } } diff --git a/src/test/java/at/gv/egiz/moazs/ITMzsServiceTest.java b/src/test/java/at/gv/egiz/moazs/ITMzsServiceTest.java index a93c720..e9b4f70 100644 --- a/src/test/java/at/gv/egiz/moazs/ITMzsServiceTest.java +++ b/src/test/java/at/gv/egiz/moazs/ITMzsServiceTest.java @@ -1,12 +1,9 @@ package at.gv.egiz.moazs; -import at.gv.egiz.moazs.process.DeliveryPipeline; import at.gv.egiz.moazs.repository.DeliveryRepository; import at.gv.egiz.moazs.scheme.RequestStatusResponse; import org.junit.Test; import org.junit.runner.RunWith; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; @@ -25,6 +22,7 @@ import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.file.Paths; import java.util.GregorianCalendar; +import java.util.function.Consumer; import static at.gv.zustellung.msg.xsd.DeliveryRequestStatusType.Success.successBuilder; import static at.gv.zustellung.msg.xsd.DeliveryRequestStatusType.deliveryRequestStatusTypeBuilder; @@ -40,8 +38,6 @@ public class ITMzsServiceTest { private final String basePath = "src/test/resources/at/gv/egiz/moazs/ITMzsServiceTest/"; - private final static Logger logger = LoggerFactory.getLogger(ITMzsServiceTest.class); - @TestConfiguration public static class TestConfig { @@ -50,7 +46,7 @@ public class ITMzsServiceTest { @Bean @Primary - public DeliveryPipeline deliveryPipelineThatAlwaysSucceeds() { + public Consumer deliveryPipelineThatAlwaysSucceeds() { return appDeliveryId -> { var success = successBuilder() diff --git a/src/test/java/at/gv/egiz/moazs/SaveResponseToFileSinkTest.java b/src/test/java/at/gv/egiz/moazs/SaveResponseToFileSinkTest.java index ca501c8..9ddd37e 100644 --- a/src/test/java/at/gv/egiz/moazs/SaveResponseToFileSinkTest.java +++ b/src/test/java/at/gv/egiz/moazs/SaveResponseToFileSinkTest.java @@ -1,6 +1,6 @@ package at.gv.egiz.moazs; -import at.gv.egiz.moazs.process.SaveResponseToFileSink; +import at.gv.egiz.moazs.backend.SaveResponseToFileSink; import at.gv.egiz.moazs.repository.DeliveryRepository; import at.gv.egiz.moazs.scheme.Marshaller; import at.gv.egiz.moazs.scheme.RequestStatusResponse; @@ -63,7 +63,7 @@ public class SaveResponseToFileSinkTest { var fileContent = "some content"; var status = setupMocks(fileContent); - sink.handle(status) + sink.apply(status) .thenRun(() -> assertFilesCreatedAndContentMatches(fileContent)); } diff --git a/src/test/java/at/gv/egiz/moazs/SingleThreadedDeliveryPipelineTest.java b/src/test/java/at/gv/egiz/moazs/SingleThreadedDeliveryPipelineTest.java deleted file mode 100644 index e245eb1..0000000 --- a/src/test/java/at/gv/egiz/moazs/SingleThreadedDeliveryPipelineTest.java +++ /dev/null @@ -1,204 +0,0 @@ -package at.gv.egiz.moazs; - -import at.gv.egiz.moazs.process.DeliveryPipeline; -import at.gv.egiz.moazs.process.SingleThreadedDeliveryPipeline; -import at.gv.egiz.moazs.client.TnvzHelper; -import at.gv.egiz.moazs.scheme.*; -import at.gv.egiz.moazs.client.ClientFactory; -import at.gv.egiz.moazs.repository.DeliveryRepository; -import at.gv.egiz.moazs.repository.InMemoryDeliveryRepository; -import at.gv.egiz.moazs.verify.MoaSPSSSignatureVerifier; -import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType; -import at.gv.zustellung.msg.xsd.App2ZusePort; -import at.gv.zustellung.msg.xsd.DeliveryRequestStatusType; -import at.gv.zustellung.msg.xsd.MetaData; -import at.gv.zustellung.msg.xsd.persondata.IdentificationType; -import at.gv.zustellung.tnvz.xsd.TNVZServicePort; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -import static at.gv.egiz.moazs.MoaZSException.moaZSException; -import static at.gv.egiz.moazs.MoaZSException.moaZSExceptionBuilder; -import static at.gv.egiz.moazs.scheme.RequestStatusResponse.getResponseID; -import static at.gv.zustellung.app2mzs.xsd.ClientType.clientTypeBuilder; -import static at.gv.zustellung.app2mzs.xsd.ConfigType.configTypeBuilder; -import static at.gv.zustellung.app2mzs.xsd.DeliveryRequestType.deliveryRequestTypeBuilder; -import static at.gv.zustellung.msg.xsd.DeliveryRequestStatusType.Success.successBuilder; -import static at.gv.zustellung.msg.xsd.DeliveryRequestStatusType.deliveryRequestStatusTypeBuilder; -import static at.gv.zustellung.msg.xsd.MetaData.metaDataBuilder; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.*; - -@RunWith(MockitoJUnitRunner.class) -public class SingleThreadedDeliveryPipelineTest { - - private DeliveryRepository repository = new InMemoryDeliveryRepository(100); - - @Mock - private TnvzHelper tnvzHelper; - - @Mock - private ClientFactory clientFactory; - - @Mock - private App2ZusePort msgClient; - - @Mock - private TNVZServicePort tnvzClient; - - @Mock - private Mzs2MsgConverter converter; - - @Mock - private MoaSPSSSignatureVerifier verifier; - - - private DeliveryPipeline pipeline; - - @Before - public void setup() { - pipeline = new SingleThreadedDeliveryPipeline( - repository, - tnvzHelper, - converter, - clientFactory, - verifier); - } - - @Test - public void executePipelineWithoutTnvzRequest() { - var appDeliveryID = "no-tnvz-request"; - var expectedStatus = setupMocks(appDeliveryID, false); - - pipeline.processRequest(appDeliveryID); - - verifyZeroInteractions(tnvzHelper); - var response = repository.retrieveResponse(getResponseID(appDeliveryID)).get(); - var actualStatus = (DeliveryRequestStatusType) response.getResponse(); - - assertThat(actualStatus).isEqualTo(expectedStatus); - } - - @Test - public void rejectDeliveryWhenReceiverIsNotAddressable() { - var appDeliveryID = "not-addressable"; - setupMocks(appDeliveryID, true); - when(tnvzHelper.performQueryPersonRequest(any(), any(), any())) - .thenThrow(buildMzsException("400", appDeliveryID)); - - pipeline.processRequest(appDeliveryID); - - var responseID = getResponseID(appDeliveryID); - var response = repository.retrieveResponse(responseID).get(); - var status = (DeliveryRequestStatusType) response.getResponse(); - var actualCode = status.getError().getErrorInfo().getCode(); - - assertThat(actualCode).isEqualTo("400"); - verifyZeroInteractions(converter); - verify(tnvzHelper).performQueryPersonRequest(any(), any(), any()); - } - - @Test - public void executePipelineWithTnvzRequest() { - var appDeliveryID = "tnvz-request"; - var expectedStatus = setupMocks(appDeliveryID, true); - - pipeline.processRequest(appDeliveryID); - var response = repository.retrieveResponse(getResponseID(appDeliveryID)).get(); - var actualStatus = (DeliveryRequestStatusType) response.getResponse(); - - assertThat(actualStatus).isEqualTo(expectedStatus); - } - - @Test - public void rejectInvalidSignature() { - var appDeliveryID = "invalid-signature"; - setupMocks(appDeliveryID, true); - doThrow(moaZSException("Signature Invalid!")).when(verifier).verify(any()); - - pipeline.processRequest(appDeliveryID); - var response = repository.retrieveResponse(getResponseID(appDeliveryID)).get(); - var status = (DeliveryRequestStatusType) response.getResponse(); - var actualCode = status.getError().getErrorInfo().getCode(); - - assertThat(actualCode).isEqualTo(MoaZSException.ERROR_MOASP_SIGNATURE_INVALID); - - } - - private DeliveryRequestStatusType setupMocks(String appDeliveryId, boolean tnvzRequest) { - - var mzsRequest = setupMzsRequest(appDeliveryId, tnvzRequest); - var msgRequest = setupMsgRequest(appDeliveryId); - var status = setupStatus(appDeliveryId); - var signedStatus = new byte[0]; - var identification = IdentificationType.identificationTypeBuilder().build(); - repository.store(mzsRequest); - repository.store(getResponseID(appDeliveryId), signedStatus); - - when(converter.convert(eq(mzsRequest) )).thenReturn(msgRequest); - when(converter.convert(eq(mzsRequest), any())).thenReturn(msgRequest); - when(clientFactory.create(any(), same(App2ZusePort.class))).thenReturn(msgClient); - when(msgClient.delivery(msgRequest)).thenReturn(status); - - if (tnvzRequest) { - when(clientFactory.create(any(), same(TNVZServicePort.class))).thenReturn(tnvzClient); - when(tnvzHelper.performQueryPersonRequest(any(), any(), any())).thenReturn(identification); - } - return status; - - } - - private MoaZSException buildMzsException(String code, String appDeliveryID) { - return moaZSExceptionBuilder("") - .withErrorCode(code) - .withAppDeliveryID(appDeliveryID) - .build(); - } - - private DeliveryRequestStatusType setupStatus(String appDeliveryId) { - - var success = successBuilder() - .withAppDeliveryID(appDeliveryId) - .build(); - - return deliveryRequestStatusTypeBuilder() - .withSuccess(success) - .build(); - - } - - private DeliveryRequestType setupMzsRequest(String appDeliveryId, boolean tnvzRequest) { - - var msgClient = clientTypeBuilder() - .withURL("http://zuse") - .build(); - - var config = configTypeBuilder() - .withPerformQueryPersonRequest(tnvzRequest) - .withMSGClient(msgClient) - .build(); - - return deliveryRequestTypeBuilder() - .withMetaData(setupMetaData(appDeliveryId)) - .withConfig(config) - .build(); - } - - private at.gv.zustellung.msg.xsd.DeliveryRequestType setupMsgRequest(String appDeliveryId) { - return at.gv.zustellung.msg.xsd.DeliveryRequestType.deliveryRequestTypeBuilder() - .withMetaData(setupMetaData(appDeliveryId)) - .build(); - } - - private MetaData setupMetaData(String appDeliveryId) { - return metaDataBuilder() - .withAppDeliveryID(appDeliveryId) - .build(); - } - -} -- cgit v1.2.3