From e1f365955aa22cdf8e44429af2b744388ce0c05b Mon Sep 17 00:00:00 2001 From: Christof Rabensteiner Date: Tue, 28 May 2019 10:48:20 +0200 Subject: Integrate Sign.Verification and Improve Error Handling of Pipeline - Ensure proper communication of errors between pipeline and mzs service by converting MoaZSExceptions into DeliveryRequestStatus messages. - Revise MoaZSException: Add optional fields; those fields are a) helpful to construct meaningful error messages and b) optional because, depending on where an exception appears, either existent or non-existent and thus optional. Add inner-class Builder. - Integrate Signature Verification into pipeline and add Stub for SignatureVerification. - Move TNVZResponse's Mimetype check into dedicated class (Reason: separate abstration layers). - Update api changes in testcases. --- .../gv/egiz/moazs/pipeline/DeliveryPipeline.java | 6 +- .../moazs/pipeline/SameThreadDeliveryPipeline.java | 131 +++++++++++++-------- 2 files changed, 88 insertions(+), 49 deletions(-) (limited to 'src/main/java/at/gv/egiz/moazs/pipeline') diff --git a/src/main/java/at/gv/egiz/moazs/pipeline/DeliveryPipeline.java b/src/main/java/at/gv/egiz/moazs/pipeline/DeliveryPipeline.java index f3ac0e6..f32dfe2 100644 --- a/src/main/java/at/gv/egiz/moazs/pipeline/DeliveryPipeline.java +++ b/src/main/java/at/gv/egiz/moazs/pipeline/DeliveryPipeline.java @@ -4,12 +4,12 @@ package at.gv.egiz.moazs.pipeline; public interface DeliveryPipeline { /** - * Performs a {@code DeliveryRequest}'s Back-End Tasks + * Performs all {@code DeliveryRequest}'s Back-End Tasks. * * Fetches {@code DeliveryRequest} referred by appDeliveryId from * {@code DeliveryRepository}, makes sure that all necessary - * tasks are executed and stores the response back to - * {@code DeliveryRepository}. + * 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/pipeline/SameThreadDeliveryPipeline.java b/src/main/java/at/gv/egiz/moazs/pipeline/SameThreadDeliveryPipeline.java index a0475fd..130e147 100644 --- a/src/main/java/at/gv/egiz/moazs/pipeline/SameThreadDeliveryPipeline.java +++ b/src/main/java/at/gv/egiz/moazs/pipeline/SameThreadDeliveryPipeline.java @@ -1,24 +1,28 @@ package at.gv.egiz.moazs.pipeline; +import at.gv.egiz.moazs.MoaZSException; import at.gv.egiz.moazs.msg.MsgClientFactory; +import at.gv.egiz.moazs.msg.SignatureVerifier; +import at.gv.egiz.moazs.msg.StoreSOAPBodyBinaryInRepositoryInterceptor; import at.gv.egiz.moazs.repository.DeliveryRepository; import at.gv.egiz.moazs.scheme.Mzs2MsgConverter; +import at.gv.egiz.moazs.scheme.NameSpace; import at.gv.egiz.moazs.tnvz.TnvzClient; +import at.gv.egiz.moazs.tnvz.TnvzResultVerifier; import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType; -import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType.Payload; -import at.gv.zustellung.msg.xsd.persondata.IdentificationType; +import at.gv.zustellung.msg.xsd.DeliveryAnswerType; +import at.gv.zustellung.msg.xsd.DeliveryRequestStatusType; import at.gv.zustellung.tnvz.xsd.PersonResultType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component; -import java.util.Collection; -import java.util.List; - -import static at.gv.egiz.moazs.MoaZSException.moaZSException; -import static java.lang.String.join; -import static java.util.stream.Collectors.toSet; +import static at.gv.egiz.moazs.MoaZSException.moaZSExceptionBuilder; +import static at.gv.egiz.moazs.util.NullCoalesce.coalesce; +import static at.gv.zustellung.msg.xsd.DeliveryRequestStatusType.Error.errorBuilder; +import static at.gv.zustellung.msg.xsd.DeliveryRequestStatusType.deliveryRequestStatusTypeBuilder; +import static at.gv.zustellung.msg.xsd.ErrorInfoType.errorInfoTypeBuilder; @Component @Profile("!cluster") @@ -26,74 +30,109 @@ public class SameThreadDeliveryPipeline implements DeliveryPipeline { private final DeliveryRepository repository; private final TnvzClient tnvzClient; + private final TnvzResultVerifier tnvzVerifier; private final Mzs2MsgConverter converter; private final MsgClientFactory msgClientFactory; + private final SignatureVerifier verifier; + private final StoreSOAPBodyBinaryInRepositoryInterceptor interceptor; @Autowired public SameThreadDeliveryPipeline(DeliveryRepository repository, TnvzClient tnvzClient, + TnvzResultVerifier tnvzVerifier, Mzs2MsgConverter converter, - MsgClientFactory msgClientFactory) { + StoreSOAPBodyBinaryInRepositoryInterceptor interceptor, + MsgClientFactory msgClientFactory, + SignatureVerifier verifier + ) { this.repository = repository; this.tnvzClient = tnvzClient; + this.tnvzVerifier = tnvzVerifier; this.converter = converter; this.msgClientFactory = msgClientFactory; + this.verifier = verifier; + this.interceptor = interceptor; } @Override public void processRequest(String appDeliveryId) { - var mzsRequest = repository.getDeliveryRequest(appDeliveryId).orElseThrow(); - var msgRequest = (mzsRequest.getConfig().isPerformQueryPersonRequest()) - ? converter.convert(mzsRequest, queryPerson(mzsRequest)) - : converter.convert(mzsRequest); + DeliveryRequestType mzsRequest; + PersonResultType tnvzResult = null; + at.gv.zustellung.msg.xsd.DeliveryRequestType msgRequest; + DeliveryRequestStatusType status; + + try { + mzsRequest = repository.getDeliveryRequest(appDeliveryId).orElseThrow(); + + if (mzsRequest.getConfig().isPerformQueryPersonRequest()) { + tnvzResult = performTnvzQuery(mzsRequest); + msgRequest = converter.convert(mzsRequest, tnvzResult.getSuccess().getIdentification()); + } else { + msgRequest = converter.convert(mzsRequest); + } + + status = msgClientFactory.create(msgRequest, mzsRequest.getConfig(), interceptor).send(); + + var signedStatus = repository.getSignedDeliveryRequestStatus(appDeliveryId).get(); + if (verifier.verify(signedStatus)) { + repository.add(status); + } else { + throw moaZSExceptionBuilder("Signature of DeliveryRequestStatus with AppDeliveryId={} " + + "is invalid.", appDeliveryId) + .withErrorCode(MoaZSException.ERROR_MOASP_SIGNATURE_INVALID) + .withMzsRequest(mzsRequest) + .withTnvzResult(tnvzResult) + .withMsgRequest(msgRequest) + .withMsgResult(status) + .build(); + } + } catch (MoaZSException exception) { + var errorStatus = generateErrorStatus(exception, appDeliveryId); + repository.add(errorStatus); + } + } - var msgClient = msgClientFactory.create(msgRequest, mzsRequest.getConfig()); - var status = msgClient.send(); - repository.add(status); + private PersonResultType performTnvzQuery(DeliveryRequestType request) { + var result = tnvzClient.query(request.getSender(), request.getReceiver()); + tnvzVerifier.verify(request, result); + return result; } - private IdentificationType queryPerson(DeliveryRequestType request) { - var result = tnvzClient.queryPerson(request.getSender(), request.getReceiver()); + private DeliveryRequestStatusType generateErrorStatus(MoaZSException exception, String appDeliveryId) { - if (result.getError() != null) { - var error = result.getError(); - var info = error.getErrorInfo(); - var noteSent = (error.getPreAdviceNoteSent() != null) ? "sent" : "not sent"; - var template = "Receiver is not addressable. Code: %s ; Text: %s; Preadvice note was %s."; - throw moaZSException(template, info.getCode(), info.getText(), noteSent); - } + var infoBuilder = errorInfoTypeBuilder() + .withText(exception.getMessage()) + .withCode(exception.getErrorCode()); - var mismatchedTypes = findMimeTypeMismatches(result, request); + var errorBuilder = errorBuilder() + .withErrorInfo(infoBuilder.build()) + .withAppDeliveryID(appDeliveryId); - if (!mismatchedTypes.isEmpty()) { - var template = "Request contains attachment of type(s) %s, but receiver only accepts attachments of type(s) %s."; - var acceptedTypesString = join(",", getAcceptedTypes(result)); - var mismatchedTypesString = join(",", mismatchedTypes); - throw moaZSException(template, mismatchedTypesString, acceptedTypesString); + if (exception.getMzsRequest() != null) { + errorBuilder.withDeliverySystem(exception.getMzsRequest().getConfig().getServer().getZUSEUrlID()); } - return result.getSuccess().getIdentification(); - } - - private Collection findMimeTypeMismatches(PersonResultType result, DeliveryRequestType request) { - var acceptedTypes = getAcceptedTypes(result); - - if (acceptedTypes.contains("*/*")) { - return List.of(); + if (exception.getTnvzResult() != null && exception.getTnvzResult().getError() != null) { + errorBuilder.withPreAdviceNoteSent(exception.getTnvzResult().getError().getPreAdviceNoteSent()); } - var typesInRequest = request.getPayload().stream() - .map(Payload::getMIMEType) - .collect(toSet()); + if (exception.getMsgResult() != null) { + var answer = getAnswerFromResult(exception.getMsgResult()); + errorBuilder.withGZ(answer.getGZ()); + errorBuilder.withZSDeliveryID(answer.getZSDeliveryID()); + } - typesInRequest.removeAll(acceptedTypes); + return deliveryRequestStatusTypeBuilder() + .withError(errorBuilder.build()) + .withVersion(NameSpace.MSG_VERSION) + .build(); - return typesInRequest; } - private List getAcceptedTypes(PersonResultType result) { - return result.getSuccess().getMimeTypeList().getMimeType(); + private DeliveryAnswerType getAnswerFromResult(DeliveryRequestStatusType msgResult) { + return coalesce(msgResult.getSuccess(), msgResult.getPartialSuccess(), msgResult.getError()).get(); } + } -- cgit v1.2.3