aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristof Rabensteiner <christof.rabensteiner@iaik.tugraz.at>2019-05-28 10:48:20 +0200
committerChristof Rabensteiner <christof.rabensteiner@iaik.tugraz.at>2019-05-28 10:48:20 +0200
commite1f365955aa22cdf8e44429af2b744388ce0c05b (patch)
tree71fec813cce57d4a74650dec259685052c405190 /src
parent695ab1f836160d40c4352a2c3127f4f687912817 (diff)
downloadmoa-zs-e1f365955aa22cdf8e44429af2b744388ce0c05b.tar.gz
moa-zs-e1f365955aa22cdf8e44429af2b744388ce0c05b.tar.bz2
moa-zs-e1f365955aa22cdf8e44429af2b744388ce0c05b.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/main/java/at/gv/egiz/moazs/MoaZSException.java123
-rw-r--r--src/main/java/at/gv/egiz/moazs/msg/MsgClient.java6
-rw-r--r--src/main/java/at/gv/egiz/moazs/msg/MsgClientFactory.java9
-rw-r--r--src/main/java/at/gv/egiz/moazs/msg/SignatureVerifier.java13
-rw-r--r--src/main/java/at/gv/egiz/moazs/msg/StoreSOAPBodyBinaryInRepositoryInterceptor.java7
-rw-r--r--src/main/java/at/gv/egiz/moazs/mzs/MzsService.java10
-rw-r--r--src/main/java/at/gv/egiz/moazs/pipeline/DeliveryPipeline.java6
-rw-r--r--src/main/java/at/gv/egiz/moazs/pipeline/SameThreadDeliveryPipeline.java131
-rw-r--r--src/main/java/at/gv/egiz/moazs/scheme/NameSpace.java1
-rw-r--r--src/main/java/at/gv/egiz/moazs/scheme/SOAPUtils.java4
-rw-r--r--src/main/java/at/gv/egiz/moazs/tnvz/TnvzClient.java12
-rw-r--r--src/main/java/at/gv/egiz/moazs/tnvz/TnvzResultVerifier.java63
-rw-r--r--src/test/java/at/gv/egiz/moazs/MsgClientTest.java8
-rw-r--r--src/test/java/at/gv/egiz/moazs/SameThreadDeliveryPipelineTest.java95
14 files changed, 386 insertions, 102 deletions
diff --git a/src/main/java/at/gv/egiz/moazs/MoaZSException.java b/src/main/java/at/gv/egiz/moazs/MoaZSException.java
index 11d9b4e..db04241 100644
--- a/src/main/java/at/gv/egiz/moazs/MoaZSException.java
+++ b/src/main/java/at/gv/egiz/moazs/MoaZSException.java
@@ -1,20 +1,129 @@
package at.gv.egiz.moazs;
+import at.gv.zustellung.msg.xsd.DeliveryRequestStatusType;
+import at.gv.zustellung.msg.xsd.DeliveryRequestType;
+import at.gv.zustellung.tnvz.xsd.PersonResultType;
+import org.springframework.lang.Nullable;
+
public class MoaZSException extends RuntimeException {
- public MoaZSException(String s, Throwable throwable) {
- super(s, throwable);
- }
- public MoaZSException(String s) {
- super(s);
+ public static final String ERROR_MZS_MIMETYPE_MISSMATCH = "8001";
+ public static final String ERROR_MOASP_SIGNATURE_INVALID = "7001";
+
+ @Nullable
+ private final String errorCode;
+ @Nullable
+ private final PersonResultType tnvzResult;
+ @Nullable
+ private final DeliveryRequestStatusType msgResult;
+ @Nullable
+ private final DeliveryRequestType msgRequest;
+ @Nullable
+ private final at.gv.zustellung.app2mzs.xsd.DeliveryRequestType mzsRequest;
+
+ private MoaZSException(String message, Throwable cause, String errorCode, PersonResultType tnvzResult,
+ DeliveryRequestStatusType msgResult, DeliveryRequestType msgRequest,
+ at.gv.zustellung.app2mzs.xsd.DeliveryRequestType mzsRequest) {
+ super(message, cause);
+ this.errorCode = errorCode;
+ this.tnvzResult = tnvzResult;
+ this.msgResult = msgResult;
+ this.msgRequest = msgRequest;
+ this.mzsRequest = mzsRequest;
}
public static MoaZSException moaZSException(String formatString, Object... objects) {
- return new MoaZSException(String.format(formatString, objects));
+ return moaZSExceptionBuilder(formatString, objects).build();
}
public static MoaZSException moaZSException(String message) {
- return new MoaZSException(String.format(message));
+ return moaZSExceptionBuilder(message).build();
+ }
+
+ public static Builder moaZSExceptionBuilder(String formatString, Object... objects) {
+ return new Builder().withMessage(String.format(formatString, objects));
+ }
+
+ public static Builder moaZSExceptionBuilder(String message) {
+ return new Builder().withMessage(message);
+ }
+
+ @Nullable
+ public String getErrorCode() {
+ return errorCode;
+ }
+
+ @Nullable
+ public PersonResultType getTnvzResult() {
+ return tnvzResult;
+ }
+
+ @Nullable
+ public DeliveryRequestStatusType getMsgResult() {
+ return msgResult;
+ }
+
+ @Nullable
+ public at.gv.zustellung.app2mzs.xsd.DeliveryRequestType getMzsRequest() {
+ return mzsRequest;
+ }
+
+ @Nullable
+ public DeliveryRequestType getMsgRequest() {
+ return msgRequest;
+ }
+
+ public static class Builder extends Throwable {
+
+ private String message;
+ private Throwable cause;
+ private String errorCode;
+ private PersonResultType tnvzResult;
+ private DeliveryRequestStatusType msgResult;
+ private DeliveryRequestType msgRequest;
+ private at.gv.zustellung.app2mzs.xsd.DeliveryRequestType mzsRequest;
+
+ private Builder() {
+ }
+
+ public Builder withMessage(String message) {
+ this.message = message;
+ return this;
+ }
+
+ public Builder withCause(Throwable cause) {
+ this.cause = cause;
+ return this;
+ }
+
+ public Builder withErrorCode(String errorCode) {
+ this.errorCode = errorCode;
+ return this;
+ }
+
+ public Builder withTnvzResult(PersonResultType tnvzResult) {
+ this.tnvzResult = tnvzResult;
+ return this;
+ }
+
+ public Builder withMsgResult(DeliveryRequestStatusType msgResult) {
+ this.msgResult = msgResult;
+ return this;
+ }
+
+ public Builder withMsgRequest(DeliveryRequestType msgRequest) {
+ this.msgRequest = msgRequest;
+ return this;
+ }
+
+ public Builder withMzsRequest(at.gv.zustellung.app2mzs.xsd.DeliveryRequestType mzsRequest) {
+ this.mzsRequest = mzsRequest;
+ return this;
+ }
+
+ public MoaZSException build() {
+ return new MoaZSException(message, cause, errorCode, tnvzResult, msgResult, msgRequest, mzsRequest);
+ }
}
}
diff --git a/src/main/java/at/gv/egiz/moazs/msg/MsgClient.java b/src/main/java/at/gv/egiz/moazs/msg/MsgClient.java
index fd36a92..82f172d 100644
--- a/src/main/java/at/gv/egiz/moazs/msg/MsgClient.java
+++ b/src/main/java/at/gv/egiz/moazs/msg/MsgClient.java
@@ -8,18 +8,14 @@ import org.apache.cxf.jaxws.JaxWsClientFactoryBean;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.PhaseInterceptor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
public class MsgClient {
- private static final Logger log = LoggerFactory.getLogger(MsgClient.class);
-
private final DeliveryRequestType msgRequest;
private final ConfigType config;
private final PhaseInterceptor<? extends Message> interceptor;
- MsgClient(DeliveryRequestType msgRequest, ConfigType config, PhaseInterceptor<? extends Message> interceptor) {
+ public MsgClient(DeliveryRequestType msgRequest, ConfigType config, PhaseInterceptor<? extends Message> interceptor) {
this.msgRequest = msgRequest;
this.config = config;
this.interceptor = interceptor;
diff --git a/src/main/java/at/gv/egiz/moazs/msg/MsgClientFactory.java b/src/main/java/at/gv/egiz/moazs/msg/MsgClientFactory.java
index 82468bc..228ebec 100644
--- a/src/main/java/at/gv/egiz/moazs/msg/MsgClientFactory.java
+++ b/src/main/java/at/gv/egiz/moazs/msg/MsgClientFactory.java
@@ -8,14 +8,7 @@ import org.springframework.stereotype.Component;
@Component
public class MsgClientFactory {
- private final StoreSOAPBodyBinaryInRepositoryInterceptor storeResponseInterceptor;
-
- @Autowired
- public MsgClientFactory(StoreSOAPBodyBinaryInRepositoryInterceptor storeResponseInterceptor) {
- this.storeResponseInterceptor = storeResponseInterceptor;
- }
-
- public MsgClient create(DeliveryRequestType msgRequest, ConfigType config) {
+ public MsgClient create(DeliveryRequestType msgRequest, ConfigType config, StoreSOAPBodyBinaryInRepositoryInterceptor storeResponseInterceptor) {
return new MsgClient(msgRequest, config, storeResponseInterceptor);
}
diff --git a/src/main/java/at/gv/egiz/moazs/msg/SignatureVerifier.java b/src/main/java/at/gv/egiz/moazs/msg/SignatureVerifier.java
new file mode 100644
index 0000000..12b1ccb
--- /dev/null
+++ b/src/main/java/at/gv/egiz/moazs/msg/SignatureVerifier.java
@@ -0,0 +1,13 @@
+package at.gv.egiz.moazs.msg;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public class SignatureVerifier {
+
+ public boolean verify(byte[] signedXMLdocument) {
+ return true;
+
+ }
+
+}
diff --git a/src/main/java/at/gv/egiz/moazs/msg/StoreSOAPBodyBinaryInRepositoryInterceptor.java b/src/main/java/at/gv/egiz/moazs/msg/StoreSOAPBodyBinaryInRepositoryInterceptor.java
index 4e023ac..c78c44b 100644
--- a/src/main/java/at/gv/egiz/moazs/msg/StoreSOAPBodyBinaryInRepositoryInterceptor.java
+++ b/src/main/java/at/gv/egiz/moazs/msg/StoreSOAPBodyBinaryInRepositoryInterceptor.java
@@ -1,6 +1,5 @@
package at.gv.egiz.moazs.msg;
-import at.gv.egiz.moazs.MoaZSException;
import at.gv.egiz.moazs.repository.DeliveryRepository;
import at.gv.egiz.moazs.scheme.SOAPUtils;
import at.gv.egiz.moazs.util.CXFMessageUtils;
@@ -17,6 +16,8 @@ import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
+import static at.gv.egiz.moazs.MoaZSException.moaZSExceptionBuilder;
+
@Component
public class StoreSOAPBodyBinaryInRepositoryInterceptor extends AbstractPhaseInterceptor<Message> {
@@ -48,7 +49,9 @@ public class StoreSOAPBodyBinaryInRepositoryInterceptor extends AbstractPhaseInt
log.info("Store binary DeliveryRequestStatus with AppDeliveryId={}", appDeliveryId);
}
} catch (ParserConfigurationException | SAXException | IOException | NullPointerException e) {
- throw new MoaZSException("Could not extract signed data from message.", e);
+ throw moaZSExceptionBuilder("Could not extract signed data from message.")
+ .withCause(e)
+ .build();
}
}
diff --git a/src/main/java/at/gv/egiz/moazs/mzs/MzsService.java b/src/main/java/at/gv/egiz/moazs/mzs/MzsService.java
index bb927ba..928e3d7 100644
--- a/src/main/java/at/gv/egiz/moazs/mzs/MzsService.java
+++ b/src/main/java/at/gv/egiz/moazs/mzs/MzsService.java
@@ -20,6 +20,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static at.gv.egiz.moazs.MoaZSException.moaZSException;
+import static at.gv.egiz.moazs.MoaZSException.moaZSExceptionBuilder;
import static at.gv.zustellung.app2mzs.xsd.PartialSuccessType.partialSuccessTypeBuilder;
import static java.lang.String.format;
import static java.util.concurrent.CompletableFuture.supplyAsync;
@@ -70,10 +71,11 @@ public class MzsService implements App2MzsPortType {
future.thenAccept(appClient::sendNotification);
return generatePartialSuccessResponse(appDeliveryID);
- } catch (Exception e ) {
- var message = format("An error occurred while processing DeliveryRequest with AppDeliveryID=%s.", appDeliveryID);
- throw new MoaZSException(message, e);
-
+ } catch (Exception e) {
+ throw moaZSExceptionBuilder("An error occurred while processing DeliveryRequest " +
+ "with AppDeliveryID=%s.", appDeliveryID)
+ .withCause(e)
+ .build();
}
}
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<String> 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<String> getAcceptedTypes(PersonResultType result) {
- return result.getSuccess().getMimeTypeList().getMimeType();
+ private DeliveryAnswerType getAnswerFromResult(DeliveryRequestStatusType msgResult) {
+ return coalesce(msgResult.getSuccess(), msgResult.getPartialSuccess(), msgResult.getError()).get();
}
+
}
diff --git a/src/main/java/at/gv/egiz/moazs/scheme/NameSpace.java b/src/main/java/at/gv/egiz/moazs/scheme/NameSpace.java
index 63276cb..fc479eb 100644
--- a/src/main/java/at/gv/egiz/moazs/scheme/NameSpace.java
+++ b/src/main/java/at/gv/egiz/moazs/scheme/NameSpace.java
@@ -5,6 +5,7 @@ public class NameSpace {
private NameSpace() {}
public static final String MSG = new at.gv.zustellung.msg.xsd.ObjectFactory().createDeliveryRequest(null).getName().getNamespaceURI();
+ public static final String MSG_VERSION = "2.2.0";
public static final String MSGP = new at.gv.zustellung.msg.xsd.persondata.ObjectFactory().createPerson(null).getName().getNamespaceURI();
diff --git a/src/main/java/at/gv/egiz/moazs/scheme/SOAPUtils.java b/src/main/java/at/gv/egiz/moazs/scheme/SOAPUtils.java
index 2d4df4b..b1c1909 100644
--- a/src/main/java/at/gv/egiz/moazs/scheme/SOAPUtils.java
+++ b/src/main/java/at/gv/egiz/moazs/scheme/SOAPUtils.java
@@ -13,6 +13,8 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
+import static at.gv.egiz.moazs.MoaZSException.moaZSExceptionBuilder;
+
@Component
public class SOAPUtils {
@@ -30,7 +32,7 @@ public class SOAPUtils {
.getBytes(StandardCharsets.UTF_8);
} catch (IOException | TransformerException e) {
- throw new MoaZSException("Error while parsing message. ", e);
+ throw moaZSExceptionBuilder("Error while parsing message. ").withCause(e).build();
}
}
diff --git a/src/main/java/at/gv/egiz/moazs/tnvz/TnvzClient.java b/src/main/java/at/gv/egiz/moazs/tnvz/TnvzClient.java
index 4a69aea..d4049fc 100644
--- a/src/main/java/at/gv/egiz/moazs/tnvz/TnvzClient.java
+++ b/src/main/java/at/gv/egiz/moazs/tnvz/TnvzClient.java
@@ -1,5 +1,7 @@
package at.gv.egiz.moazs.tnvz;
+import at.gv.egiz.moazs.MoaZSException;
+import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType;
import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType.Sender;
import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType.Receiver;
import at.gv.zustellung.tnvz.xsd.PersonResultSuccessType;
@@ -7,10 +9,18 @@ import at.gv.zustellung.tnvz.xsd.PersonResultType;
import at.gv.zustellung.tnvz.xsd.PersonResultType.PersonResultTypeBuilder;
import org.springframework.stereotype.Component;
+import java.util.Collection;
+import java.util.List;
+
+import static at.gv.egiz.moazs.MoaZSException.moaZSExceptionBuilder;
+import static java.lang.String.join;
+import static java.util.stream.Collectors.toSet;
+
@Component
public class TnvzClient {
- public PersonResultType queryPerson(Sender sender, Receiver receiver) {
+ public PersonResultType query(Sender sender, Receiver receiver) {
+ //TODO: Replace this stub with actual request.
PersonResultSuccessType success = new PersonResultSuccessType.PersonResultSuccessTypeBuilder().build();
return new PersonResultTypeBuilder().withSuccess(success).build();
}
diff --git a/src/main/java/at/gv/egiz/moazs/tnvz/TnvzResultVerifier.java b/src/main/java/at/gv/egiz/moazs/tnvz/TnvzResultVerifier.java
new file mode 100644
index 0000000..9992246
--- /dev/null
+++ b/src/main/java/at/gv/egiz/moazs/tnvz/TnvzResultVerifier.java
@@ -0,0 +1,63 @@
+package at.gv.egiz.moazs.tnvz;
+
+import at.gv.egiz.moazs.MoaZSException;
+import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType;
+import at.gv.zustellung.tnvz.xsd.PersonResultType;
+import org.springframework.stereotype.Component;
+
+import java.util.Collection;
+import java.util.List;
+
+import static at.gv.egiz.moazs.MoaZSException.moaZSExceptionBuilder;
+import static java.lang.String.join;
+import static java.util.stream.Collectors.toSet;
+
+@Component
+public class TnvzResultVerifier {
+
+ public void verify(DeliveryRequestType request, PersonResultType result) {
+
+ if (result.getError() != null) {
+ var info = result.getError().getErrorInfo();
+ throw moaZSExceptionBuilder("Receiver is not addressable. Reason: %s", info.getText())
+ .withErrorCode(info.getCode())
+ .withMzsRequest(request)
+ .withTnvzResult(result)
+ .build();
+ }
+
+ var mismatchedTypes = findMimeTypeMismatches(result, request);
+
+ 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 moaZSExceptionBuilder(template, mismatchedTypesString, acceptedTypesString)
+ .withErrorCode(MoaZSException.ERROR_MZS_MIMETYPE_MISSMATCH)
+ .withMzsRequest(request)
+ .withTnvzResult(result)
+ .build();
+ }
+ }
+
+ private Collection<String> findMimeTypeMismatches(PersonResultType result, DeliveryRequestType request) {
+ var acceptedTypes = getAcceptedTypes(result);
+
+ if (acceptedTypes.contains("*/*")) {
+ return List.of();
+ }
+
+ var typesInRequest = request.getPayload().stream()
+ .map(DeliveryRequestType.Payload::getMIMEType)
+ .collect(toSet());
+
+ typesInRequest.removeAll(acceptedTypes);
+
+ return typesInRequest;
+ }
+
+ private List<String> getAcceptedTypes(PersonResultType result) {
+ return result.getSuccess().getMimeTypeList().getMimeType();
+ }
+}
diff --git a/src/test/java/at/gv/egiz/moazs/MsgClientTest.java b/src/test/java/at/gv/egiz/moazs/MsgClientTest.java
index 1822ff5..8cebf06 100644
--- a/src/test/java/at/gv/egiz/moazs/MsgClientTest.java
+++ b/src/test/java/at/gv/egiz/moazs/MsgClientTest.java
@@ -2,6 +2,7 @@ package at.gv.egiz.moazs;
import at.gv.egiz.moazs.msg.MsgClient;
import at.gv.egiz.moazs.msg.MsgClientFactory;
+import at.gv.egiz.moazs.msg.StoreSOAPBodyBinaryInRepositoryInterceptor;
import at.gv.egiz.moazs.scheme.Marshaller;
import at.gv.zustellung.app2mzs.xsd.ConfigType;
import at.gv.zustellung.msg.xsd.DeliveryRequestType;
@@ -39,6 +40,9 @@ public class MsgClientTest {
@Autowired
private MsgClientFactory factory;
+ @Autowired
+ private StoreSOAPBodyBinaryInRepositoryInterceptor interceptor;
+
private static final ObjectFactory OF = new ObjectFactory();
@@ -49,7 +53,7 @@ public class MsgClientTest {
var request = loadFromFile("validDeliveryRequest.xml");
var config = generateConfig(httpServiceUri);
- var client = factory.create(request, config);
+ var client = factory.create(request, config, interceptor);
try{
var status = client.send();
@@ -64,7 +68,7 @@ public class MsgClientTest {
var request = loadFromFile("validDeliveryRequest.xml");
var config = generateConfig(sslServiceUri);
- var client = factory.create(request, config);
+ var client = factory.create(request, config, interceptor);
var status = client.send();
diff --git a/src/test/java/at/gv/egiz/moazs/SameThreadDeliveryPipelineTest.java b/src/test/java/at/gv/egiz/moazs/SameThreadDeliveryPipelineTest.java
index 5e4b9b0..b0c03a2 100644
--- a/src/test/java/at/gv/egiz/moazs/SameThreadDeliveryPipelineTest.java
+++ b/src/test/java/at/gv/egiz/moazs/SameThreadDeliveryPipelineTest.java
@@ -2,11 +2,15 @@ package at.gv.egiz.moazs;
import at.gv.egiz.moazs.msg.MsgClient;
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.pipeline.DeliveryPipeline;
import at.gv.egiz.moazs.pipeline.SameThreadDeliveryPipeline;
import at.gv.egiz.moazs.repository.DeliveryRepository;
+import at.gv.egiz.moazs.repository.InMemoryDeliveryRepository;
import at.gv.egiz.moazs.scheme.Mzs2MsgConverter;
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.msg.xsd.DeliveryRequestStatusType;
import at.gv.zustellung.msg.xsd.MetaData;
@@ -24,6 +28,7 @@ import static at.gv.zustellung.app2mzs.xsd.ConfigType.configTypeBuilder;
import static at.gv.zustellung.app2mzs.xsd.DeliveryRequestType.Payload;
import static at.gv.zustellung.app2mzs.xsd.DeliveryRequestType.Payload.payloadBuilder;
import static at.gv.zustellung.app2mzs.xsd.DeliveryRequestType.deliveryRequestTypeBuilder;
+import static at.gv.zustellung.app2mzs.xsd.ServerType.serverTypeBuilder;
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.ErrorInfoType.errorInfoTypeBuilder;
@@ -32,16 +37,15 @@ import static at.gv.zustellung.tnvz.xsd.MimeTypeList.mimeTypeListBuilder;
import static at.gv.zustellung.tnvz.xsd.PersonResultSuccessType.personResultSuccessTypeBuilder;
import static at.gv.zustellung.tnvz.xsd.PersonResultType.Error.errorBuilder;
import static at.gv.zustellung.tnvz.xsd.PersonResultType.personResultTypeBuilder;
-import static java.util.Optional.of;
import static java.util.stream.Collectors.toList;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class SameThreadDeliveryPipelineTest {
- @Mock
- private DeliveryRepository repository;
+ private DeliveryRepository repository = new InMemoryDeliveryRepository();
@Mock
private TnvzClient tnvzClient;
@@ -55,34 +59,46 @@ public class SameThreadDeliveryPipelineTest {
@Mock
private Mzs2MsgConverter converter;
+ @Mock
+ private StoreSOAPBodyBinaryInRepositoryInterceptor interceptor;
+
+ @Mock
+ private SignatureVerifier verifier;
+
private DeliveryPipeline pipeline;
@Before
public void setup() {
- pipeline = new SameThreadDeliveryPipeline(repository, tnvzClient, converter, msgClientFactory);
+ pipeline = new SameThreadDeliveryPipeline(repository, tnvzClient, new TnvzResultVerifier(),
+ converter,interceptor, msgClientFactory, verifier);
}
@Test
public void executePipelineWithoutTnvzRequest() {
var appDeliveryId = "no-tnvz-request";
- var status = setupMocks(appDeliveryId, false, List.of(), List.of("*/*"));
+ var expectedStatus = setupMocks(appDeliveryId, false, List.of(), List.of("*/*"));
pipeline.processRequest(appDeliveryId);
verifyZeroInteractions(tnvzClient);
- verify(repository).add(status);
+ var actualStatus = repository.getDeliveryRequestStatus(appDeliveryId).get();
+
+ assertThat(actualStatus).isEqualTo(expectedStatus);
}
- @Test(expected = MoaZSException.class)
+ @Test
public void rejectDeliveryWhenReceiverIsNotAddressable() {
var appDeliveryId = "not-addressable";
setupMocks(appDeliveryId, true, List.of(), List.of("*/*"));
- when(tnvzClient.queryPerson(any(), any())).thenReturn(setupTnvzError());
+ when(tnvzClient.query(any(), any())).thenReturn(setupTnvzError("400", "Person not found."));
pipeline.processRequest(appDeliveryId);
+ var actualCode = repository.getDeliveryRequestStatus(appDeliveryId).get()
+ .getError().getErrorInfo().getCode();
- verify(tnvzClient).queryPerson(any(), any());
+ verify(tnvzClient).query(any(), any());
+ assertThat(actualCode).isEqualTo("400");
}
@Test
@@ -90,15 +106,16 @@ public class SameThreadDeliveryPipelineTest {
var appDeliveryId = "wild-card-mimetype";
List<String> acceptedTypes = List.of("*/*");
List<String> attachedTypes = List.of("pdf", "xml", "html", "random/attachedtype");
- var status = setupMocks(appDeliveryId, true, attachedTypes, acceptedTypes);
+ var expectedStatus = setupMocks(appDeliveryId, true, attachedTypes, acceptedTypes);
pipeline.processRequest(appDeliveryId);
+ var actualStatus = repository.getDeliveryRequestStatus(appDeliveryId).get();
- verify(tnvzClient).queryPerson(any(), any());
- verify(repository).add(status);
+ verify(tnvzClient).query(any(), any());
+ assertThat(actualStatus).isEqualTo(expectedStatus);
}
- @Test(expected = MoaZSException.class)
+ @Test
public void rejectMismatchedMimeTypes() {
var appDeliveryId = "mismatched-mimetype";
List<String> acceptedTypes = List.of("xml");
@@ -106,8 +123,12 @@ public class SameThreadDeliveryPipelineTest {
setupMocks(appDeliveryId, true, attachedTypes, acceptedTypes);
pipeline.processRequest(appDeliveryId);
+ var actualCode = repository.getDeliveryRequestStatus(appDeliveryId).get()
+ .getError().getErrorInfo().getCode();
+
+ verify(tnvzClient).query(any(), any());
+ assertThat(actualCode).isEqualTo(MoaZSException.ERROR_MZS_MIMETYPE_MISSMATCH);
- verify(tnvzClient).queryPerson(any(), any());
}
@Test
@@ -115,36 +136,59 @@ public class SameThreadDeliveryPipelineTest {
var appDeliveryId = "specific-mimetype";
List<String> acceptedTypes = List.of("pdf", "xml", "html");
List<String> attachedTypes = List.of("pdf", "xml");
- var status = setupMocks(appDeliveryId, true, attachedTypes, acceptedTypes);
+ var expectedStatus = setupMocks(appDeliveryId, true, attachedTypes, acceptedTypes);
+
+ pipeline.processRequest(appDeliveryId);
+ var actualStatus = repository.getDeliveryRequestStatus(appDeliveryId).get();
+
+ verify(tnvzClient).query(any(), any());
+ assertThat(actualStatus).isEqualTo(expectedStatus);
+ }
+
+ @Test
+ public void rejectInvalidSignature() {
+ var appDeliveryId = "invalid-signature";
+ setupMocks(appDeliveryId, true, List.of(), List.of("*/*"), false);
pipeline.processRequest(appDeliveryId);
+ var actualCode = repository.getDeliveryRequestStatus(appDeliveryId).get()
+ .getError().getErrorInfo().getCode();
+
+ assertThat(actualCode).isEqualTo(MoaZSException.ERROR_MOASP_SIGNATURE_INVALID);
- verify(tnvzClient).queryPerson(any(), any());
- verify(repository).add(status);
}
private DeliveryRequestStatusType setupMocks(String appDeliveryId, boolean tnvzRequest,
List<String> attachedTypes, List<String> acceptedTypes) {
+ return setupMocks(appDeliveryId, tnvzRequest, attachedTypes, acceptedTypes, true);
+ }
+
+ private DeliveryRequestStatusType setupMocks(String appDeliveryId, boolean tnvzRequest,
+ List<String> attachedTypes, List<String> acceptedTypes, boolean isSignedStatusValid) {
var mzsRequest = setupMzsRequest(appDeliveryId, tnvzRequest, attachedTypes);
var msgRequest = setupMsgRequest(appDeliveryId);
var status = setupStatus(appDeliveryId);
- when(repository.getDeliveryRequest(appDeliveryId)).thenReturn(of(mzsRequest));
- when(tnvzClient.queryPerson(any(), any())).thenReturn(setupTnvzSuccess(acceptedTypes));
+ var signedStatus = new byte[0];
+ repository.add(mzsRequest);
+ repository.addSignedDeliveryRequestStatus(signedStatus, appDeliveryId);
+
+ when(tnvzClient.query(any(), any())).thenReturn(setupTnvzSuccess(acceptedTypes));
when(converter.convert(eq(mzsRequest) )).thenReturn(msgRequest);
when(converter.convert(eq(mzsRequest), any())).thenReturn(msgRequest);
- when(msgClientFactory.create(msgRequest, mzsRequest.getConfig())).thenReturn(msgClient);
+ when(msgClientFactory.create(msgRequest, mzsRequest.getConfig(), interceptor)).thenReturn(msgClient);
when(msgClient.send()).thenReturn(status);
+ when(verifier.verify(signedStatus)).thenReturn(isSignedStatusValid);
return status;
}
- private PersonResultType setupTnvzError() {
+ private PersonResultType setupTnvzError(String code, String text) {
var info = errorInfoTypeBuilder()
- .withCode("400")
- .withText("Person Not Found")
+ .withCode(code)
+ .withText(text)
.build();
var error = errorBuilder()
@@ -181,8 +225,13 @@ public class SameThreadDeliveryPipelineTest {
private DeliveryRequestType setupMzsRequest(String appDeliveryId, boolean tnvzRequest, List<String> mimeTypes) {
+ var server = serverTypeBuilder()
+ .withZUSEUrlID("http://zuse")
+ .build();
+
var config = configTypeBuilder()
.withPerformQueryPersonRequest(tnvzRequest)
+ .withServer(server)
.build();
return deliveryRequestTypeBuilder()