diff options
author | Christof Rabensteiner <christof.rabensteiner@iaik.tugraz.at> | 2019-07-22 13:02:19 +0200 |
---|---|---|
committer | Christof Rabensteiner <christof.rabensteiner@iaik.tugraz.at> | 2019-07-22 13:02:19 +0200 |
commit | cb9a76eaafd37f921006822bcfe043655288bc63 (patch) | |
tree | 76c2463e181ac293134f4c5bfc7e342607f3f399 /src | |
parent | d873625c0ced62e712dc1b1a7570b63482fd0a0a (diff) | |
download | moa-zs-cb9a76eaafd37f921006822bcfe043655288bc63.tar.gz moa-zs-cb9a76eaafd37f921006822bcfe043655288bc63.tar.bz2 moa-zs-cb9a76eaafd37f921006822bcfe043655288bc63.zip |
Test Flow of DeliveryRequest from "End-To-End" & Fix Bugs
Schema Changes:
- Remove mzs:DeliveryRequest/TnvzMetaData because all metadata fields
can be collected from DeliveryRequest and redundancy is not needed.
Fixes and Refactoring in preprocess:
- MzsDeliveryRequestValidator: Instead of returning false, throw an
exception when a condition is not met, and explain which condition
is not met / why it is not met in the exception's message.
- Integrate interface change in ConfigProfileGenerator and
DeliveryRequestAugmenter.
- Rewrite and simplify DeliveryRequestAugmenter's augmentation.
- ConfigUtil Fixes: Ensure that we do not override the wrong
parameters while merging. This error appeared in tnvz / msg client,
connection / receive timeout, key / trust store, and lax hostname
verification / trust all.
Fix Bugs in Interceptor / SoapUtils:
- Problem: DOM access and information extraction was implemented
somewhat sloppy.
- SolutioN: Change DOM access interface to access DOM more
efficiently. Add boundary checks and handle edge cases while
extracting information from SOAP Messages.
- Test those changes properly.
Testing:
- Implement Delivery Request Flow in ITEndToEndTest.
- Start application on random port instead of fixed port when running
integration tests.
- Add assertions to tests in ITMzsServiceTest suite.
Others Bug Fixes:
- ServicesConfig: Ensure that mzs service and msg service run on
different endpoint addresses (/msg and /mzs).
- DeliveryRequestBackend: Throw exception when binary message is
missing. Don't wrap the exception.
- SaveResponseToFileSink: Wrap Response in JAXB Element (otherwise,
marshaller does not recognize it)
Diffstat (limited to 'src')
26 files changed, 961 insertions, 187 deletions
diff --git a/src/main/java/at/gv/egiz/moazs/backend/DeliveryRequestBackend.java b/src/main/java/at/gv/egiz/moazs/backend/DeliveryRequestBackend.java index 6a1e0fd..72f8ba0 100644 --- a/src/main/java/at/gv/egiz/moazs/backend/DeliveryRequestBackend.java +++ b/src/main/java/at/gv/egiz/moazs/backend/DeliveryRequestBackend.java @@ -18,10 +18,10 @@ import org.springframework.stereotype.Component; import java.util.function.Consumer; -import static at.gv.egiz.moazs.scheme.RequestStatusResponse.*; +import static at.gv.egiz.moazs.MoaZSException.moaZSException; import static at.gv.egiz.moazs.scheme.RequestStatusResponse.generateError; +import static at.gv.egiz.moazs.scheme.RequestStatusResponse.getAnswer; import static at.gv.zustellung.msg.xsd.DeliveryRequestStatusType.Error.errorBuilder; -import static at.gv.zustellung.msg.xsd.DeliveryRequestStatusType.deliveryRequestStatusTypeBuilder; import static java.lang.String.format; @Component @@ -72,7 +72,7 @@ public class DeliveryRequestBackend implements Consumer<String> { try { var mzsRequest = repository.retrieveDeliveryRequest(appDeliveryID).orElseThrow( - () -> MoaZSException.moaZSException(format(DELIVERY_REQUEST_MISSING_ERROR_MSG, appDeliveryID))); + () -> moaZSException(format(DELIVERY_REQUEST_MISSING_ERROR_MSG, appDeliveryID))); fallbackAnswerBuilder.withDeliverySystem(mzsRequest.getConfig().getMSGClient().getURL()); var msgRequest = buildMsgRequest(mzsRequest); @@ -98,14 +98,15 @@ public class DeliveryRequestBackend implements Consumer<String> { } private void verifySignedStatus(String responseID, String appDeliveryID) throws MoaZSException { + var signedStatus = repository.retrieveBinaryResponse(responseID).orElseThrow(() -> moaZSException( + format(BINARY_RESPONSE_MISSING_ERROR_MSG, responseID), + MoaZSException.ERROR_MZS_BINARY_RESPONSE_MISSING)); try { - var signedStatus = repository.retrieveBinaryResponse(responseID).orElseThrow( - () -> MoaZSException.moaZSException(format(BINARY_RESPONSE_MISSING_ERROR_MSG, responseID))); signatureVerifier.accept(signedStatus); } catch (MoaZSException ex) { var message = format(MsgResponseBackend.MOASP_SIGNATURE_INVALID_ERROR_MSG, appDeliveryID); var code = MoaZSException.ERROR_MOASP_SIGNATURE_INVALID; - throw MoaZSException.moaZSException(message, code, ex); + throw moaZSException(message, code, ex); } } diff --git a/src/main/java/at/gv/egiz/moazs/backend/SaveResponseToFileSink.java b/src/main/java/at/gv/egiz/moazs/backend/SaveResponseToFileSink.java index 2468ca9..c58e1a5 100644 --- a/src/main/java/at/gv/egiz/moazs/backend/SaveResponseToFileSink.java +++ b/src/main/java/at/gv/egiz/moazs/backend/SaveResponseToFileSink.java @@ -50,7 +50,7 @@ public class SaveResponseToFileSink { var responseID = response.getResponseID(); var responsePath = generatePath(rootPath, responseID, "xml"); - var storeResponseToFileSystemFuture = supplyAsync(() -> msgMarshaller.marshallXml(response.getResponse())) + var storeResponseToFileSystemFuture = supplyAsync(() -> msgMarshaller.marshallXml(response.getResponseAsJAXBElement())) .thenApply(responseString -> responseString.getBytes(StandardCharsets.UTF_8)) .thenAccept(responseByteArray -> storeToFile(responsePath, responseByteArray)) .exceptionally(ex -> logException(ex, responseID)); diff --git a/src/main/java/at/gv/egiz/moazs/client/TnvzHelper.java b/src/main/java/at/gv/egiz/moazs/client/TnvzHelper.java index de22805..a304bdf 100644 --- a/src/main/java/at/gv/egiz/moazs/client/TnvzHelper.java +++ b/src/main/java/at/gv/egiz/moazs/client/TnvzHelper.java @@ -96,18 +96,16 @@ public class TnvzHelper { var builder = metaDataBuilder(); - var meta = request.getTnvzMetaData(); - + var meta = request.getMetaData(); if (meta.getDeliveryQuality() != null) { builder.withDeliveryQuality(meta.getDeliveryQuality()); } else { builder.withPrivateMessageQuality(meta.getPrivateMessageQuality()); } - return builder - .withOrigin(meta.getOrigin()) - .withPreAdviceNote(request.getReceiver().getPreAdviceNote()) + return builder.withOrigin(meta.getOrigin()) .withIgnorePostRedirectionOrder(meta.getIgnorePostRedirectionOrder()) + .withPreAdviceNote(request.getReceiver().getPreAdviceNote()) .build(); } 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 c16dfd2..6f71e50 100644 --- a/src/main/java/at/gv/egiz/moazs/config/ServicesConfig.java +++ b/src/main/java/at/gv/egiz/moazs/config/ServicesConfig.java @@ -23,14 +23,15 @@ public class ServicesConfig { @Autowired public Endpoint msgEndpoint(MsgService msgService, Zuse2AppPortService zuse2app, - Interceptor<Message> msgInterceptor) { - return endpointFactory.create(msgService, zuse2app, msgInterceptor); + Interceptor<Message> msgInterceptor + ) { + return endpointFactory.create(msgService, zuse2app, "/msg", msgInterceptor); } @Bean @Autowired public Endpoint mzsEndpoint(MzsService mzsService, App2Mzs app2mzs) { - return endpointFactory.create(mzsService, app2mzs); + return endpointFactory.create(mzsService, app2mzs, "/mzs"); } @Bean diff --git a/src/main/java/at/gv/egiz/moazs/preprocess/ConfigProfileGenerator.java b/src/main/java/at/gv/egiz/moazs/preprocess/ConfigProfileGenerator.java index 5e81f0d..0637f98 100644 --- a/src/main/java/at/gv/egiz/moazs/preprocess/ConfigProfileGenerator.java +++ b/src/main/java/at/gv/egiz/moazs/preprocess/ConfigProfileGenerator.java @@ -11,6 +11,8 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import static at.gv.egiz.moazs.MoaZSException.moaZSException; +import static java.lang.String.format; import static java.util.stream.Collectors.*; public class ConfigProfileGenerator { @@ -70,9 +72,11 @@ public class ConfigProfileGenerator { var defaultProfile = profiles.get(defaultConfigKey); - if (!validator.isConfigProfileComplete(defaultProfile)) { + try { + validator.isConfigProfileComplete(defaultProfile); + } catch (MoaZSException ex) { if (verifyCompletenessOfDefaultConfiguration) - throw MoaZSException.moaZSException(PROFILE_NOT_COMPLETE_ERROR_MESSAGE); + throw moaZSException(format("%s Reason: %s", PROFILE_NOT_COMPLETE_ERROR_MESSAGE, ex.getMessage())); else { LOGGER.warn(PROFILE_NOT_COMPLETE_WARNING_MESSAGE); } diff --git a/src/main/java/at/gv/egiz/moazs/preprocess/ConfigUtil.java b/src/main/java/at/gv/egiz/moazs/preprocess/ConfigUtil.java index 056f6dc..f49132f 100644 --- a/src/main/java/at/gv/egiz/moazs/preprocess/ConfigUtil.java +++ b/src/main/java/at/gv/egiz/moazs/preprocess/ConfigUtil.java @@ -205,7 +205,7 @@ public class ConfigUtil { } if (primary.getTNVZClient() != null) { - builder.withMSGClient(merge(primary.getTNVZClient(), fallback.getTNVZClient())); + builder.withTNVZClient(merge(primary.getTNVZClient(), fallback.getTNVZClient())); } if (primary.getMsgResponseSinks() != null) { @@ -240,7 +240,7 @@ public class ConfigUtil { } if (primary.getReceiveTimeout() != null) { - builder.withConnectionTimeout(primary.getReceiveTimeout()); + builder.withReceiveTimeout(primary.getReceiveTimeout()); } return builder.build(); @@ -259,7 +259,7 @@ public class ConfigUtil { } if (primary.getTrustStore() != null) { - builder.withKeyStore(merge(primary.getTrustStore(), fallback.getTrustStore())); + builder.withTrustStore(merge(primary.getTrustStore(), fallback.getTrustStore())); } if (primary.isLaxHostNameVerification() != null) { @@ -267,8 +267,9 @@ public class ConfigUtil { } if (primary.isTrustAll() != null) { - builder.withLaxHostNameVerification(primary.isTrustAll()); + builder.withTrustAll(primary.isTrustAll()); } + return builder.build(); } diff --git a/src/main/java/at/gv/egiz/moazs/preprocess/DeliveryRequestAugmenter.java b/src/main/java/at/gv/egiz/moazs/preprocess/DeliveryRequestAugmenter.java index e7ee357..240a677 100644 --- a/src/main/java/at/gv/egiz/moazs/preprocess/DeliveryRequestAugmenter.java +++ b/src/main/java/at/gv/egiz/moazs/preprocess/DeliveryRequestAugmenter.java @@ -1,36 +1,41 @@ package at.gv.egiz.moazs.preprocess; +import at.gv.egiz.moazs.scheme.Marshaller; import at.gv.zustellung.app2mzs.xsd.ConfigType; import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType; +import at.gv.zustellung.app2mzs.xsd.ObjectFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.lang.Nullable; import org.springframework.stereotype.Component; import java.util.Map; import static at.gv.egiz.moazs.MoaZSException.moaZSException; +import static at.gv.egiz.moazs.util.NullCoalesce.coalesce; import static at.gv.zustellung.app2mzs.xsd.DeliveryRequestType.deliveryRequestTypeBuilder; -import static java.lang.String.format; @Component public class DeliveryRequestAugmenter { + private static final Logger log = LoggerFactory.getLogger(DeliveryRequestAugmenter.class); + private static final ObjectFactory FACTORY = new ObjectFactory(); + private final ConfigUtil util; private final Map<String, ConfigType> configs; private final MzsDeliveryRequestValidator validator; + private final Marshaller mzsMarshaller; - private static final String INCOMPLETE_TNVZ_ERROR_MESSAGE = "mzs:DeliveryRequest is incomplete because mandatory " + - "fields for sending a tnvz:QueryPersonRequest are missing."; - private static final String INCOMPLETE_CONFIG_ERROR_MESSAGE = "Could not find a profile for " + - "the delivery request configuration, and the configuration attached to mzs:DeliveryRequest is incomplete."; - private static final String INCOMPLETE_MERGED_CONFIG_ERROR_MESSAGE = "I merged parameters from " + - "mzs:DeliveryRequest/Config with parameters from config profile with ProfileId='%s', but the " + - "configuration is incomplete."; + private static final String CONFIG_MISSING_ERROR_MSG = "Delivery request configuration is missing."; @Autowired - public DeliveryRequestAugmenter(Map<String, ConfigType> deliveryRequestConfigs, ConfigUtil util, MzsDeliveryRequestValidator validator) { + public DeliveryRequestAugmenter(Map<String, ConfigType> deliveryRequestConfigs, ConfigUtil util, + MzsDeliveryRequestValidator validator, Marshaller mzsMarshaller) { this.configs = deliveryRequestConfigs; this.util = util; this.validator = validator; + this.mzsMarshaller = mzsMarshaller; } /** @@ -46,41 +51,29 @@ public class DeliveryRequestAugmenter { var fallbackProfileId = determineProfileIdFrom(requestConfig); var fallbackConfig = configs.get(fallbackProfileId); - if (fallbackConfig == null) { - - if (!validator.isConfigProfileComplete(request.getConfig())) { - throw moaZSException(INCOMPLETE_CONFIG_ERROR_MESSAGE); - } else if (!validator.isTnvzComplete(request)) { - throw moaZSException(INCOMPLETE_TNVZ_ERROR_MESSAGE); - } else { - return request; - } + trace("request config", requestConfig); + trace("fallback config", fallbackConfig); - } else { + var augmentedConfig = (requestConfig != null && fallbackConfig != null) + ? util.merge(requestConfig, fallbackConfig) + : coalesce(requestConfig, fallbackConfig) + .orElseThrow(()-> moaZSException(CONFIG_MISSING_ERROR_MSG)); - var mergedConfig = (requestConfig == null) - ? fallbackConfig - : util.merge(requestConfig, fallbackConfig); + trace("augmented config", augmentedConfig); - if (!validator.isConfigProfileComplete(mergedConfig)) { - var message = format(INCOMPLETE_MERGED_CONFIG_ERROR_MESSAGE, fallbackProfileId); - throw moaZSException(message); - } + validator.isConfigProfileComplete(augmentedConfig); - var mergedRequest = deliveryRequestTypeBuilder(request) - .withConfig(mergedConfig) - .build(); + var augmentedRequest = deliveryRequestTypeBuilder(request) + .withConfig(augmentedConfig) + .build(); - if (!validator.isTnvzComplete(mergedRequest)) { - throw moaZSException(INCOMPLETE_TNVZ_ERROR_MESSAGE); - } + validator.isTnvzComplete(augmentedRequest); - return mergedRequest; + return augmentedRequest; - } } - private String determineProfileIdFrom(ConfigType requestConfig) { + private String determineProfileIdFrom(@Nullable ConfigType requestConfig) { return (requestConfig == null || requestConfig.getProfileID() == null || isProfileMissing(requestConfig.getProfileID())) @@ -92,4 +85,11 @@ public class DeliveryRequestAugmenter { return !configs.containsKey(id); } + private void trace(String description, ConfigType config) { + if (log.isTraceEnabled()) { + log.trace("{} : {}", description, mzsMarshaller.marshallXml(FACTORY.createConfig(config))); + } + } + + } diff --git a/src/main/java/at/gv/egiz/moazs/preprocess/MzsDeliveryRequestValidator.java b/src/main/java/at/gv/egiz/moazs/preprocess/MzsDeliveryRequestValidator.java index 2c2fc36..67086a2 100644 --- a/src/main/java/at/gv/egiz/moazs/preprocess/MzsDeliveryRequestValidator.java +++ b/src/main/java/at/gv/egiz/moazs/preprocess/MzsDeliveryRequestValidator.java @@ -1,90 +1,168 @@ package at.gv.egiz.moazs.preprocess; +import at.gv.egiz.moazs.MoaZSException; import at.gv.zustellung.app2mzs.xsd.*; import org.springframework.lang.Nullable; import org.springframework.stereotype.Component; +import static at.gv.egiz.moazs.MoaZSException.moaZSException; +import static at.gv.egiz.moazs.scheme.NameSpace.*; +import static java.lang.String.format; + @Component public class MzsDeliveryRequestValidator { /** * Checks if the mandatory fields that are needed to send a tnvz:QueryPersonRequest are present. * @param request - * @return true if mandatory fields are present. + * @throws MoaZSException if a field is missing. */ - public boolean isTnvzComplete(DeliveryRequestType request) { - return !request.getConfig().isPerformQueryPersonRequest() || - (request.getTnvzMetaData() != null - && request.getSender().getCorporateBody() != null); + public void isTnvzComplete(DeliveryRequestType request) { + if (request.getConfig().isPerformQueryPersonRequest()) { + + if (request.getMetaData().getOrigin() == null) + throw mzse(MZS_DELIVERY_REQUEST, MZS_DELIVERY_REQUEST + "/MetaData/Origin is missing."); + + if (request.getMetaData().getDeliveryQuality() == null) + throw mzse(MZS_DELIVERY_REQUEST, MZS_DELIVERY_REQUEST + "/MetaData/DeliveryQuality missing."); + + if (request.getSender().getCorporateBody() == null) + throw mzse(MZS_DELIVERY_REQUEST, MZS_DELIVERY_REQUEST + "/Sender/CorporateBody is missing."); + } } /** * Check if all mandatory fields of configuration are present. * * @param profile - * @return true if all mandatory fields are present. + * @throws MoaZSException if a field is missing. */ - public boolean isConfigProfileComplete(@Nullable ConfigType profile) { - return profile != null - && profile.isPerformQueryPersonRequest() != null - && isTVNZClientConfigured(profile.getTNVZClient(), profile.isPerformQueryPersonRequest()) - && isClientConfigured(profile.getMSGClient()) - && areSinksConfigured(profile.getMsgResponseSinks()); + public void isConfigProfileComplete(@Nullable ConfigType profile) { + + if (profile == null) + throw mzse(MZS_DELIVERY_REQUEST + "/Config"); + + if (profile.isPerformQueryPersonRequest() == null) + throw mzse(MZS_DELIVERY_REQUEST + "/Config", "PerformQueryPersonRequest is missing."); + + isTNVZClientConfigured(profile.getTNVZClient(), profile.isPerformQueryPersonRequest()); + areSinksConfigured(profile.getMsgResponseSinks()); + + try { + isClientConfigured(profile.getMSGClient()); + } catch (MoaZSException ex) { + throw mzse(MZS_MSGCLIENT, ex.getMessage()); + } + } - private boolean isTVNZClientConfigured(ClientType tnvzClient, Boolean isPerformQueryPersonRequest) { - return !isPerformQueryPersonRequest || (tnvzClient != null + private void isTNVZClientConfigured(@Nullable ClientType tnvzClient, Boolean isPerformQueryPersonRequest) { + if (!isPerformQueryPersonRequest) return; + + var isConfigured = tnvzClient != null && tnvzClient.getURL() != null && tnvzClient.getReceiveTimeout() != null - && tnvzClient.getConnectionTimeout() != null - && isSSLConfigured(tnvzClient)); + && tnvzClient.getConnectionTimeout() != null; + + if (!isConfigured) { + if(tnvzClient == null) throw mzse(MZS_TNVZCLIENT); + + var reasons = new StringBuilder("The following elements in " + MZS_TNVZCLIENT + " are missing: "); + if(tnvzClient.getURL() == null) reasons.append("URL;"); + if(tnvzClient.getReceiveTimeout() == null) reasons.append("ReceiveTimeout;"); + if(tnvzClient.getConnectionTimeout() == null) reasons.append("ConnectionTimeout;"); + throw mzse(MZS_TNVZCLIENT, reasons.toString()); + } + + try { + isSSLConfigured(tnvzClient); + } catch (MoaZSException ex) { + throw mzse(MZS_TNVZCLIENT, ex.getMessage()); + } } - private boolean isClientConfigured(ClientType clientParams) { - return clientParams != null + private void isClientConfigured(@Nullable ClientType clientParams) { + var isConfigured = clientParams != null && clientParams.getURL() != null - && isSSLConfigured(clientParams) && clientParams.getReceiveTimeout() != null && clientParams.getConnectionTimeout() != null; + + if (!isConfigured) throw mzse("Client"); + + isSSLConfigured(clientParams); + } - private boolean isSSLConfigured(ClientType clientParams) { - return !clientParams.getURL().startsWith("https") || (clientParams.getSSL() != null - && clientParams.getSSL().isTrustAll() != null - && clientParams.getSSL().isLaxHostNameVerification() != null - && isKeyStoreConfigured(clientParams.getSSL().getKeyStore()) - && isTrustStoreConfigured(clientParams.getSSL().getTrustStore())); + private void isSSLConfigured(ClientType clientParams) { + if (!clientParams.getURL().startsWith("https")) return; + + var isConfigured = (clientParams.getSSL() != null + && clientParams.getSSL().isTrustAll() != null + && clientParams.getSSL().isLaxHostNameVerification() != null); + if (!isConfigured) throw mzse("SSL"); + + try { + isKeyStoreConfigured(clientParams.getSSL().getKeyStore()); + isTrustStoreConfigured(clientParams.getSSL().getTrustStore()); + } catch (MoaZSException ex) { + throw mzse("SSL", ex.getMessage()); + } } - private boolean isKeyStoreConfigured(KeyStoreType keyStore) { - return keyStore == null || (keyStore.getPassword() != null + private void isKeyStoreConfigured(@Nullable KeyStoreType keyStore) { + if (keyStore == null) return; + + var isConfigured = keyStore.getPassword() != null && keyStore.getFileType() != null - && keyStore.getFileName() != null); + && keyStore.getFileName() != null; + if (!isConfigured) throw mzse("KeyStore"); } - private boolean isTrustStoreConfigured(KeyStoreType trustStore) { - return trustStore == null || (trustStore.getPassword() != null + private void isTrustStoreConfigured(@Nullable KeyStoreType trustStore) { + if (trustStore == null) return; + + var isConfigured = trustStore.getPassword() != null && "JKS".equals(trustStore.getFileType()) - && trustStore.getFileName() != null); + && trustStore.getFileName() != null; + if (!isConfigured) throw mzse("TrustStore"); } - private boolean areSinksConfigured(MsgResponseSinksType sinks) { - return sinks != null - && sinks.isLogResponse() != null - && isSaveResponseToFileConfigured(sinks.getSaveResponseToFile()) - && isForwardResponseToServiceConfigured(sinks.getForwardResponseToService()); + private void areSinksConfigured(@Nullable MsgResponseSinksType sinks) { + var isConfigured = sinks != null && sinks.isLogResponse() != null; + if (!isConfigured) throw mzse("MsgResponseSinks"); + + isSaveResponseToFileConfigured(sinks.getSaveResponseToFile()); + isForwardResponseToServiceConfigured(sinks.getForwardResponseToService()); } - private boolean isSaveResponseToFileConfigured(SaveResponseToFileType fileSink) { - return fileSink != null + private void isSaveResponseToFileConfigured(@Nullable SaveResponseToFileType fileSink) { + var isConfigured = fileSink != null && (!fileSink.isActive() || fileSink.getPath() != null); + + if (!isConfigured) throw mzse("SaveResponseToFile"); + } + + private void isForwardResponseToServiceConfigured(@Nullable ForwardResponseToServiceType forwardSink) { + if (forwardSink == null) throw mzse("ForwardResponseToService"); + + if (forwardSink.isActive()) { + try { + isClientConfigured(forwardSink.getMzsClient()); + } catch (MoaZSException e) { + throw mzse("ForwardResponseToService", e.getMessage()); + } + } } - private boolean isForwardResponseToServiceConfigured(ForwardResponseToServiceType forwardSink) { - return forwardSink != null - && (!forwardSink.isActive() || isClientConfigured(forwardSink.getMzsClient())); + private MoaZSException mzse(String missing) { + return moaZSException(format("%s is not configured.", missing)); } + private MoaZSException mzse(String missing, String reason) { + return moaZSException(format("%s is not configured. Reason: %s", missing, reason)); + } + + } diff --git a/src/main/java/at/gv/egiz/moazs/repository/InMemoryDeliveryRepository.java b/src/main/java/at/gv/egiz/moazs/repository/InMemoryDeliveryRepository.java index 41b742b..b8a6d78 100644 --- a/src/main/java/at/gv/egiz/moazs/repository/InMemoryDeliveryRepository.java +++ b/src/main/java/at/gv/egiz/moazs/repository/InMemoryDeliveryRepository.java @@ -4,6 +4,8 @@ package at.gv.egiz.moazs.repository; import at.gv.egiz.moazs.scheme.MsgResponse; import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType; import com.google.common.cache.Cache; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Repository; @@ -17,6 +19,8 @@ import static java.util.Optional.ofNullable; @Profile("!cluster") public class InMemoryDeliveryRepository implements DeliveryRepository { + private static final Logger log = LoggerFactory.getLogger(InMemoryDeliveryRepository.class); + private final Cache<String, DeliveryRequestType> requestRepository; private final Cache<String, MsgResponse> responseRepository; private final Cache<String, byte[]> binaryResponseRepository; @@ -31,33 +35,38 @@ public class InMemoryDeliveryRepository implements DeliveryRepository { @Override public void store(DeliveryRequestType request) { var key = request.getMetaData().getAppDeliveryID(); + log.trace("Store DeliveryRequest by key={}", key); requestRepository.put(key, request); } @Override public Optional<DeliveryRequestType> retrieveDeliveryRequest(String appDeliveryID) { + log.trace("Retrieve DeliveryRequest by key={}", appDeliveryID); return ofNullable(requestRepository.getIfPresent(appDeliveryID)); } @Override public void store(MsgResponse response) { String key = response.getResponseID(); + log.trace("Store MsgResponse by key={}", key); responseRepository.put(key, response); } @Override public Optional<MsgResponse> retrieveResponse(String responseID) { + log.trace("Retrieve MsgResponse by key={}", responseID); return ofNullable(responseRepository.getIfPresent(responseID)); } @Override - public void store(String id, byte[] data) { - binaryResponseRepository.put(id, data); - + public void store(String responseID, byte[] data) { + log.trace("Store Binary MsgResponse by key={}", responseID); + binaryResponseRepository.put(responseID, data); } @Override public Optional<byte[]> retrieveBinaryResponse(String responseID) { + log.trace("Retrieve Binary MsgResponse by key={}", responseID); return ofNullable(binaryResponseRepository.getIfPresent(responseID)); } diff --git a/src/main/java/at/gv/egiz/moazs/scheme/Marshaller.java b/src/main/java/at/gv/egiz/moazs/scheme/Marshaller.java index 83ace5c..1a86079 100644 --- a/src/main/java/at/gv/egiz/moazs/scheme/Marshaller.java +++ b/src/main/java/at/gv/egiz/moazs/scheme/Marshaller.java @@ -32,6 +32,10 @@ public class Marshaller { } public <T> String marshallXml(final T obj) { + if (obj == null) { + return "null"; + } + StringWriter sw = new StringWriter(); Result result = new StreamResult(sw); jaxbMarshaller.marshal(obj, result); 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 6b6f34a..386a7a6 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() {} private static final at.gv.zustellung.msg.xsd.ObjectFactory MSG_FACTORY = new at.gv.zustellung.msg.xsd.ObjectFactory(); + private static final at.gv.zustellung.app2mzs.xsd.ObjectFactory MZS_FACTORY = new at.gv.zustellung.app2mzs.xsd.ObjectFactory(); public static final String MSG_VERSION = "2.2.0"; public static final String MSG = MSG_FACTORY.createDeliveryRequest(null).getName().getNamespaceURI(); @@ -18,4 +19,8 @@ public class NameSpace { public static final String MSG_DELIVERY_NOTIFICATION = MSG_FACTORY.createDeliveryNotification(null).getName().getLocalPart(); public static final String MSG_APP_DELIVERY_ID = MSG_FACTORY.createAppDeliveryID("").getName().getLocalPart(); + public static final String MZS_DELIVERY_REQUEST = MZS_FACTORY.createDeliveryRequest(null).getName().getLocalPart(); + public static final String MZS_TNVZCLIENT = MZS_FACTORY.createTNVZClient(null).getName().getLocalPart(); + public static final String MZS_MSGCLIENT = MZS_FACTORY.createTNVZClient(null).getName().getLocalPart(); + } 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 6e96a6b..461d8fe 100644 --- a/src/main/java/at/gv/egiz/moazs/scheme/SOAPUtils.java +++ b/src/main/java/at/gv/egiz/moazs/scheme/SOAPUtils.java @@ -3,8 +3,12 @@ package at.gv.egiz.moazs.scheme; import at.gv.egiz.eaaf.core.impl.utils.DOMUtils; import at.gv.egiz.moazs.MoaZSException; import org.apache.cxf.binding.soap.Soap11; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import javax.xml.parsers.ParserConfigurationException; @@ -12,34 +16,72 @@ import javax.xml.transform.TransformerException; import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.LinkedList; +import java.util.List; + +import static at.gv.egiz.moazs.MoaZSException.moaZSException; @Component public class SOAPUtils { + private static final Logger log = LoggerFactory.getLogger(SOAPUtils.class); + private static final String SOAP_BODY_MISSING_ERROR_MSG = "<soap11:Body> is missing."; + private static final String SOAP_BODY_CHILDREN_MISSING_ERROR_MSG = "<soap11:Body> has no child elements."; + private static final String APP_DELIVERY_ID_MISSING_ERROR_MSG = "<msg:AppDeliveryID> is missing."; + private static final String APP_DELIVERY_ID_EMPTY_ERROR_MSG = "<msg:AppDeliveryID> is empty."; + private static final String MULTIPLE_MSG = "Found multiple {} elements. Will choose first element."; + private static final String APP_DELIVERY_ID_FULL_TAG_NAME = "<msg:" + NameSpace.MSG_APP_DELIVERY_ID + ">"; + public Element toDOM(byte[] bytes) throws IOException, SAXException, ParserConfigurationException { var stream = new ByteArrayInputStream(bytes); return DOMUtils.parseXmlNonValidating(stream); } - public byte[] unwrapSoapEnvelope(Element document) { - try { - var body = document.getElementsByTagNameNS(Soap11.SOAP_NAMESPACE, "Body"); - var item = body.item(0).getFirstChild(); + public Node getChildElementOfSoapBody(Element document) throws MoaZSException { + + var bodyList = document.getElementsByTagNameNS(Soap11.SOAP_NAMESPACE, "Body"); + if (bodyList.getLength() == 0) throw moaZSException(SOAP_BODY_MISSING_ERROR_MSG); + if (bodyList.getLength() > 1) log.warn(MULTIPLE_MSG, "<soap11:Body>"); + + var body = bodyList.item(0); + var children = body.getChildNodes(); + var candidates = filterNodeByType(children, Node.ELEMENT_NODE); + + if (candidates.isEmpty()) throw moaZSException(SOAP_BODY_CHILDREN_MISSING_ERROR_MSG); + if (candidates.size() > 1) log.warn(MULTIPLE_MSG, "<soap11:Body> child"); - return DOMUtils.serializeNode(item, true) - .getBytes(StandardCharsets.UTF_8); + return candidates.get(0); + } - } catch (IOException | TransformerException e) { - throw MoaZSException.moaZSException("Error while parsing message. ", e); + private List<Node> filterNodeByType(NodeList children, short nodeType) { + var candidates = new LinkedList<Node>(); + for (int i = 0; i < children.getLength(); i++) { + var child = children.item(i); + if (child.getNodeType() == nodeType) { + candidates.add(child); + } } + + return candidates; + } + + public byte[] toBytes(Node node) throws TransformerException, IOException { + return DOMUtils.serializeNode(node, true).getBytes(StandardCharsets.UTF_8); } public String getAppDeliveryIDFrom(Element document) { - var elements = document.getElementsByTagNameNS(NameSpace.MSG, NameSpace.MSG_APP_DELIVERY_ID); + var elementList = document.getElementsByTagNameNS(NameSpace.MSG, NameSpace.MSG_APP_DELIVERY_ID); + + if (elementList.getLength() == 0) throw moaZSException(APP_DELIVERY_ID_MISSING_ERROR_MSG); + if (elementList.getLength() > 1) log.warn(MULTIPLE_MSG, APP_DELIVERY_ID_FULL_TAG_NAME); - var appDeliveryIdElement = elements.item(0).getFirstChild(); + var children = elementList.item(0).getChildNodes(); + var candidates = filterNodeByType(children, Node.TEXT_NODE); + if (candidates.isEmpty() || candidates.get(0).getNodeValue().isBlank()) + throw moaZSException(APP_DELIVERY_ID_EMPTY_ERROR_MSG); + if (candidates.size() > 1) log.warn(MULTIPLE_MSG, APP_DELIVERY_ID_FULL_TAG_NAME); - return appDeliveryIdElement.getNodeValue(); + return candidates.get(0).getNodeValue(); } } diff --git a/src/main/java/at/gv/egiz/moazs/util/EndpointFactory.java b/src/main/java/at/gv/egiz/moazs/util/EndpointFactory.java index 24321e1..9d31596 100644 --- a/src/main/java/at/gv/egiz/moazs/util/EndpointFactory.java +++ b/src/main/java/at/gv/egiz/moazs/util/EndpointFactory.java @@ -20,13 +20,13 @@ public class EndpointFactory { this.bus = bus; } - public Endpoint create(Object implementor, Service service) { - return create(implementor, service, null); + public Endpoint create(Object implementor, Service service, String route) { + return create(implementor, service, route, null); } - public Endpoint create(Object implementor, Service service, Interceptor<Message> interceptor) { + public Endpoint create(Object implementor, Service service, String route, Interceptor<Message> interceptor) { EndpointImpl endpoint = new EndpointImpl(bus, implementor); - endpoint.setAddress("/"); + endpoint.setAddress(route); endpoint.setServiceName(service.getServiceName()); endpoint.setWsdlLocation(service.getWSDLDocumentLocation().toString()); endpoint.publish(); diff --git a/src/main/java/at/gv/egiz/moazs/util/StoreSOAPBodyBinaryInRepositoryInterceptor.java b/src/main/java/at/gv/egiz/moazs/util/StoreSOAPBodyBinaryInRepositoryInterceptor.java index 88ab7e0..d4aa75a 100644 --- a/src/main/java/at/gv/egiz/moazs/util/StoreSOAPBodyBinaryInRepositoryInterceptor.java +++ b/src/main/java/at/gv/egiz/moazs/util/StoreSOAPBodyBinaryInRepositoryInterceptor.java @@ -13,6 +13,7 @@ import org.w3c.dom.Element; import org.xml.sax.SAXException; import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.Map; @@ -46,25 +47,22 @@ public class StoreSOAPBodyBinaryInRepositoryInterceptor extends AbstractPhaseInt try { byte[] content = messageUtils.copyContent(message); - if(log.isTraceEnabled()) { - log.trace("Interceptor received this SOAP message: {}. ", new String(content, StandardCharsets.UTF_8)); - } - if (content.length <= 0) { return; } Element document = soapUtils.toDOM(content); - byte[] response = soapUtils.unwrapSoapEnvelope(document); - String appDeliveryID = soapUtils.getAppDeliveryIDFrom(document); - String rootTag = document.getTagName(); + var rootTagNode = soapUtils.getChildElementOfSoapBody(document); + var rootTagLocalName = rootTagNode.getLocalName(); - if (!idGenerators.containsKey(rootTag)) { - log.trace("Will not store message of type {}. ", rootTag); + if (!idGenerators.containsKey(rootTagLocalName)) { + log.trace("Child element {} of <soap:Body> is unknown. Will not store message.", rootTagLocalName); return; } - var id = idGenerators.get(rootTag).apply(appDeliveryID); + String appDeliveryID = soapUtils.getAppDeliveryIDFrom(document); + var id = idGenerators.get(rootTagLocalName).apply(appDeliveryID); + byte[] response = soapUtils.toBytes(rootTagNode); repository.store(id, response); if(log.isTraceEnabled()) { @@ -72,7 +70,7 @@ public class StoreSOAPBodyBinaryInRepositoryInterceptor extends AbstractPhaseInt appDeliveryID, new String(response, StandardCharsets.UTF_8)); } - } catch (ParserConfigurationException | SAXException | IOException | NullPointerException e) { + } catch (ParserConfigurationException | SAXException | IOException | NullPointerException | TransformerException e) { throw moaZSException("Could not extract signed data from message.", e); } } diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index a7b7524..ce4d892 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -51,7 +51,9 @@ delivery-request-configuration-profiles: # addressable. Requires setting up the tvnz-client. perform-query-person-request: false - # Optional (Mandatory if perform-query-person-request is true) + # TODO: Move tnvz-client into perform-query-person-request to make relationship clearer (also + # TODO: add active) + # Mandatory (if perform-query-person-request is true) # Parameters for the connection to tvnz. Specify url, # connection-timeout, receive-timeout and ssl here. See msg-client # for an exhaustive description of all parameters. @@ -166,12 +168,12 @@ moa.spss: # Select, which trust-profile moa spss uses to verify a signature. default-trustprofile: test-trustprofile -# Optional -# Redis Setup (Cluster Mode) spring: + # Redis Setup (Cluster Mode) redis: host: 172.17.0.2 port: 6379 + main.allow-bean-definition-overriding: true # Mandatory repository: diff --git a/src/main/resources/mzs/app2mzs.wsdl b/src/main/resources/mzs/app2mzs.wsdl index b3f0f4b..8c0547b 100644 --- a/src/main/resources/mzs/app2mzs.wsdl +++ b/src/main/resources/mzs/app2mzs.wsdl @@ -45,7 +45,7 @@ </binding> <service name="app2mzs"> <port binding="tns:app2mzsBinding" name="app2mzsPort"> - <soap:address location="http://localhost:8080/moazs/services/DeliveryRequest"/> + <soap:address location="http://localhost:8080/moazs/services/mzs/DeliveryRequest"/> </port> </service> </definitions> diff --git a/src/main/resources/mzs/app2mzs.xsd b/src/main/resources/mzs/app2mzs.xsd index 7e70092..d19ff3b 100644 --- a/src/main/resources/mzs/app2mzs.xsd +++ b/src/main/resources/mzs/app2mzs.xsd @@ -56,7 +56,6 @@ </xs:sequence> </xs:complexType> </xs:element> - <xs:element ref="TnvzMetaData" minOccurs="0"/> <xs:element ref="msg:MetaData" /> <xs:element name="Payload" maxOccurs="unbounded"> <xs:complexType> @@ -80,21 +79,10 @@ <xs:element ref="Config" minOccurs="0"/> </xs:sequence> </xs:complexType> - <xs:element name="TnvzMetaData" type="TnvzMetaDataType" /> - <xs:complexType name="TnvzMetaDataType"> - <xs:sequence> - <xs:element ref="msg:Origin" /> - <xs:choice> - <xs:element ref="msg:DeliveryQuality"/> - <xs:element ref="msg:PrivateMessageQuality"/> - </xs:choice> - <xs:element ref="msg:IgnorePostRedirectionOrder" minOccurs="0"/> - </xs:sequence> - </xs:complexType> <xs:element name="Config" type="ConfigType"/> <xs:complexType name="ConfigType"> <xs:sequence> - <xs:element name="ProfileID" type="xs:token" minOccurs="0"></xs:element> + <xs:element name="ProfileID" type="xs:token" minOccurs="0" /> <xs:element name="ServiceTimeout" type="xs:nonNegativeInteger" minOccurs="0"/> <xs:element name="PerformQueryPersonRequest" type="xs:boolean" minOccurs="0" /> <xs:element ref="MSGClient" minOccurs="0" /> diff --git a/src/test/java/at/gv/egiz/moazs/ConfigProfileGeneratorTest.java b/src/test/java/at/gv/egiz/moazs/ConfigProfileGeneratorTest.java index f408c3b..c056b2c 100644 --- a/src/test/java/at/gv/egiz/moazs/ConfigProfileGeneratorTest.java +++ b/src/test/java/at/gv/egiz/moazs/ConfigProfileGeneratorTest.java @@ -5,10 +5,12 @@ import at.gv.egiz.moazs.preprocess.*; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; import java.util.Map; +import static at.gv.egiz.moazs.MoaZSException.moaZSException; import static at.gv.egiz.moazs.preprocess.ConfigProfileGenerator.configProfileGeneratorBuilder; import static at.gv.zustellung.app2mzs.xsd.ConfigType.configTypeBuilder; import static org.mockito.ArgumentMatchers.any; @@ -91,7 +93,7 @@ public class ConfigProfileGeneratorTest { public void cancelAtIncompleteDefaultProfile() { var propMap = Map.of(PREFIX + "." + DEFAULT + ".property-a", "value-a"); var generator = setupMocksAndBuilder(propMap).build(); - when(validator.isConfigProfileComplete(any())).thenReturn(false); + doThrow(moaZSException("Not Complete.")).when(validator).isConfigProfileComplete(any()); generator.generate(); } @@ -100,7 +102,7 @@ public class ConfigProfileGeneratorTest { public void continueAtIncompleteDefaultWhenVerificationDisabled() { var propMap = Map.of(PREFIX + "." + DEFAULT + ".property-a", "value-a"); - when(validator.isConfigProfileComplete(any())).thenReturn(false); + doThrow(moaZSException("Not Complete.")).when(validator).isConfigProfileComplete(any()); var generator = setupMocksAndBuilder(propMap) .withVerifyCompletenessOfDefaultConfiguration(false) @@ -117,7 +119,6 @@ public class ConfigProfileGeneratorTest { when(properties.getProperty(any())).thenAnswer(i -> propMap.get(i.getArgument(0))); when(util.merge(any(), any())).thenAnswer(i -> i.getArgument(0)); when(util.convert(any())).thenReturn(configTypeBuilder().build()); - when(validator.isConfigProfileComplete(any())).thenReturn(true); return configProfileGeneratorBuilder() .withProperties(properties) diff --git a/src/test/java/at/gv/egiz/moazs/DeliveryRequestAugmenterTest.java b/src/test/java/at/gv/egiz/moazs/DeliveryRequestAugmenterTest.java index 12f1dea..2e9dd80 100644 --- a/src/test/java/at/gv/egiz/moazs/DeliveryRequestAugmenterTest.java +++ b/src/test/java/at/gv/egiz/moazs/DeliveryRequestAugmenterTest.java @@ -3,6 +3,7 @@ package at.gv.egiz.moazs; import at.gv.egiz.moazs.preprocess.MzsDeliveryRequestValidator; import at.gv.egiz.moazs.preprocess.ConfigUtil; import at.gv.egiz.moazs.preprocess.DeliveryRequestAugmenter; +import at.gv.egiz.moazs.scheme.Marshaller; import at.gv.zustellung.app2mzs.xsd.ConfigType; import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType; import org.junit.Before; @@ -31,10 +32,10 @@ public class DeliveryRequestAugmenterTest { @Mock private MzsDeliveryRequestValidator validator; + private Marshaller mzsMarshaller = new Marshaller(true); + @Before public void setupMock() { - when(validator.isConfigProfileComplete(any())).thenReturn(true); - when(validator.isTnvzComplete(any())).thenReturn(true); when(configUtil.merge(any(), any())).thenCallRealMethod(); } @@ -109,11 +110,11 @@ public class DeliveryRequestAugmenterTest { } private DeliveryRequestAugmenter createAugmenter(ConfigType fallback) { - return new DeliveryRequestAugmenter(Map.of("default", fallback), configUtil, validator); + return new DeliveryRequestAugmenter(Map.of("default", fallback), configUtil, validator, mzsMarshaller); } private DeliveryRequestAugmenter createAugmenter(Map<String, ConfigType> profiles) { - return new DeliveryRequestAugmenter(profiles, configUtil, validator); + return new DeliveryRequestAugmenter(profiles, configUtil, validator, mzsMarshaller); } private ConfigType createConfig(String url, Boolean performTnvz) { diff --git a/src/test/java/at/gv/egiz/moazs/ITEndToEndTest.java b/src/test/java/at/gv/egiz/moazs/ITEndToEndTest.java new file mode 100644 index 0000000..fd2e629 --- /dev/null +++ b/src/test/java/at/gv/egiz/moazs/ITEndToEndTest.java @@ -0,0 +1,259 @@ +package at.gv.egiz.moazs; + +import at.gv.egiz.moazs.client.ClientFactory; +import at.gv.egiz.moazs.repository.DeliveryRepository; +import at.gv.egiz.moazs.scheme.NotificationResponse; +import at.gv.egiz.moazs.scheme.RequestStatusResponse; +import at.gv.zustellung.app2mzs.xsd.DeliveryNotificationACKType; +import at.gv.zustellung.app2mzs.xsd.DeliveryResponseType; +import at.gv.zustellung.app2mzs.xsd.Mzs2AppPortType; +import at.gv.zustellung.msg.xsd.App2ZusePort; +import at.gv.zustellung.msg.xsd.DeliveryRequestStatusType; +import at.gv.zustellung.msg.xsd.DeliveryRequestType; +import at.gv.zustellung.tnvz.xsd.TNVZServicePort; +import org.apache.commons.io.FileUtils; +import org.junit.Before; +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.TestConfiguration; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.test.context.junit4.SpringRunner; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.nio.file.Paths; +import java.util.Collection; +import java.util.List; +import java.util.function.Consumer; + +import static at.gv.zustellung.app2mzs.xsd.DeliveryNotificationACKType.deliveryNotificationACKTypeBuilder; +import static at.gv.zustellung.app2mzs.xsd.persondata.IdentificationType.Value.valueBuilder; +import static at.gv.zustellung.app2mzs.xsd.persondata.IdentificationType.identificationTypeBuilder; +import static at.gv.zustellung.msg.xsd.DeliveryAnswerType.deliveryAnswerTypeBuilder; +import static at.gv.zustellung.msg.xsd.DeliveryRequestStatusType.deliveryRequestStatusTypeBuilder; +import static java.net.http.HttpResponse.BodyHandlers.ofString; +import static org.apache.commons.io.FileUtils.readFileToString; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.*; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public class ITEndToEndTest { + + private final static Logger log = LoggerFactory.getLogger(ITEndToEndTest.class); + public static final String GZ_WATERMARK = "my-secret-watermark-string"; + public static final String DELIVERY_SYSTEM = "http://localhost/url/to/msg/service"; + + @LocalServerPort + public int port; + private String mzsFrontendURL; + + private final String basePath = "src/test/resources/at/gv/egiz/moazs/ITEndToEndTest/"; + private static Mzs2AppPortType APP; + + @Before + public void setupFrontendURL() { + this.mzsFrontendURL = "http://localhost:" + port + "/services"; + } + + @TestConfiguration + public static class MockClientsAndSignatureVerificationConfig { + + + @Autowired + private DeliveryRepository repository; + + @Bean + @Primary + public Consumer<byte[]> signatureVerifier() { + return bytes -> {}; + } + + @Bean + @Primary + public ClientFactory mockClientFactory() { + var factory = mock(ClientFactory.class); + var tnvz = mockTnvz(); + var msg = mockMsg(); + APP = mockApp(); + when(factory.create(any(), same(TNVZServicePort.class))).thenReturn(tnvz); + when(factory.create(any(), same(App2ZusePort.class))).thenReturn(msg); + when(factory.create(any(), same(Mzs2AppPortType.class))).thenReturn(APP); + return factory; + } + + private Mzs2AppPortType mockApp() { + var app = mock(Mzs2AppPortType.class); + when(app.forwardStatus(any())).thenAnswer(i -> ack(i.getArgument(0))); + when(app.forwardNotification(any())).thenAnswer(i -> ack(i.getArgument(0))); + return app; + } + + private DeliveryNotificationACKType ack(DeliveryResponseType response) { + return deliveryNotificationACKTypeBuilder() + .withAppDeliveryID(response.getSuccess().getAppDeliveryID()) + .build(); + } + + private TNVZServicePort mockTnvz() { + var tnvz = mock(TNVZServicePort.class); + var value = valueBuilder().withId("id").withValue("value").build(); + var receiverId = identificationTypeBuilder() + .withValue(value).withId("id").withType("type").build(); + var tnvzHelperTest = new TnvzHelperTest(); + tnvzHelperTest.setup(); + var tnvzSuccess = tnvzHelperTest.tnvzSuccess(List.of("*/*"), receiverId); + + when(tnvz.queryPerson(any())).thenReturn(tnvzSuccess); + return tnvz; + } + + private App2ZusePort mockMsg() { + var msg = mock(App2ZusePort.class); + when(msg.delivery(any())).thenAnswer(i-> partialSuccess(i.getArgument(0))); + return msg; + } + + private DeliveryRequestStatusType partialSuccess(DeliveryRequestType request) { + + var appDeliveryID = request.getMetaData().getAppDeliveryID(); + var zsDeliveryID = "ZSDID-" + appDeliveryID; + var responseID = RequestStatusResponse.getResponseID(appDeliveryID); + var answer = deliveryAnswerTypeBuilder() + .withDeliverySystem(DELIVERY_SYSTEM) + .withAppDeliveryID(appDeliveryID) + .withZSDeliveryID(zsDeliveryID) + .withGZ(GZ_WATERMARK) + .build(); + repository.store(responseID, new byte[]{}); + return deliveryRequestStatusTypeBuilder() + .withPartialSuccess(answer) + .build(); + } + + } + + @Test + public void testHappyPath() throws IOException, InterruptedException { + + //prepare + var appDeliveryID = "delivery-request-id"; + var zsDeliveryID = "ZSDID-" + appDeliveryID; + var timestamp = ITMzsServiceTest.genTimeStamp().toXMLFormat(); + var saveSinkFolder = "target/tmp/ITEndToEndTestOut"; + delete(saveSinkFolder); + + //app sends delivery request to moazs and receives partial success + var partialSuccess = sendMzsDeliveryRequest("mzs-delivery-request.xml"); + assertThat(partialSuccess.statusCode()).isEqualTo(200); + assertThat(partialSuccess.body()).contains(List.of(GZ_WATERMARK, "PartialSuccess")); + + // zusemsg sends async success + var statusResponseID = RequestStatusResponse.getResponseID(appDeliveryID); + var msgStatus = formatFile("msg-delivery-request-status.xml", new String[]{ + DELIVERY_SYSTEM, zsDeliveryID, appDeliveryID, GZ_WATERMARK, timestamp + }); + sendMsgResponse(msgStatus); + Thread.sleep(100); + verify(APP).forwardStatus(any()); + assertStatusWrittenToFileSystem(saveSinkFolder, statusResponseID); + assertStatusWasLogged(); + + // zusemsg sends async notification + var notificationResponseID = NotificationResponse.getResponseID(appDeliveryID); + var notification = formatFile("msg-delivery-notification.xml", new String[]{ + DELIVERY_SYSTEM, zsDeliveryID, appDeliveryID, GZ_WATERMARK, timestamp, timestamp + }); + sendMsgResponse(notification); + Thread.sleep(100); + verify(APP).forwardNotification(any()); + assertStatusWrittenToFileSystem(saveSinkFolder, notificationResponseID); + assertStatusWasLogged(); + + } + + private void assertStatusWrittenToFileSystem(String folder, String pathSubString) { + var rootFolder = new File(folder); + Collection<File> files = FileUtils.listFiles(rootFolder, null, true); + + assertThat(rootFolder.exists()).isTrue(); + assertThat(rootFolder.isDirectory()).isTrue(); + assertThat(files).isNotEmpty(); + + long count = files.stream() + .map(File::getAbsolutePath) + .filter(path -> path.contains(pathSubString)) + .count(); + + assertThat(count).isEqualTo(2); + } + + private String readFile(File file) { + try { + return readFileToString(file, StandardCharsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private void delete(String file) { + try { + FileUtils.deleteDirectory(new File(file)); + } catch (IOException e) { + log.warn("Could not delete {}", file); + } + } + + private void assertStatusWasLogged() { + //todo + } + + + private String formatFile(String templateFile, String... values) throws IOException { + var path = basePath + templateFile; + var templateString = FileUtils.readFileToString(new File(path), StandardCharsets.UTF_8); + return String.format(templateString, values); + } + + private HttpResponse<String> sendMsgResponse(String bodyString) throws IOException, InterruptedException { + + var body = HttpRequest.BodyPublishers.ofString(bodyString); + var client = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).build(); + var request = HttpRequest.newBuilder() + .uri(URI.create(mzsFrontendURL + "/msg/")) + .header("Content-Type", "text/xml;charset=UTF-8") + .header("SOAPAction", "\"\"") + .POST(body) + .build(); + + return client.send(request, ofString()); + + } + + private HttpResponse<String> sendMzsDeliveryRequest(String fileName) throws IOException, InterruptedException { + + var path = basePath + fileName; + var client = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).build(); + var request = HttpRequest.newBuilder() + .uri(URI.create(mzsFrontendURL + "/mzs/")) + .header("Content-Type", "text/xml;charset=UTF-8") + .header("SOAPAction", "\"\"") + .POST(HttpRequest.BodyPublishers.ofFile(Paths.get(path))) + .build(); + + return client.send(request, ofString()); + + } + +} diff --git a/src/test/java/at/gv/egiz/moazs/ITMzsServiceTest.java b/src/test/java/at/gv/egiz/moazs/ITMzsServiceTest.java index e9b4f70..3cf0362 100644 --- a/src/test/java/at/gv/egiz/moazs/ITMzsServiceTest.java +++ b/src/test/java/at/gv/egiz/moazs/ITMzsServiceTest.java @@ -2,12 +2,14 @@ package at.gv.egiz.moazs; import at.gv.egiz.moazs.repository.DeliveryRepository; import at.gv.egiz.moazs.scheme.RequestStatusResponse; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.boot.web.server.LocalServerPort; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; import org.springframework.test.context.junit4.SpringRunner; @@ -27,17 +29,24 @@ import java.util.function.Consumer; import static at.gv.zustellung.msg.xsd.DeliveryRequestStatusType.Success.successBuilder; import static at.gv.zustellung.msg.xsd.DeliveryRequestStatusType.deliveryRequestStatusTypeBuilder; import static java.net.http.HttpClient.Version; -import static org.junit.Assert.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; @RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT) +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) public class ITMzsServiceTest { - private final String serviceUri = "http://localhost:8080/services/DeliveryRequest"; - private final String basePath = "src/test/resources/at/gv/egiz/moazs/ITMzsServiceTest/"; + @LocalServerPort + public int port; + private String serviceUri; + + @Before + public void setupServiceURI() { + this.serviceUri = "http://localhost:" + port + "/services/mzs"; + } + @TestConfiguration public static class TestConfig { @@ -64,50 +73,44 @@ public class ITMzsServiceTest { }; } - private XMLGregorianCalendar genTimeStamp() { - try { - return DatatypeFactory.newInstance().newXMLGregorianCalendar(new GregorianCalendar()); - } catch (DatatypeConfigurationException e) { - throw new RuntimeException("ups"); - } - } } @Test public void acceptValidDeliveryRequest() throws IOException, InterruptedException { var response = sendDeliveryRequestFile("validDeliveryRequest.soap"); - assertEquals(200, response.statusCode()); + assertThat(response.statusCode()).isEqualTo(200); + assertThat(response.body()).contains("valid-delivery-request-id"); } @Test public void rejectRequestWithoutSender() throws IOException, InterruptedException { var response = sendDeliveryRequestFile("missingSender.soap"); - assertEquals(500, response.statusCode()); + assertThat(response.statusCode()).isEqualTo(500); } @Test public void rejectBothProfileAndCorporateBody() throws IOException, InterruptedException { var response = sendDeliveryRequestFile("profileAndCorporateBody.soap"); - assertEquals(500, response.statusCode()); + assertThat(response.statusCode()).isEqualTo(500); } @Test public void rejectFormallyIncorrectDeliveryRequest() throws IOException, InterruptedException { var response = sendDeliveryRequestFile("formallyIncorrectDeliveryRequest.soap"); - assertEquals(500, response.statusCode()); + assertThat(response.statusCode()).isEqualTo(500); } @Test public void rejectRequestWithoutAppDeliveryID() throws IOException, InterruptedException { var response = sendDeliveryRequestFile("missingAppDeliveryId.soap"); - assertEquals(500, response.statusCode()); + assertThat(response.statusCode()).isEqualTo(500); } @Test public void rejectRequestWithoutMetaData() throws IOException, InterruptedException { var response = sendDeliveryRequestFile("missingMetaData.soap"); - assertEquals(500, response.statusCode()); + assertThat(response.statusCode()).isEqualTo(500); } private HttpResponse<String> sendDeliveryRequestFile(String fileName) throws IOException, InterruptedException { @@ -125,4 +128,13 @@ public class ITMzsServiceTest { } + public static XMLGregorianCalendar genTimeStamp() { + try { + return DatatypeFactory.newInstance().newXMLGregorianCalendar(new GregorianCalendar()); + } catch (DatatypeConfigurationException e) { + throw new RuntimeException("ups"); + } + + } + } diff --git a/src/test/java/at/gv/egiz/moazs/SOAPUtilsTest.java b/src/test/java/at/gv/egiz/moazs/SOAPUtilsTest.java index 31aa197..ff0060e 100644 --- a/src/test/java/at/gv/egiz/moazs/SOAPUtilsTest.java +++ b/src/test/java/at/gv/egiz/moazs/SOAPUtilsTest.java @@ -4,10 +4,8 @@ import at.gv.egiz.moazs.scheme.SOAPUtils; import org.junit.Before; import org.junit.Test; import org.w3c.dom.Element; -import org.xml.sax.SAXException; +import org.w3c.dom.Node; -import javax.xml.parsers.ParserConfigurationException; -import java.io.IOException; import java.nio.charset.StandardCharsets; import static org.assertj.core.api.Assertions.assertThat; @@ -25,39 +23,152 @@ public class SOAPUtilsTest { "est-id</ZSDeliveryID><AppDeliveryID>valid-delivery-request-id</AppDeliveryID><GZ>12345</GZ>" + "</PartialSuccess></DeliveryResponse></soap:Body></soap:Envelope>"; + + public static final String FORMATTED_MESSAGE = + "<soapenv:Envelope\n" + + " xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"\n" + + " xmlns:msg=\"http://reference.e-government.gv.at/namespace/zustellung/msg/phase2/20181206#\">\n" + + " <soapenv:Body>\n" + + " <msg:DeliveryNotification>\n" + + " <msg:AppDeliveryID>formatted-adid</msg:AppDeliveryID>\n" + + " </msg:DeliveryNotification>\n" + + " </soapenv:Body>\n" + + "</soapenv:Envelope>\n"; + + public static final String CLUTTERED_MESSAGE = + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + + "<soapenv:Envelope " + + " xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"\n " + + " xmlns:msg=\"http://reference.e-government.gv.at/namespace/zustellung/msg/phase2/20181206#\">\n" + + " <soapenv:Body unexpected-attribute=\"unexpectedvalue\"> \n" + + " <msg:DeliveryNotification>\n" + + " <msg:AppDeliveryID attribute=\"some-value\"><element-that-got-lost />cluttered-adid</msg:AppDeliveryID>\n" + + " </msg:DeliveryNotification>\n" + + " </soapenv:Body>\n" + + "</soapenv:Envelope>\n"; + + private static final String MISSING_BODY_MESSAGE = + "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><NotABodyTag></NotABodyTag></soap:Envelope>"; + + private static final String EMPTY_BODY_MESSAGE = + "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body> </soap:Body></soap:Envelope>"; + + public static final String EMPTY_APP_DELIVERY_ID_MESSAGE = + "<soapenv:Envelope\n" + + " xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"\n" + + " xmlns:msg=\"http://reference.e-government.gv.at/namespace/zustellung/msg/phase2/20181206#\">\n" + + " <soapenv:Body>\n" + + " <msg:DeliveryNotification>\n" + + " <msg:AppDeliveryID />\n" + + " </msg:DeliveryNotification>\n" + + " </soapenv:Body>\n" + + "</soapenv:Envelope>\n"; + + public static final String BLANK_APP_DELIVERY_ID_MESSAGE = + "<soapenv:Envelope\n" + + " xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"\n" + + " xmlns:msg=\"http://reference.e-government.gv.at/namespace/zustellung/msg/phase2/20181206#\">\n" + + " <soapenv:Body>\n" + + " <msg:DeliveryNotification>\n" + + " <msg:AppDeliveryID> </msg:AppDeliveryID>\n" + + " </msg:DeliveryNotification>\n" + + " </soapenv:Body>\n" + + "</soapenv:Envelope>\n"; + @Before public void setup() { utils = new SOAPUtils(); } @Test - public void toDom() throws ParserConfigurationException, SAXException, IOException { - byte[] bytes = SOAP_MESSAGE.getBytes(StandardCharsets.UTF_8); + public void canParseSoapMessage() throws Exception { + parseAndCheckLocalName(SOAP_MESSAGE); + } + + @Test + public void canParseFormattedSoapMessage() throws Exception { + parseAndCheckLocalName(FORMATTED_MESSAGE); + } + + @Test + public void canParseClutteredSoapMessage() throws Exception { + parseAndCheckLocalName(CLUTTERED_MESSAGE); + } + private void parseAndCheckLocalName(String text) throws Exception { + byte[] bytes = text.getBytes(StandardCharsets.UTF_8); Element root = utils.toDOM(bytes); + assertThat(root.getLocalName()).isEqualTo("Envelope"); + } + + @Test + public void canUnwrapSoapMessage() throws Exception { + getFirstChildAndCheckLocalName(SOAP_MESSAGE, "DeliveryResponse"); + } - assertThat(root.getTagName()).isEqualTo("soap:Envelope"); + @Test + public void canUnwrapFormattedSoapMessage() throws Exception { + getFirstChildAndCheckLocalName(FORMATTED_MESSAGE, "DeliveryNotification"); } @Test - public void unwrapSoapEnvelope() throws ParserConfigurationException, SAXException, IOException { - byte[] bytes = SOAP_MESSAGE.getBytes(StandardCharsets.UTF_8); + public void canUnwrapClutteredSoapMessage() throws Exception { + getFirstChildAndCheckLocalName(CLUTTERED_MESSAGE, "DeliveryNotification"); + } + + @Test(expected=MoaZSException.class) + public void failUnwrapMissingBody() throws Exception { + getFirstChildAndCheckLocalName(MISSING_BODY_MESSAGE, ""); + } + + @Test(expected=MoaZSException.class) + public void failUnwrapEmptyBody() throws Exception { + getFirstChildAndCheckLocalName(EMPTY_BODY_MESSAGE, ""); + } + + private void getFirstChildAndCheckLocalName(String message, String expectedLocalNameOfChild) throws Exception { + byte[] bytes = message.getBytes(StandardCharsets.UTF_8); Element soapRoot = utils.toDOM(bytes); + Node child = utils.getChildElementOfSoapBody(soapRoot); + var actualLocalName = child.getLocalName(); + assertThat(actualLocalName).isEqualTo(expectedLocalNameOfChild); + } - byte[] unwrappedMessage = utils.unwrapSoapEnvelope(soapRoot); + @Test + public void getAppDeliveryIDFromSoapMessage() throws Exception { + getAppDeliveryIDAndCheck(SOAP_MESSAGE, "valid-delivery-request-id"); + } - Element deliveryResponseRoot = utils.toDOM(unwrappedMessage); - assertThat(deliveryResponseRoot.getTagName()).isEqualTo("DeliveryResponse"); + @Test + public void getAppDeliveryIDFromFormattedMessage() throws Exception { + getAppDeliveryIDAndCheck(FORMATTED_MESSAGE, "formatted-adid"); } @Test - public void getAppDeliveryID() throws ParserConfigurationException, SAXException, IOException { - byte[] bytes = SOAP_MESSAGE.getBytes(StandardCharsets.UTF_8); - Element soapRoot = utils.toDOM(bytes); + public void getAppDeliveryIDFromClutteredMessage() throws Exception { + getAppDeliveryIDAndCheck(CLUTTERED_MESSAGE, "cluttered-adid"); + } + + @Test(expected = MoaZSException.class) + public void failToRetrieveAppDeliveryIDWhenBodyIsMissing() throws Exception { + getAppDeliveryIDAndCheck(MISSING_BODY_MESSAGE, ""); + } - String appDeliveryID = utils.getAppDeliveryIDFrom(soapRoot); + @Test(expected = MoaZSException.class) + public void failToRetrieveEmptyAppDeliveryID() throws Exception { + getAppDeliveryIDAndCheck(EMPTY_APP_DELIVERY_ID_MESSAGE, ""); + } + + @Test(expected = MoaZSException.class) + public void failToRetrieveBlankAppDeliveryID() throws Exception { + getAppDeliveryIDAndCheck(BLANK_APP_DELIVERY_ID_MESSAGE, ""); + } - assertThat(appDeliveryID).isEqualTo("valid-delivery-request-id"); + private void getAppDeliveryIDAndCheck(String message, String expectedValue) throws Exception { + byte[] bytes = message.getBytes(StandardCharsets.UTF_8); + Element soapRoot = utils.toDOM(bytes); + String actualAppDeliveryID = utils.getAppDeliveryIDFrom(soapRoot); + assertThat(actualAppDeliveryID).isEqualTo(expectedValue); } } diff --git a/src/test/java/at/gv/egiz/moazs/TnvzHelperTest.java b/src/test/java/at/gv/egiz/moazs/TnvzHelperTest.java index 020e270..550f089 100644 --- a/src/test/java/at/gv/egiz/moazs/TnvzHelperTest.java +++ b/src/test/java/at/gv/egiz/moazs/TnvzHelperTest.java @@ -5,6 +5,8 @@ import at.gv.egiz.moazs.scheme.Mzs2MsgConverter; import at.gv.egiz.moazs.client.TnvzHelper; import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType; import at.gv.zustellung.app2mzs.xsd.persondata.IdentificationType; +import at.gv.zustellung.msg.xsd.MetaData; +import at.gv.zustellung.msg.xsd.SystemComponentType; import at.gv.zustellung.tnvz.xsd.MimeTypeList; import at.gv.zustellung.tnvz.xsd.QueryPersonResponse; import at.gv.zustellung.tnvz.xsd.TNVZServicePort; @@ -20,11 +22,12 @@ import static at.gv.zustellung.app2mzs.xsd.DeliveryRequestType.Payload.payloadBu import static at.gv.zustellung.app2mzs.xsd.DeliveryRequestType.Receiver.receiverBuilder; import static at.gv.zustellung.app2mzs.xsd.DeliveryRequestType.Sender.senderBuilder; import static at.gv.zustellung.app2mzs.xsd.DeliveryRequestType.deliveryRequestTypeBuilder; -import static at.gv.zustellung.app2mzs.xsd.TnvzMetaDataType.tnvzMetaDataTypeBuilder; import static at.gv.zustellung.app2mzs.xsd.persondata.CorporateBodyType.corporateBodyTypeBuilder; import static at.gv.zustellung.app2mzs.xsd.persondata.IdentificationType.Value.valueBuilder; import static at.gv.zustellung.app2mzs.xsd.persondata.IdentificationType.identificationTypeBuilder; import static at.gv.zustellung.msg.xsd.ErrorInfoType.errorInfoTypeBuilder; +import static at.gv.zustellung.msg.xsd.MetaData.metaDataBuilder; +import static at.gv.zustellung.msg.xsd.SystemComponentType.systemComponentTypeBuilder; 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; @@ -119,14 +122,19 @@ public class TnvzHelperTest { .withIdentification(receiverId) .build(); - var metadata = tnvzMetaDataTypeBuilder() + var origin = systemComponentTypeBuilder() + .withParticipantID("ID") + .build(); + + var metadata = metaDataBuilder() + .withOrigin(origin) .build(); return deliveryRequestTypeBuilder() .withSender(sender) .withReceiver(receiver) - .withTnvzMetaData(metadata) .withPayload(payload(mzsMimeTypes)) + .withMetaData(metadata) .build(); } @@ -148,7 +156,7 @@ public class TnvzHelperTest { .collect(toList()); } - private QueryPersonResponse tnvzSuccess(List<String> mimeTypes, IdentificationType receiverId) { + public QueryPersonResponse tnvzSuccess(List<String> mimeTypes, IdentificationType receiverId) { var success = personResultSuccessTypeBuilder() .withMimeTypeList(setupMimeTypeList(mimeTypes)) diff --git a/src/test/resources/at/gv/egiz/moazs/ITEndToEndTest/msg-delivery-notification.xml b/src/test/resources/at/gv/egiz/moazs/ITEndToEndTest/msg-delivery-notification.xml new file mode 100644 index 0000000..3a90d36 --- /dev/null +++ b/src/test/resources/at/gv/egiz/moazs/ITEndToEndTest/msg-delivery-notification.xml @@ -0,0 +1,100 @@ +<?xml version="1.0" encoding="UTF-8"?> +<soapenv:Envelope + xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" + xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" + xmlns:p="http://reference.e-government.gv.at/namespace/persondata/phase2/20181206#" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:msg="http://reference.e-government.gv.at/namespace/zustellung/msg/phase2/20181206#"> + <soapenv:Body> + <msg:DeliveryNotification> + <msg:DeliverySystem>%s</msg:DeliverySystem> + <msg:ZSDeliveryID>%s</msg:ZSDeliveryID> + <msg:AppDeliveryID>%s</msg:AppDeliveryID> + <msg:GZ>%s</msg:GZ> + <msg:SenderDetails> + <p:Identification> + <p:Value>12345</p:Value> + <p:Type>678910</p:Type> + </p:Identification> + <p:CorporateBody> + <p:FullName>Bundesministerium für Testzwecke</p:FullName> + </p:CorporateBody> + </msg:SenderDetails> + <msg:ReceiverDetails> + <p:Identification> + <p:Value>123</p:Value> + <p:Type>654654</p:Type> + </p:Identification> + <p:PhysicalPerson> + <p:Name> + <p:GivenName>Maxi</p:GivenName> + <p:FamilyName>Mustermann1</p:FamilyName> + </p:Name> + <p:DateOfBirth>1984-01-24</p:DateOfBirth> + </p:PhysicalPerson> + </msg:ReceiverDetails> + <msg:RelayedViaERV>false</msg:RelayedViaERV> + <msg:Timestamp>%s</msg:Timestamp> + <msg:Answer xsi:type="msg:AcceptedType"> + <msg:NotificationsPerformed> + <msg:RecipientNotification> + <msg:Timestamp>%s</msg:Timestamp> + </msg:RecipientNotification> + </msg:NotificationsPerformed> + </msg:Answer> + <dsig:Signature xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" Id="signature-1-1"> + <dsig:SignedInfo> + <dsig:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> + <dsig:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> + <dsig:Reference Id="reference-1-1" URI=""> + <dsig:Transforms> + <dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> + <dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> + </dsig:Transforms> + <dsig:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> + <dsig:DigestValue>ejvUI0yh/IIyauFe8x5ZonD/i5oznl8vFyS3oLNivzA=</dsig:DigestValue> + </dsig:Reference> + </dsig:SignedInfo> + <dsig:SignatureValue> + hmVZrLkMDbXaRLYQKOaV3OtK13TQgMu3csKyw9M4zWqNyva1yxnYkzoX3dKDOdc9 + O56yQJsjoA3Cuw7pXlGO7jSfVM77dTXbWSDaF95O9Vdsrmr7R6Uki0jA9SmgQLXg + hZAUG8JpsHcBn8M0L2BXADKjSn0LuMDL2L7dmU3EM7eRy+OvFwDrXDw1fhjQO6L2 + KoflAWLgUerDhJSpzr0+YfmkrjzitLUA7oIg8ieOnfGyql31ECmDJEqgnL78hyPZ + KaNZImDf3EWFs8je6mt+os1TwsyXYwz+GGbjoDR8lGTS9xVqnXdrgP8Jyv6p9FEu + 0IYgSY2FlbI3skPZC8ZVXg== + </dsig:SignatureValue> + <dsig:KeyInfo> + <dsig:X509Data> + <dsig:X509Certificate> + MIIEqzCCBBSgAwIBAgIHANux81oNezANBgkqhkiG9w0BAQUFADBAMSIwIAYDVQQD + ExlJQUlLIFRlc3QgSW50ZXJtZWRpYXRlIENBMQ0wCwYDVQQKEwRJQUlLMQswCQYD + VQQGEwJBVDAeFw0xMzA5MjcwNTMzMzdaFw0yMzA5MjcwNTMzMzdaMIHkMQswCQYD + VQQGEwJBVDENMAsGA1UEBxMER3JhejEmMCQGA1UEChMdR3JheiBVbml2ZXJzaXR5 + IG9mIFRlY2hub2xvZ3kxSDBGBgNVBAsTP0luc3RpdHV0ZSBmb3IgQXBwbGllZCBJ + bmZvcm1hdGlvbiBQcm9jZXNzaW5nIGFuZCBDb21tdW5pY2F0aW9uczEUMBIGA1UE + BBMLTU9BLVNTIFRlc3QxGDAWBgNVBCoTD0VHSVogVGVzdHBvcnRhbDEkMCIGA1UE + AxMbRUdJWiBUZXN0cG9ydGFsIE1PQS1TUyBUZXN0MIIBIjANBgkqhkiG9w0BAQEF + AAOCAQ8AMIIBCgKCAQEAuDjOyf+mY+oQL2FQzzuaiC8C23vVKbq/n2Zi7BqSibZH + mtqMJfmj4pT+hWSNHvVvWsaxFcx4KeNqdCMzwnw1r4P3Sf+2o5uFku5KHEMLMokR + yYQG9VqY/KkB94ye7Pv6zT8gvKqxGFg96UamECep4swPaSZrA8AOER5WAtyGDzKI + Tz+a5zfFaTXDoba7f98PCWR96yKiFjVOhzp38WVz4VJgz+b8ZSY7Xsv5Kn7DXjOL + STX4MevFLki3rFPup3+4vGToaMBW3PEj67HXBdqR855Le6+E6rVxORqsXqlVwhsI + 6nuS0CO2LWYmBNR1IB0mXteeYH/HfxvuZc+7yDjdPQIDAQABo4IBhDCCAYAwDgYD + VR0PAQH/BAQDAgbAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFEmcH6VY4BG1EAGB + TLoNR9vH/g6yMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jYS5pYWlrLnR1Z3Jh + ei5hdC9jYXBzby9jcmxzL0lBSUtUZXN0X0ludGVybWVkaWF0ZUNBLmNybDCBqgYI + KwYBBQUHAQEEgZ0wgZowSgYIKwYBBQUHMAGGPmh0dHA6Ly9jYS5pYWlrLnR1Z3Jh + ei5hdC9jYXBzby9PQ1NQP2NhPUlBSUtUZXN0X0ludGVybWVkaWF0ZUNBMEwGCCsG + AQUFBzAChkBodHRwOi8vY2EuaWFpay50dWdyYXouYXQvY2Fwc28vY2VydHMvSUFJ + S1Rlc3RfSW50ZXJtZWRpYXRlQ0EuY2VyMCEGA1UdEQQaMBiBFnRob21hcy5sZW56 + QGVnaXouZ3YuYXQwHwYDVR0jBBgwFoAUaKJeEdreL4BrRES/jfplNoEkp28wDQYJ + KoZIhvcNAQEFBQADgYEAlFGjUxXLs7SAT8NtXSrv2WrjlklaRnHTFHLQwyVo8JWb + gvRkHHDUv2o8ofXUY2R2WJ38dxeDoccgbXrJb/Qhi8IY7YhCwv/TuIZDisyAqo8W + ORKSip/6HWlGCSR/Vgoet1GtCmF0FoUxFUIGSAuQ2yyt4fIzt5GJrU1X5ujjI1w= + </dsig:X509Certificate> + </dsig:X509Data> + </dsig:KeyInfo> + </dsig:Signature> + </msg:DeliveryNotification> + </soapenv:Body> +</soapenv:Envelope> diff --git a/src/test/resources/at/gv/egiz/moazs/ITEndToEndTest/msg-delivery-request-status.xml b/src/test/resources/at/gv/egiz/moazs/ITEndToEndTest/msg-delivery-request-status.xml new file mode 100644 index 0000000..bbeded8 --- /dev/null +++ b/src/test/resources/at/gv/egiz/moazs/ITEndToEndTest/msg-delivery-request-status.xml @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="UTF-8"?> +<soapenv:Envelope + xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" + xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" + xmlns:msg="http://reference.e-government.gv.at/namespace/zustellung/msg/phase2/20181206#"> + <soapenv:Body> + <msg:DeliveryRequestStatus> + <msg:Success> + <msg:DeliverySystem>%s</msg:DeliverySystem> + <msg:ZSDeliveryID>%s</msg:ZSDeliveryID> + <msg:AppDeliveryID>%s</msg:AppDeliveryID> + <msg:GZ>%s</msg:GZ> + <msg:DeliveryTimestamp>%s</msg:DeliveryTimestamp> + <msg:RelayedViaERV>false</msg:RelayedViaERV> + </msg:Success> + <dsig:Signature xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" Id="signature-1-1"> + <dsig:SignedInfo> + <dsig:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> + <dsig:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> + <dsig:Reference Id="reference-1-1" URI=""> + <dsig:Transforms> + <dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> + <dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> + </dsig:Transforms> + <dsig:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> + <dsig:DigestValue>ejvUI0yh/IIyauFe8x5ZonD/i5oznl8vFyS3oLNivzA=</dsig:DigestValue> + </dsig:Reference> + </dsig:SignedInfo> + <dsig:SignatureValue> + hmVZrLkMDbXaRLYQKOaV3OtK13TQgMu3csKyw9M4zWqNyva1yxnYkzoX3dKDOdc9 + O56yQJsjoA3Cuw7pXlGO7jSfVM77dTXbWSDaF95O9Vdsrmr7R6Uki0jA9SmgQLXg + hZAUG8JpsHcBn8M0L2BXADKjSn0LuMDL2L7dmU3EM7eRy+OvFwDrXDw1fhjQO6L2 + KoflAWLgUerDhJSpzr0+YfmkrjzitLUA7oIg8ieOnfGyql31ECmDJEqgnL78hyPZ + KaNZImDf3EWFs8je6mt+os1TwsyXYwz+GGbjoDR8lGTS9xVqnXdrgP8Jyv6p9FEu + 0IYgSY2FlbI3skPZC8ZVXg== + </dsig:SignatureValue> + <dsig:KeyInfo> + <dsig:X509Data> + <dsig:X509Certificate> + MIIEqzCCBBSgAwIBAgIHANux81oNezANBgkqhkiG9w0BAQUFADBAMSIwIAYDVQQD + ExlJQUlLIFRlc3QgSW50ZXJtZWRpYXRlIENBMQ0wCwYDVQQKEwRJQUlLMQswCQYD + VQQGEwJBVDAeFw0xMzA5MjcwNTMzMzdaFw0yMzA5MjcwNTMzMzdaMIHkMQswCQYD + VQQGEwJBVDENMAsGA1UEBxMER3JhejEmMCQGA1UEChMdR3JheiBVbml2ZXJzaXR5 + IG9mIFRlY2hub2xvZ3kxSDBGBgNVBAsTP0luc3RpdHV0ZSBmb3IgQXBwbGllZCBJ + bmZvcm1hdGlvbiBQcm9jZXNzaW5nIGFuZCBDb21tdW5pY2F0aW9uczEUMBIGA1UE + BBMLTU9BLVNTIFRlc3QxGDAWBgNVBCoTD0VHSVogVGVzdHBvcnRhbDEkMCIGA1UE + AxMbRUdJWiBUZXN0cG9ydGFsIE1PQS1TUyBUZXN0MIIBIjANBgkqhkiG9w0BAQEF + AAOCAQ8AMIIBCgKCAQEAuDjOyf+mY+oQL2FQzzuaiC8C23vVKbq/n2Zi7BqSibZH + mtqMJfmj4pT+hWSNHvVvWsaxFcx4KeNqdCMzwnw1r4P3Sf+2o5uFku5KHEMLMokR + yYQG9VqY/KkB94ye7Pv6zT8gvKqxGFg96UamECep4swPaSZrA8AOER5WAtyGDzKI + Tz+a5zfFaTXDoba7f98PCWR96yKiFjVOhzp38WVz4VJgz+b8ZSY7Xsv5Kn7DXjOL + STX4MevFLki3rFPup3+4vGToaMBW3PEj67HXBdqR855Le6+E6rVxORqsXqlVwhsI + 6nuS0CO2LWYmBNR1IB0mXteeYH/HfxvuZc+7yDjdPQIDAQABo4IBhDCCAYAwDgYD + VR0PAQH/BAQDAgbAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFEmcH6VY4BG1EAGB + TLoNR9vH/g6yMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jYS5pYWlrLnR1Z3Jh + ei5hdC9jYXBzby9jcmxzL0lBSUtUZXN0X0ludGVybWVkaWF0ZUNBLmNybDCBqgYI + KwYBBQUHAQEEgZ0wgZowSgYIKwYBBQUHMAGGPmh0dHA6Ly9jYS5pYWlrLnR1Z3Jh + ei5hdC9jYXBzby9PQ1NQP2NhPUlBSUtUZXN0X0ludGVybWVkaWF0ZUNBMEwGCCsG + AQUFBzAChkBodHRwOi8vY2EuaWFpay50dWdyYXouYXQvY2Fwc28vY2VydHMvSUFJ + S1Rlc3RfSW50ZXJtZWRpYXRlQ0EuY2VyMCEGA1UdEQQaMBiBFnRob21hcy5sZW56 + QGVnaXouZ3YuYXQwHwYDVR0jBBgwFoAUaKJeEdreL4BrRES/jfplNoEkp28wDQYJ + KoZIhvcNAQEFBQADgYEAlFGjUxXLs7SAT8NtXSrv2WrjlklaRnHTFHLQwyVo8JWb + gvRkHHDUv2o8ofXUY2R2WJ38dxeDoccgbXrJb/Qhi8IY7YhCwv/TuIZDisyAqo8W + ORKSip/6HWlGCSR/Vgoet1GtCmF0FoUxFUIGSAuQ2yyt4fIzt5GJrU1X5ujjI1w= + </dsig:X509Certificate> + </dsig:X509Data> + </dsig:KeyInfo> + </dsig:Signature> + </msg:DeliveryRequestStatus> + </soapenv:Body> +</soapenv:Envelope> diff --git a/src/test/resources/at/gv/egiz/moazs/ITEndToEndTest/mzs-delivery-request.xml b/src/test/resources/at/gv/egiz/moazs/ITEndToEndTest/mzs-delivery-request.xml new file mode 100644 index 0000000..ef07686 --- /dev/null +++ b/src/test/resources/at/gv/egiz/moazs/ITEndToEndTest/mzs-delivery-request.xml @@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="UTF-8"?> +<soapenv:Envelope + xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" + xmlns:mzs="http://reference.e-government.gv.at/namespace/zustellung/mzs/app2mzs#" + xmlns:p="http://reference.e-government.gv.at/namespace/zustellung/mzs/persondata#" + xmlns:msg="http://reference.e-government.gv.at/namespace/zustellung/msg/phase2/20181206#"> + <soapenv:Body> + <mzs:DeliveryRequest> + <mzs:Sender> + <p:CorporateBody> + <p:Identification> + <p:Value>kkvj693+tw99uW8UPuEK9en1LzZItkylPajkUUyJJDWQB78VGPkAuhCEk+TD12yQDD/WRglsf+JfQpjubIs/4l/ptluJ9teF3nwkNlu5Dm7mIjzgW1qxrDyomCmPvVxTWOCBuMUbOWRZBhOq+KvDQAu9Vv9KnqSfjYeDZrpHYu4=</p:Value> + <p:Type>urn:publicid:gv:at:cemtoken</p:Type> + </p:Identification> + <p:FullName>Bundesministerium für Testzwecke</p:FullName> + </p:CorporateBody> + <mzs:WebserviceURL>https://authority.gv.at/delivery_notification</mzs:WebserviceURL> + </mzs:Sender> + <mzs:Receiver> + <p:PhysicalPerson> + <p:Name> + <p:GivenName>Maxi</p:GivenName> + <p:FamilyName>Mustermann1</p:FamilyName> + </p:Name> + <p:DateOfBirth>1984-01-24</p:DateOfBirth> + </p:PhysicalPerson> + <p:PostalAddress> + <p:CountryCode>AT</p:CountryCode> + <p:PostalCode>1010</p:PostalCode> + <p:Municipality>Wien</p:Municipality> + <p:DeliveryAddress> + <p:StreetName>Muststrasse</p:StreetName> + <p:BuildingNumber>10</p:BuildingNumber> + </p:DeliveryAddress> + </p:PostalAddress> + </mzs:Receiver> + <msg:MetaData> + <msg:AppDeliveryID>delivery-request-id</msg:AppDeliveryID> + <msg:Origin> + <msg:ParticipantID>VKABC</msg:ParticipantID> + </msg:Origin> + <msg:Subject>WichtigeMitteilung</msg:Subject> + <msg:DeliveryQuality>RSa</msg:DeliveryQuality> + </msg:MetaData> + <mzs:Payload> + <mzs:DocumentReference>https://authority.gv.at/files/73bdf969781ba41fa07df1ff8439cf685c0db1c3</mzs:DocumentReference> + <mzs:FileName>brief.xml</mzs:FileName> + <mzs:MIMEType>text/xml</mzs:MIMEType> + <msg:CheckSum> + <msg:AlgorithmID>SHA1</msg:AlgorithmID> + <msg:Value>9b972c70fdaf5e1b26b3387c87b0ffb72e5940b6</msg:Value> + </msg:CheckSum> + <mzs:Size>123401</mzs:Size> + </mzs:Payload> + <mzs:Config> + <mzs:PerformQueryPersonRequest>true</mzs:PerformQueryPersonRequest> + <mzs:TNVZClient> + <mzs:URL>http://localhost/tvnzservice</mzs:URL> + <mzs:ConnectionTimeout>0</mzs:ConnectionTimeout> + <mzs:ReceiveTimeout>0</mzs:ReceiveTimeout> + </mzs:TNVZClient> + <mzs:MsgResponseSinks> + <mzs:SaveResponseToFile> + <mzs:Active>true</mzs:Active> + <mzs:Path>target/tmp/ITEndToEndTestOut</mzs:Path> + </mzs:SaveResponseToFile> + <mzs:LogResponse>true</mzs:LogResponse> + <mzs:ForwardResponseToService> + <mzs:Active>true</mzs:Active> + <mzs:MzsClient> + <mzs:URL>http://localhost/appurl</mzs:URL> + <mzs:ConnectionTimeout>0</mzs:ConnectionTimeout> + <mzs:ReceiveTimeout>0</mzs:ReceiveTimeout> + </mzs:MzsClient> + </mzs:ForwardResponseToService> + </mzs:MsgResponseSinks> + </mzs:Config> + </mzs:DeliveryRequest> + </soapenv:Body> +</soapenv:Envelope> |