aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/at/gv
diff options
context:
space:
mode:
authorChristof Rabensteiner <christof.rabensteiner@iaik.tugraz.at>2019-05-27 09:46:36 +0200
committerChristof Rabensteiner <christof.rabensteiner@iaik.tugraz.at>2019-05-27 10:28:56 +0200
commit695ab1f836160d40c4352a2c3127f4f687912817 (patch)
treecd23bf0e2f6430bd2f5caf40825705e3fe644f98 /src/main/java/at/gv
parent0a316ada10bb88720dd15958168409fcb9fcf800 (diff)
downloadmoa-zs-695ab1f836160d40c4352a2c3127f4f687912817.tar.gz
moa-zs-695ab1f836160d40c4352a2c3127f4f687912817.tar.bz2
moa-zs-695ab1f836160d40c4352a2c3127f4f687912817.zip
Intercept Incoming DeliveryRequestStatus and Store as byte[]
- Add egovutils dependency (Reason: Need DomUtils to serialize / unserialize Soap Message via DOMParser) - Add Incerceptor to MsgClient / -Factory that stores the message content byte-by-byte in the DeliveryRepository. The format is required for successfully validating a DeliveryRequestStatus. - Add SoapUtils, which interacts with byte[] Soap message. - Add CXFMessageUtils, which interacts with CXF Messages from interceptor chains. - Refactor xsd namespaces: Move them out from the PrefixMapper and into a dedicated class.
Diffstat (limited to 'src/main/java/at/gv')
-rw-r--r--src/main/java/at/gv/egiz/moazs/msg/MsgClient.java43
-rw-r--r--src/main/java/at/gv/egiz/moazs/msg/MsgClientFactory.java10
-rw-r--r--src/main/java/at/gv/egiz/moazs/msg/StoreSOAPBodyBinaryInRepositoryInterceptor.java55
-rw-r--r--src/main/java/at/gv/egiz/moazs/scheme/MoaZSPrefixMapper.java36
-rw-r--r--src/main/java/at/gv/egiz/moazs/scheme/NameSpace.java17
-rw-r--r--src/main/java/at/gv/egiz/moazs/scheme/SOAPUtils.java44
-rw-r--r--src/main/java/at/gv/egiz/moazs/util/CXFMessageUtils.java92
7 files changed, 237 insertions, 60 deletions
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 6f0b1d9..fd36a92 100644
--- a/src/main/java/at/gv/egiz/moazs/msg/MsgClient.java
+++ b/src/main/java/at/gv/egiz/moazs/msg/MsgClient.java
@@ -6,6 +6,8 @@ import at.gv.zustellung.msg.xsd.DeliveryRequestStatusType;
import at.gv.zustellung.msg.xsd.DeliveryRequestType;
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;
@@ -15,53 +17,34 @@ public class MsgClient {
private final DeliveryRequestType msgRequest;
private final ConfigType config;
+ private final PhaseInterceptor<? extends Message> interceptor;
- MsgClient(DeliveryRequestType msgRequest, ConfigType config) {
+ MsgClient(DeliveryRequestType msgRequest, ConfigType config, PhaseInterceptor<? extends Message> interceptor) {
this.msgRequest = msgRequest;
this.config = config;
+ this.interceptor = interceptor;
}
+ /**
+ * Send {@code msgRequest} to {@code Config/Server/ZUSEUrlID} and run {@code interceptor} on response.
+ * @return
+ */
public DeliveryRequestStatusType send() {
-
var proxy = connect(config);
-
return proxy.delivery(msgRequest);
-
}
private App2ZusePort connect(ConfigType config) {
- new JaxWsClientFactoryBean();
-
var address = config.getServer().getZUSEUrlID();
- var factory = new JaxWsProxyFactoryBean();
+
+ var factory = new JaxWsClientFactoryBean();
factory.setServiceClass(App2ZusePort.class);
factory.setAddress(address);
+ factory.getInInterceptors().add(interceptor);
- var proxy = factory.create();
-
-// var client = ClientProxy.getClient(proxy);
-// var conduit = (HTTPConduit) client.getConduit();
-//
-// if (addressIsHttps(address)) {
-// var tlsParams = new TLSClientParameters();
-// tlsParams.setSSLSocketFactory(createSSLContext().getSocketFactory());
-// conduit.setTlsClientParameters(tlsParams);
-// }
+ var proxy = new JaxWsProxyFactoryBean(factory).create();
return (App2ZusePort) proxy;
}
-
-// private SSLContext createSSLContext() {
-// java.util.Properties props = new Properties();
-// props.entrySet();
-//
-// // return SSLUtils.getPropertiesSSLContext(this.props, this.configDir, this.propsPrefix, forceTrustAllManager);
-// return null;
-// }
-
- private boolean addressIsHttps(String address) {
- return address.startsWith("https://");
- }
-
}
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 9884bd5..82468bc 100644
--- a/src/main/java/at/gv/egiz/moazs/msg/MsgClientFactory.java
+++ b/src/main/java/at/gv/egiz/moazs/msg/MsgClientFactory.java
@@ -2,13 +2,21 @@ package at.gv.egiz.moazs.msg;
import at.gv.zustellung.app2mzs.xsd.ConfigType;
import at.gv.zustellung.msg.xsd.DeliveryRequestType;
+import org.springframework.beans.factory.annotation.Autowired;
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) {
- return new MsgClient(msgRequest, config);
+ return new MsgClient(msgRequest, config, storeResponseInterceptor);
}
}
diff --git a/src/main/java/at/gv/egiz/moazs/msg/StoreSOAPBodyBinaryInRepositoryInterceptor.java b/src/main/java/at/gv/egiz/moazs/msg/StoreSOAPBodyBinaryInRepositoryInterceptor.java
new file mode 100644
index 0000000..4e023ac
--- /dev/null
+++ b/src/main/java/at/gv/egiz/moazs/msg/StoreSOAPBodyBinaryInRepositoryInterceptor.java
@@ -0,0 +1,55 @@
+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;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.phase.AbstractPhaseInterceptor;
+import org.apache.cxf.phase.Phase;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.IOException;
+
+@Component
+public class StoreSOAPBodyBinaryInRepositoryInterceptor extends AbstractPhaseInterceptor<Message> {
+
+ private static final Logger log = LoggerFactory.getLogger(StoreSOAPBodyBinaryInRepositoryInterceptor.class);
+
+ private final CXFMessageUtils messageUtils;
+ private final SOAPUtils soapUtils;
+ private final DeliveryRepository repository;
+
+ @Autowired
+ public StoreSOAPBodyBinaryInRepositoryInterceptor(CXFMessageUtils extractor, SOAPUtils soapUtils,
+ DeliveryRepository repository) {
+ super(Phase.RECEIVE);
+ this.messageUtils = extractor;
+ this.soapUtils = soapUtils;
+ this.repository = repository;
+ }
+
+ public void handleMessage(Message message) {
+
+ try {
+ byte[] content = messageUtils.copyContent(message);
+
+ if(content.length > 0) {
+ Element document = soapUtils.toDOM(content);
+ byte[] status = soapUtils.unwrapSoapEnvelope(document);
+ String appDeliveryId = soapUtils.getAppDeliveryIDFrom(document);
+ repository.addSignedDeliveryRequestStatus(status, appDeliveryId);
+ 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);
+ }
+ }
+
+}
diff --git a/src/main/java/at/gv/egiz/moazs/scheme/MoaZSPrefixMapper.java b/src/main/java/at/gv/egiz/moazs/scheme/MoaZSPrefixMapper.java
index faee8a5..d725ce6 100644
--- a/src/main/java/at/gv/egiz/moazs/scheme/MoaZSPrefixMapper.java
+++ b/src/main/java/at/gv/egiz/moazs/scheme/MoaZSPrefixMapper.java
@@ -12,43 +12,21 @@ public class MoaZSPrefixMapper extends NamespacePrefixMapper {
private final Map<String, String> map = new HashMap<>();
public MoaZSPrefixMapper() {
- map.put(getMsgNamespaceUri(), "msg");
- map.put(getMsgPNamespaceUri(), "msgp");
- map.put(getMzsNamespaceUri(), "mzs");
- map.put(getMzsPNamespaceUri(), "mzsp");
- map.put(getDsigNamespaceUri(), "dsig");
+ map.put(NameSpace.MSG, "msg");
+ map.put(NameSpace.MSGP, "msgp");
+ map.put(NameSpace.MZS, "mzs");
+ map.put(NameSpace.MZSP, "mzsp");
+ map.put(NameSpace.DSIG, "dsig");
}
public MoaZSPrefixMapper(boolean isMzs) {
this();
- map.put((isMzs) ? getMzsPNamespaceUri() : getMsgPNamespaceUri(), "p");
- map.put((isMzs) ? getMzsNamespaceUri() : getMsgNamespaceUri(), "");
+ map.put((isMzs) ? NameSpace.MZSP : NameSpace.MSGP, "p");
+ map.put((isMzs) ? NameSpace.MZS : NameSpace.MSG , "");
}
@Override
public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
return map.getOrDefault(namespaceUri, suggestion);
}
-
- private String getMsgNamespaceUri() {
- return new at.gv.zustellung.msg.xsd.ObjectFactory().createDeliveryRequest(null).getName().getNamespaceURI();
- }
-
- private String getMsgPNamespaceUri() {
- return new at.gv.zustellung.msg.xsd.persondata.ObjectFactory().createPerson(null).getName().getNamespaceURI();
- }
-
- private String getMzsNamespaceUri() {
- return new at.gv.zustellung.app2mzs.xsd.ObjectFactory().createDeliveryRequest(null).getName().getNamespaceURI();
- }
-
- private String getMzsPNamespaceUri() {
- return new at.gv.zustellung.app2mzs.xsd.persondata.ObjectFactory().createAbstractPersonData(null).getName().getNamespaceURI();
- }
-
- private String getDsigNamespaceUri() {
- return new org.w3._2000._09.xmldsig_.ObjectFactory().createCanonicalizationMethod(null).getName().getNamespaceURI();
- }
-
-
}
diff --git a/src/main/java/at/gv/egiz/moazs/scheme/NameSpace.java b/src/main/java/at/gv/egiz/moazs/scheme/NameSpace.java
new file mode 100644
index 0000000..63276cb
--- /dev/null
+++ b/src/main/java/at/gv/egiz/moazs/scheme/NameSpace.java
@@ -0,0 +1,17 @@
+package at.gv.egiz.moazs.scheme;
+
+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 MSGP = new at.gv.zustellung.msg.xsd.persondata.ObjectFactory().createPerson(null).getName().getNamespaceURI();
+
+ public static final String MZS = new at.gv.zustellung.app2mzs.xsd.ObjectFactory().createDeliveryRequest(null).getName().getNamespaceURI();
+
+ public static final String MZSP = new at.gv.zustellung.app2mzs.xsd.persondata.ObjectFactory().createAbstractPersonData(null).getName().getNamespaceURI();
+
+ public static final String DSIG = new org.w3._2000._09.xmldsig_.ObjectFactory().createCanonicalizationMethod(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
new file mode 100644
index 0000000..2d4df4b
--- /dev/null
+++ b/src/main/java/at/gv/egiz/moazs/scheme/SOAPUtils.java
@@ -0,0 +1,44 @@
+package at.gv.egiz.moazs.scheme;
+
+import at.gv.egiz.moazs.MoaZSException;
+import at.gv.util.DOMUtils;
+import org.apache.cxf.binding.soap.Soap11;
+import org.springframework.stereotype.Component;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+@Component
+public class SOAPUtils {
+
+ 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();
+
+ return DOMUtils.serializeNode(item, true)
+ .getBytes(StandardCharsets.UTF_8);
+
+ } catch (IOException | TransformerException e) {
+ throw new MoaZSException("Error while parsing message. ", e);
+ }
+ }
+
+ public String getAppDeliveryIDFrom(Element document) {
+ var elements = document.getElementsByTagNameNS(NameSpace.MSG, "AppDeliveryID");
+
+ var appDeliveryIdElement = elements.item(0).getFirstChild();
+
+ return appDeliveryIdElement.getNodeValue();
+ }
+}
diff --git a/src/main/java/at/gv/egiz/moazs/util/CXFMessageUtils.java b/src/main/java/at/gv/egiz/moazs/util/CXFMessageUtils.java
new file mode 100644
index 0000000..07fdfb6
--- /dev/null
+++ b/src/main/java/at/gv/egiz/moazs/util/CXFMessageUtils.java
@@ -0,0 +1,92 @@
+package at.gv.egiz.moazs.util;
+
+import org.apache.cxf.helpers.IOUtils;
+import org.apache.cxf.io.CachedOutputStream;
+import org.apache.cxf.io.CachedWriter;
+import org.apache.cxf.io.DelegatingInputStream;
+import org.apache.cxf.message.Message;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.SequenceInputStream;
+
+@Component
+public class CXFMessageUtils {
+
+ private static final Logger LOG = LoggerFactory.getLogger(CXFMessageUtils.class);
+
+ /**
+ * Copy and return content of org.apache.cxf.message.Message; Restore InputStream / Reader from
+ * message.getContent() after consuming it.
+ * @param message
+ * @return
+ * @throws IOException
+ */
+ public byte[] copyContent(Message message) throws IOException {
+
+ if (message.getContent(InputStream.class) != null) {
+ return streamMessageContentToByteArray(message);
+ } else if (message.getContent(Reader.class) != null) {
+ return readMessageContentToByteArray(message);
+ } else {
+ LOG.warn("Message Content is neither Reader nor InputStream; will return empty content.");
+ return new byte[0];
+ }
+ }
+
+ /**
+ * Source: Adapted from ApacheCXF 3.3.0 / LoggingInInterceptor.logInputStream()
+ * @param message
+ * @return copy of message content
+ * @throws IOException
+ */
+ private byte[] streamMessageContentToByteArray(Message message) throws IOException {
+
+ var in = message.getContent(InputStream.class);
+
+ try (var out = new CachedOutputStream()) {
+
+ // use the appropriate input stream and restore it later
+ InputStream bis = in instanceof DelegatingInputStream
+ ? ((DelegatingInputStream)in).getInputStream() : in;
+
+ //only copy up to the limit since that's all we need to log
+ //we can stream the rest
+ IOUtils.copy(bis, out);
+ out.flush();
+ bis = new SequenceInputStream(out.getInputStream(), bis);
+
+ // restore the delegating input stream or the input stream
+ if (in instanceof DelegatingInputStream) {
+ ((DelegatingInputStream)in).setInputStream(bis);
+ } else {
+ message.setContent(InputStream.class, bis);
+ }
+
+ return out.getBytes();
+ }
+
+ }
+
+ /**
+ * Source: Adapted from ApacheCXF 3.3.0 / LoggingInInterceptor.logReader()
+ * @param message
+ * @return copy of message content
+ * @throws IOException
+ */
+ private byte[] readMessageContentToByteArray(Message message) throws IOException {
+ var reader = message.getContent(Reader.class);
+ var writer = new CachedWriter();
+ IOUtils.copyAndCloseInput(reader, writer);
+ message.setContent(Reader.class, writer.getReader());
+
+ var buffer = new StringBuilder();
+ writer.writeCacheTo(buffer);
+ return buffer.toString().getBytes();
+ }
+
+}