From c2623b7b6290afcbfd6f584399cc819442d66c18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Even=20=C3=98stvold?= Date: Thu, 31 Oct 2019 06:40:25 +0100 Subject: [PATCH] Added and fixed CEF connectivity tests, and refactored --- pom.xml | 22 +- .../oxalis/as4/common/DummyHeaderParser.java | 12 +- .../oxalis/as4/outbound/As4MessageSender.java | 98 +++++--- .../as4/outbound/As4OutboundModule.java | 22 +- .../as4/outbound/MessagingProvider.java | 66 ++--- .../TransmissionResponseConverter.java | 8 +- .../no/difi/oxalis/as4/util/GeneralUtils.java | 15 ++ .../oxalis/as4/util/PeppolConfiguration.java | 1 - .../as4/util/TransmissionRequestUtil.java | 25 ++ .../no/difi/oxalis/as4/SendReceiveTest.java | 12 +- .../AbstractMessagingProviderTest.java | 228 ++++++++++++++++++ .../MessagingProviderTest_CEF_SBDH.java | 72 ++++++ .../MessagingProviderTest_SIMPLE_SBDH.java | 47 ++++ .../as4/util/TransmissionRequestUtilTest.java | 53 ++++ .../DefaultTransmissionRequestFacade.java | 41 ++++ .../transmission/MessagingProviderFacade.java | 29 +++ src/test/resources/cef-sbd.xml | 49 ++++ 17 files changed, 681 insertions(+), 119 deletions(-) create mode 100644 src/main/java/no/difi/oxalis/as4/util/GeneralUtils.java create mode 100644 src/main/java/no/difi/oxalis/as4/util/TransmissionRequestUtil.java create mode 100644 src/test/java/no/difi/oxalis/as4/outbound/AbstractMessagingProviderTest.java create mode 100644 src/test/java/no/difi/oxalis/as4/outbound/MessagingProviderTest_CEF_SBDH.java create mode 100644 src/test/java/no/difi/oxalis/as4/outbound/MessagingProviderTest_SIMPLE_SBDH.java create mode 100644 src/test/java/no/difi/oxalis/as4/util/TransmissionRequestUtilTest.java create mode 100644 src/test/java/no/difi/oxalis/outbound/transmission/DefaultTransmissionRequestFacade.java create mode 100644 src/test/java/no/difi/oxalis/outbound/transmission/MessagingProviderFacade.java create mode 100644 src/test/resources/cef-sbd.xml diff --git a/pom.xml b/pom.xml index e2a0a3a..15b8427 100755 --- a/pom.xml +++ b/pom.xml @@ -71,6 +71,12 @@ test + + no.difi.oxalis + oxalis-outbound + test + + javax.servlet javax.servlet-api @@ -191,22 +197,6 @@ - org.jvnet.jaxb2.maven2 maven-jaxb2-plugin diff --git a/src/main/java/no/difi/oxalis/as4/common/DummyHeaderParser.java b/src/main/java/no/difi/oxalis/as4/common/DummyHeaderParser.java index bb58131..4084cca 100644 --- a/src/main/java/no/difi/oxalis/as4/common/DummyHeaderParser.java +++ b/src/main/java/no/difi/oxalis/as4/common/DummyHeaderParser.java @@ -4,10 +4,11 @@ import lombok.extern.slf4j.Slf4j; import no.difi.oxalis.api.header.HeaderParser; import no.difi.oxalis.api.util.Type; -import no.difi.vefa.peppol.common.model.Header; +import no.difi.vefa.peppol.common.model.*; import java.io.IOException; import java.io.InputStream; +import java.util.Date; @Slf4j @Singleton @@ -26,6 +27,13 @@ public Header parse(InputStream inputStream) { log.error("IOException while parsing header", e); } - return new Header(); + return Header.of( + ParticipantIdentifier.of("DummySender"), + ParticipantIdentifier.of("DummyReceiver"), + ProcessIdentifier.of("DummyProcess"), + DocumentTypeIdentifier.of("DummyDocument"), + InstanceIdentifier.of("DummyInstance"), + InstanceType.of("Dummy", "InstanceType", "1.0"), + new Date(0L)); } } diff --git a/src/main/java/no/difi/oxalis/as4/outbound/As4MessageSender.java b/src/main/java/no/difi/oxalis/as4/outbound/As4MessageSender.java index 042793a..dde553d 100644 --- a/src/main/java/no/difi/oxalis/as4/outbound/As4MessageSender.java +++ b/src/main/java/no/difi/oxalis/as4/outbound/As4MessageSender.java @@ -5,11 +5,10 @@ import no.difi.oxalis.api.outbound.TransmissionRequest; import no.difi.oxalis.api.outbound.TransmissionResponse; import no.difi.oxalis.api.settings.Settings; -import no.difi.oxalis.api.timestamp.TimestampProvider; import no.difi.oxalis.as4.api.MessageIdGenerator; import no.difi.oxalis.as4.lang.OxalisAs4TransmissionException; import no.difi.oxalis.as4.util.CompressionUtil; -import no.difi.oxalis.as4.util.OxalisAlgorithmSuiteLoader; +import no.difi.oxalis.as4.util.Constants; import no.difi.oxalis.commons.http.HttpConf; import no.difi.oxalis.commons.security.KeyStoreConf; import org.apache.cxf.Bus; @@ -17,6 +16,7 @@ import org.apache.cxf.binding.soap.SoapHeader; import org.apache.cxf.ext.logging.LoggingFeature; import org.apache.cxf.headers.Header; +import org.apache.cxf.jaxb.JAXBDataBinding; import org.apache.cxf.jaxws.DispatchImpl; import org.apache.cxf.message.Attachment; import org.apache.cxf.message.Message; @@ -26,13 +26,13 @@ import org.apache.cxf.ws.policy.PolicyConstants; import org.apache.cxf.ws.policy.WSPolicyFeature; import org.apache.cxf.ws.security.SecurityConstants; -import org.apache.cxf.ws.security.policy.custom.AlgorithmSuiteLoader; import org.apache.neethi.Policy; -import org.apache.wss4j.common.ConfigurationConstants; import org.apache.wss4j.common.crypto.Merlin; import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.oasis_open.docs.ebxml_msg.ebms.v3_0.ns.core._200704.Messaging; import org.xml.sax.SAXException; +import javax.xml.bind.JAXBException; import javax.xml.namespace.QName; import javax.xml.parsers.ParserConfigurationException; import javax.xml.soap.SOAPMessage; @@ -68,54 +68,56 @@ public class As4MessageSender { @Inject private CompressionUtil compressionUtil; - @Inject - private TimestampProvider timestampProvider; - @Inject private Settings httpConfSettings; + @Inject + private TransmissionResponseConverter transmissionResponseConverter; + @Inject + private Bus bus; - public TransmissionResponse send(TransmissionRequest request) throws OxalisAs4TransmissionException { - - final String address = request.getEndpoint().getAddress().toString(); + private Service service; - Service service = Service.create(SERVICE_NAME, new LoggingFeature(), new WSPolicyFeature()); + public As4MessageSender() { + service = Service.create(SERVICE_NAME, new LoggingFeature(), new WSPolicyFeature()); service.addPort(PORT_NAME, SOAPBinding.SOAP12HTTP_BINDING, "BindingProvider.ENDPOINT_ADDRESS_PROPERTY placeholder"); + } + public TransmissionResponse send(TransmissionRequest request) throws OxalisAs4TransmissionException { + Dispatch dispatch = createDispatch(request.getEndpoint().getAddress().toString()); - Dispatch dispatch = service.createDispatch(PORT_NAME, SOAPMessage.class, Service.Mode.MESSAGE); - dispatch.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, address); + Collection attachments = prepareAttachments(request); + Messaging messaging = messagingProvider.createMessagingHeader(request, attachments); - HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy(); - httpClientPolicy.setConnectionTimeout(httpConfSettings.getInt(HttpConf.TIMEOUT_CONNECT)); - httpClientPolicy.setReceiveTimeout(httpConfSettings.getInt(HttpConf.TIMEOUT_READ)); - ((HTTPConduit)((DispatchImpl)dispatch).getClient().getConduit()).setClient(httpClientPolicy); + SoapHeader header = null; + try { + header = new SoapHeader( + Constants.MESSAGING_QNAME, + messaging, + new JAXBDataBinding(Messaging.class), + true); + }catch (JAXBException e){ + throw new OxalisAs4TransmissionException("Unable to marshal AS4 header", e); + } + dispatch.getRequestContext().put(Header.HEADER_LIST, new ArrayList(Arrays.asList(header))); + dispatch.getRequestContext().put(Message.ATTACHMENTS, attachments); - HashMap> headers = new HashMap<>(); - headers.put("Content-ID", Collections.singletonList(messageIdGenerator.generate())); - headers.put("CompressionType", Collections.singletonList("application/gzip")); - headers.put("MimeType", Collections.singletonList("application/xml")); - Attachment attachment = null; - try{ - attachment = AttachmentUtil.createAttachment(compressionUtil.getCompressedStream(request.getPayload()), headers); + configureSecurity(request, dispatch); - }catch (IOException e){ - throw new OxalisAs4TransmissionException("Unable to compress payload", e); - } - Collection attachments = new ArrayList<>(Arrays.asList(attachment)); + SOAPMessage response = dispatch.invoke(null); - SoapHeader header = messagingProvider.createMessagingHeader(request, attachments); + return transmissionResponseConverter.convert(request, response); - dispatch.getRequestContext().put(Header.HEADER_LIST, new ArrayList(Arrays.asList(header))); - dispatch.getRequestContext().put(Message.ATTACHMENTS, attachments); + } + private void configureSecurity(TransmissionRequest request, Dispatch dispatch) throws OxalisAs4TransmissionException { Merlin signatureCrypto = new Merlin(); signatureCrypto.setCryptoProvider(BouncyCastleProvider.PROVIDER_NAME); @@ -130,21 +132,45 @@ public TransmissionResponse send(TransmissionRequest request) throws OxalisAs4Tr try { - Bus bus = ((DispatchImpl) dispatch).getClient().getBus(); - bus.setExtension(new OxalisAlgorithmSuiteLoader(bus), AlgorithmSuiteLoader.class); - PolicyBuilder builder = ((DispatchImpl) dispatch).getClient().getBus().getExtension(org.apache.cxf.ws.policy.PolicyBuilder.class); + PolicyBuilder builder = bus.getExtension(PolicyBuilder.class); Policy policy = builder.getPolicy(getClass().getResourceAsStream("/policy.xml")); dispatch.getRequestContext().put(PolicyConstants.POLICY_OVERRIDE, policy); }catch (IOException | ParserConfigurationException | SAXException e){ throw new OxalisAs4TransmissionException("Unable to parse WSPolicy \"/policy.xml\"", e); } + } + public Collection prepareAttachments(TransmissionRequest request) throws OxalisAs4TransmissionException { - SOAPMessage response = dispatch.invoke(null); + HashMap> headers = new HashMap<>(); + headers.put("Content-ID", Collections.singletonList(messageIdGenerator.generate())); + headers.put("CompressionType", Collections.singletonList("application/gzip")); + headers.put("MimeType", Collections.singletonList("application/xml")); + + try{ + + Attachment attachment = AttachmentUtil.createAttachment(compressionUtil.getCompressedStream(request.getPayload()), headers); + return new ArrayList<>(Arrays.asList(attachment)); + + }catch (IOException e){ - return new TransmissionResponseConverter(request, timestampProvider).convert(response); + throw new OxalisAs4TransmissionException("Unable to compress payload", e); + } + } + + private Dispatch createDispatch(String address) { + + Dispatch dispatch = service.createDispatch(PORT_NAME, SOAPMessage.class, Service.Mode.MESSAGE); + dispatch.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, address); + + HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy(); + httpClientPolicy.setConnectionTimeout(httpConfSettings.getInt(HttpConf.TIMEOUT_CONNECT)); + httpClientPolicy.setReceiveTimeout(httpConfSettings.getInt(HttpConf.TIMEOUT_READ)); + + ((HTTPConduit)((DispatchImpl)dispatch).getClient().getConduit()).setClient(httpClientPolicy); + return dispatch; } diff --git a/src/main/java/no/difi/oxalis/as4/outbound/As4OutboundModule.java b/src/main/java/no/difi/oxalis/as4/outbound/As4OutboundModule.java index 949ea35..d4d5f95 100644 --- a/src/main/java/no/difi/oxalis/as4/outbound/As4OutboundModule.java +++ b/src/main/java/no/difi/oxalis/as4/outbound/As4OutboundModule.java @@ -6,7 +6,11 @@ import no.difi.oxalis.api.settings.Settings; import no.difi.oxalis.as4.config.As4Conf; import no.difi.oxalis.as4.util.CompressionUtil; +import no.difi.oxalis.as4.util.OxalisAlgorithmSuiteLoader; import no.difi.oxalis.as4.util.PeppolConfiguration; +import org.apache.cxf.Bus; +import org.apache.cxf.BusFactory; +import org.apache.cxf.ws.security.policy.custom.AlgorithmSuiteLoader; import org.bouncycastle.jce.provider.BouncyCastleProvider; import java.security.Security; @@ -33,20 +37,26 @@ protected void configure() { bind(As4MessageSender.class); + bind(TransmissionResponseConverter.class); + + } + + @Provides + @Singleton + public Bus getBus(){ + Bus bus = BusFactory.getThreadDefaultBus(true); + bus.setExtension(new OxalisAlgorithmSuiteLoader(bus), AlgorithmSuiteLoader.class); + + return bus; } @Provides @Singleton - protected PeppolConfiguration getPeppolOutboundConfiguration(Settings settings){ + public PeppolConfiguration getPeppolOutboundConfiguration(Settings settings){ if("cef-connectivity".equalsIgnoreCase(settings.getString(As4Conf.TYPE))){ return new PeppolConfiguration(){ - @Override - public String getServiceType() { - return "urn:oasis:names:tc:ebcore:partyid-type:unregistered"; - } - @Override public String getPartyIDType() { return "urn:oasis:names:tc:ebcore:partyid-type:unregistered"; diff --git a/src/main/java/no/difi/oxalis/as4/outbound/MessagingProvider.java b/src/main/java/no/difi/oxalis/as4/outbound/MessagingProvider.java index 03da439..af6646f 100644 --- a/src/main/java/no/difi/oxalis/as4/outbound/MessagingProvider.java +++ b/src/main/java/no/difi/oxalis/as4/outbound/MessagingProvider.java @@ -5,17 +5,13 @@ import no.difi.oxalis.api.outbound.TransmissionRequest; import no.difi.oxalis.as4.api.MessageIdGenerator; import no.difi.oxalis.as4.lang.OxalisAs4TransmissionException; -import no.difi.oxalis.as4.util.CompressionUtil; -import no.difi.oxalis.as4.util.Constants; import no.difi.oxalis.as4.util.PeppolConfiguration; import no.difi.oxalis.commons.security.CertificateUtils; +import no.difi.vefa.peppol.common.model.ProcessIdentifier; import org.apache.cxf.attachment.AttachmentUtil; -import org.apache.cxf.binding.soap.SoapHeader; -import org.apache.cxf.jaxb.JAXBDataBinding; import org.apache.cxf.message.Attachment; import org.oasis_open.docs.ebxml_msg.ebms.v3_0.ns.core._200704.*; -import javax.xml.bind.JAXBException; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.XMLGregorianCalendar; @@ -24,29 +20,28 @@ import java.time.ZoneId; import java.util.*; import java.util.stream.Collectors; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; import static no.difi.oxalis.as4.util.Constants.TEST_ACTION; import static no.difi.oxalis.as4.util.Constants.TEST_SERVICE; +import static no.difi.oxalis.as4.util.GeneralUtils.iteratorToStreamOfUnknownSize; +import static no.difi.oxalis.as4.util.TransmissionRequestUtil.translateDocumentTypeToAction; +import static no.difi.oxalis.as4.util.TransmissionRequestUtil.translateParticipantIdentifierToRecipient; public class MessagingProvider { private final X509Certificate certificate; - private final CompressionUtil compressionUtil; private final MessageIdGenerator messageIdGenerator; private final PeppolConfiguration defaultOutboundConfiguration; @Inject - public MessagingProvider(X509Certificate certificate, CompressionUtil compressionUtil, MessageIdGenerator messageIdGenerator, PeppolConfiguration defaultOutboundConfiguration) { + public MessagingProvider(X509Certificate certificate, MessageIdGenerator messageIdGenerator, PeppolConfiguration defaultOutboundConfiguration) { this.certificate = certificate; - this.compressionUtil = compressionUtil; this.messageIdGenerator = messageIdGenerator; this.defaultOutboundConfiguration = defaultOutboundConfiguration; } - public SoapHeader createMessagingHeader(TransmissionRequest request, Collection attachments) throws OxalisAs4TransmissionException { + public Messaging createMessagingHeader(TransmissionRequest request, Collection attachments) throws OxalisAs4TransmissionException { UserMessage userMessage = UserMessage.builder() .withMessageInfo(createMessageInfo(request)) @@ -57,25 +52,11 @@ public SoapHeader createMessagingHeader(TransmissionRequest request, Collection< .build(); - Messaging messaging = Messaging.builder() + return Messaging.builder() .addUserMessage(userMessage) .build(); - - try { - return new SoapHeader( - Constants.MESSAGING_QNAME, - messaging, - new JAXBDataBinding(Messaging.class), - true); - }catch (JAXBException e){ - throw new OxalisAs4TransmissionException("Unable to marshal AS4 header", e); - } } - - - - private PayloadInfo createPayloadInfo(TransmissionRequest request, Collection attachments) { ArrayList partInfos = Lists.newArrayList(); @@ -85,7 +66,7 @@ private PayloadInfo createPayloadInfo(TransmissionRequest request, Collection !"Content-ID".equals(header)) .map(header -> Property.builder().withName(header).withValue(attachment.getHeader(header)).build()) .forEach(partProperties::addProperty); @@ -115,11 +96,6 @@ private PayloadInfo createPayloadInfo(TransmissionRequest request, Collection properties = new HashMap<>(); @@ -130,12 +106,15 @@ private MessageProperties createMessageProperties(TransmissionRequest request) { } } + String originalSender = translateParticipantIdentifierToRecipient(request.getHeader().getSender()); + String finalRecipient = translateParticipantIdentifierToRecipient(request.getHeader().getReceiver()); + if (!properties.containsKey("originalSender")) { - properties.put("originalSender", request.getHeader().getSender().toString()); + properties.put("originalSender", originalSender); } if (!properties.containsKey("finalRecipient")) { - properties.put("finalRecipient", request.getHeader().getReceiver().toString()); + properties.put("finalRecipient", finalRecipient); } return MessageProperties.builder() @@ -177,18 +156,20 @@ private PartyInfo createPartyInfo(TransmissionRequest request) { private CollaborationInfo createCollaborationInfo(TransmissionRequest request) { - PeppolConfiguration outboundConfiguration = request.getTag() instanceof PeppolConfiguration ? - (PeppolConfiguration) request.getTag() : defaultOutboundConfiguration; + String action = translateDocumentTypeToAction(request.getHeader().getDocumentType()); + ProcessIdentifier process = request.getHeader().getProcess(); + CollaborationInfo.Builder cib = CollaborationInfo.builder() .withConversationId(getConversationId(request)) - .withAction(request.getHeader().getDocumentType().toString()) + .withAction(action) .withService(Service.builder() - .withType(outboundConfiguration.getServiceType()) - .withValue(request.getHeader().getProcess().getIdentifier()) + .withType(process.getScheme().getIdentifier()) + .withValue(process.getIdentifier()) .build() ); + if (request instanceof As4TransmissionRequest && ((As4TransmissionRequest)request).isPing()) { cib = cib.withAction(TEST_ACTION) .withService(Service.builder() @@ -197,7 +178,6 @@ private CollaborationInfo createCollaborationInfo(TransmissionRequest request) { } - if (defaultOutboundConfiguration.getAgreementRef() != null) { cib = cib.withAgreementRef(AgreementRef.builder() .withValue(defaultOutboundConfiguration.getAgreementRef()) @@ -205,6 +185,7 @@ private CollaborationInfo createCollaborationInfo(TransmissionRequest request) { ); } + return cib.build(); } @@ -258,9 +239,4 @@ private String newId() { } - private Stream iteratorToStream(Iterator iterator){ - return StreamSupport.stream( - Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), - false); - } } diff --git a/src/main/java/no/difi/oxalis/as4/outbound/TransmissionResponseConverter.java b/src/main/java/no/difi/oxalis/as4/outbound/TransmissionResponseConverter.java index 2d04fde..f518519 100644 --- a/src/main/java/no/difi/oxalis/as4/outbound/TransmissionResponseConverter.java +++ b/src/main/java/no/difi/oxalis/as4/outbound/TransmissionResponseConverter.java @@ -1,5 +1,6 @@ package no.difi.oxalis.as4.outbound; +import com.google.inject.Inject; import no.difi.oxalis.api.lang.TimestampException; import no.difi.oxalis.api.model.Direction; import no.difi.oxalis.api.model.TransmissionIdentifier; @@ -31,15 +32,14 @@ public class TransmissionResponseConverter { - private TransmissionRequest request; private TimestampProvider timestampProvider; - public TransmissionResponseConverter(TransmissionRequest request, TimestampProvider timestampProvider) { - this.request = request; + @Inject + public TransmissionResponseConverter(TimestampProvider timestampProvider) { this.timestampProvider = timestampProvider; } - public TransmissionResponse convert(SOAPMessage response) { + public TransmissionResponse convert(TransmissionRequest request, SOAPMessage response) { try { SignalMessage signalMessage = getSignalMessage(response); diff --git a/src/main/java/no/difi/oxalis/as4/util/GeneralUtils.java b/src/main/java/no/difi/oxalis/as4/util/GeneralUtils.java new file mode 100644 index 0000000..f99a18c --- /dev/null +++ b/src/main/java/no/difi/oxalis/as4/util/GeneralUtils.java @@ -0,0 +1,15 @@ +package no.difi.oxalis.as4.util; + +import java.util.Iterator; +import java.util.Spliterators; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +public class GeneralUtils { + + public static Stream iteratorToStreamOfUnknownSize(Iterator iterator, int characteristics, boolean parallel){ + return StreamSupport.stream( + Spliterators.spliteratorUnknownSize(iterator, characteristics), + parallel); + } +} diff --git a/src/main/java/no/difi/oxalis/as4/util/PeppolConfiguration.java b/src/main/java/no/difi/oxalis/as4/util/PeppolConfiguration.java index aca3e3b..629448f 100644 --- a/src/main/java/no/difi/oxalis/as4/util/PeppolConfiguration.java +++ b/src/main/java/no/difi/oxalis/as4/util/PeppolConfiguration.java @@ -15,7 +15,6 @@ public class PeppolConfiguration implements Tag { private String partyIDType = "urn:fdc:peppol.eu:2017:identifiers:ap"; private String agreementRef = "urn:fdc:peppol.eu:2017:agreements:tia:ap_provider"; - private String serviceType = "cenbii-procid-ubl"; private String fromRole = "http://docs.oasis-open.org/ebxml-msg/ebms/v3.0/ns/core/200704/initiator"; private String toRole = "http://docs.oasis-open.org/ebxml-msg/ebms/v3.0/ns/core/200704/responder"; diff --git a/src/main/java/no/difi/oxalis/as4/util/TransmissionRequestUtil.java b/src/main/java/no/difi/oxalis/as4/util/TransmissionRequestUtil.java new file mode 100644 index 0000000..76cd29a --- /dev/null +++ b/src/main/java/no/difi/oxalis/as4/util/TransmissionRequestUtil.java @@ -0,0 +1,25 @@ +package no.difi.oxalis.as4.util; + +import no.difi.vefa.peppol.common.model.DocumentTypeIdentifier; +import no.difi.vefa.peppol.common.model.ParticipantIdentifier; + +public class TransmissionRequestUtil { + + public static String translateDocumentTypeToAction(DocumentTypeIdentifier documentTypeIdentifier) { + return documentTypeIdentifier.getScheme() == null || + documentTypeIdentifier.getScheme().getIdentifier() == null || + documentTypeIdentifier.getScheme().getIdentifier().trim().isEmpty() ? + + documentTypeIdentifier.getIdentifier() : + documentTypeIdentifier.toString(); + } + + public static String translateParticipantIdentifierToRecipient(ParticipantIdentifier documentTypeIdentifier) { + return documentTypeIdentifier.getScheme() == null || + documentTypeIdentifier.getScheme().getIdentifier() == null || + documentTypeIdentifier.getScheme().getIdentifier().trim().isEmpty() ? + + documentTypeIdentifier.getIdentifier() : + documentTypeIdentifier.toString(); + } +} diff --git a/src/test/java/no/difi/oxalis/as4/SendReceiveTest.java b/src/test/java/no/difi/oxalis/as4/SendReceiveTest.java index 733d65c..2a742a7 100755 --- a/src/test/java/no/difi/oxalis/as4/SendReceiveTest.java +++ b/src/test/java/no/difi/oxalis/as4/SendReceiveTest.java @@ -16,7 +16,6 @@ import no.difi.oxalis.as4.api.MessageIdGenerator; import no.difi.oxalis.as4.common.DefaultMessageIdGenerator; import no.difi.oxalis.as4.inbound.As4InboundModule; -import no.difi.oxalis.as4.outbound.As4OutboundModule; import no.difi.oxalis.as4.util.PeppolConfiguration; import no.difi.oxalis.commons.guice.GuiceModuleLoader; import no.difi.oxalis.test.jetty.AbstractJettyServerTest; @@ -68,7 +67,7 @@ public SendReceiveTest() throws Exception { @Override public Injector getInjector() { return Guice.createInjector( - new As4OutboundModule(), +// new As4OutboundModule(), new As4InboundModule(), Modules.override(new GuiceModuleLoader()).with(new AbstractModule() { @Override @@ -137,11 +136,6 @@ public String getAgreementRef() { return "TestAgreementRef"; } - @Override - public String getServiceType() { - return "TestServiceType"; - } - @Override public String getFromRole() { return "TestFromRole"; @@ -185,8 +179,8 @@ public Header getHeader() { return Header.newInstance() .sender(ParticipantIdentifier.of("9908:991825827")) .receiver(ParticipantIdentifier.of("9908:991825827")) - .documentType(DocumentTypeIdentifier.of("urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:www.cenbii.eu:transaction:biicoretrdm010:ver1.0:#urn:test.com:bis:something_else:ver1.0::2.0")) - .process(ProcessIdentifier.of("urn:www.cenbii.eu:profile:something_else:ver1.0")); + .documentType(DocumentTypeIdentifier.of("urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:www.cenbii.eu:transaction:biicoretrdm010:ver1.0:#urn:test.com:bis:something_else:ver1.0::2.0", Scheme.of("TestSchema"))) + .process(ProcessIdentifier.of("urn:www.cenbii.eu:profile:something_else:ver1.0", Scheme.of("TestSchema"))); } @Override diff --git a/src/test/java/no/difi/oxalis/as4/outbound/AbstractMessagingProviderTest.java b/src/test/java/no/difi/oxalis/as4/outbound/AbstractMessagingProviderTest.java new file mode 100644 index 0000000..b6d14f5 --- /dev/null +++ b/src/test/java/no/difi/oxalis/as4/outbound/AbstractMessagingProviderTest.java @@ -0,0 +1,228 @@ +package no.difi.oxalis.as4.outbound; + +import io.opentracing.noop.NoopTracerFactory; +import no.difi.oxalis.api.outbound.TransmissionMessage; +import no.difi.oxalis.api.outbound.TransmissionRequest; +import no.difi.oxalis.as4.common.DefaultMessageIdGenerator; +import no.difi.oxalis.as4.util.PeppolConfiguration; +import no.difi.oxalis.commons.header.SbdhHeaderParser; +import no.difi.oxalis.commons.tag.NoopTagGenerator; +import no.difi.oxalis.commons.transformer.NoopContentDetector; +import no.difi.oxalis.commons.transformer.NoopContentWrapper; +import no.difi.oxalis.outbound.transmission.DefaultTransmissionRequestFacade; +import no.difi.oxalis.outbound.transmission.MessagingProviderFacade; +import no.difi.oxalis.outbound.transmission.TransmissionRequestFactory; +import no.difi.vefa.peppol.common.model.Endpoint; +import no.difi.vefa.peppol.common.model.TransportProfile; +import org.apache.cxf.attachment.AttachmentUtil; +import org.apache.cxf.message.Attachment; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; +import org.oasis_open.docs.ebxml_msg.ebms.v3_0.ns.core._200704.Messaging; +import org.oasis_open.docs.ebxml_msg.ebms.v3_0.ns.core._200704.Property; +import org.oasis_open.docs.ebxml_msg.ebms.v3_0.ns.core._200704.Service; +import org.oasis_open.docs.ebxml_msg.ebms.v3_0.ns.core._200704.UserMessage; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import javax.xml.datatype.XMLGregorianCalendar; +import java.io.InputStream; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.cert.X509Certificate; +import java.util.*; + +public abstract class AbstractMessagingProviderTest { + + private static final String Content_ID_KEY = "Content-ID"; + private static final String Content_ID_VALUE = "payloadId"; + private static final String COMPRESSION_TYPE_KEY = "CompressionType"; + private static final String COMPRESSION_TYPE_VALUE = "application/gzip"; + private static final String MIME_TYPE_KEY = "MimeType"; + private static final String MIME_TYPE_VALUE = "application/xml"; + private static final String SENDER = "OxalisSender"; + private static final String RECEIVER = "OxalisReceiver"; + private static final String TO_ROLE = "http://docs.oasis-open.org/ebxml-msg/ebms/v3.0/ns/core/200704/responder"; + private static final String FROM_ROLE = "http://docs.oasis-open.org/ebxml-msg/ebms/v3.0/ns/core/200704/initiator"; + + private final String ACTION = getAction(); + private final String SERVICE_TYPE = getServiceType(); + private final String SERVICE_VALUE = getServiceValue(); + private final String PARTY_TYPE = getPartyType(); + + private final String FINAL_RECIPIENT = getFinalRecipient(); + private final String ORIGINAL_SENDER = getOriginalSender(); + + + private MessagingProviderFacade messagingProvider; + private X509Certificate senderCert; + private X509Certificate receiverCert; + + + protected abstract String getPayloadPath(); + + protected abstract PeppolConfiguration getPEPPOLOutboundConfiguration(); + + protected abstract String getAction(); + protected abstract String getServiceType(); + protected abstract String getServiceValue(); + protected abstract String getPartyType(); + protected abstract String getFinalRecipient(); + protected abstract String getOriginalSender(); + + + @BeforeClass + public void beforeClass() throws Exception { + + senderCert = generateSelfSignedCertificate("CN=" + SENDER + ",O=Difi,L=Oslo,C=NO"); + receiverCert = generateSelfSignedCertificate("CN=" + RECEIVER + ",O=Difi,L=Oslo,C=NO"); + + messagingProvider = new MessagingProviderFacade( + senderCert, + new DefaultMessageIdGenerator("test"), + getPEPPOLOutboundConfiguration()); + } + + + + @Test + public void testCreateMessagingHeader() throws Exception { + + TransmissionRequestFactory transmissionRequestFactory = new TransmissionRequestFactory( + new NoopContentDetector(), + new NoopContentWrapper(), + new NoopTagGenerator(), + new SbdhHeaderParser(), + NoopTracerFactory.create() + ); + + TransmissionMessage transmissionMessage; + try (InputStream inputStream = getClass().getResourceAsStream(getPayloadPath())) { + transmissionMessage = transmissionRequestFactory.newInstance(inputStream); + } + + + Assert.assertNotNull(transmissionMessage.getHeader()); + + TransmissionRequest transmissionRequest = new DefaultTransmissionRequestFacade( + transmissionMessage, + Endpoint.of(TransportProfile.PEPPOL_AS2_2_0, null, receiverCert) + ); + + HashMap> headers = new HashMap<>(); + headers.put(Content_ID_KEY, Collections.singletonList(Content_ID_VALUE)); + headers.put(COMPRESSION_TYPE_KEY, Collections.singletonList(COMPRESSION_TYPE_VALUE)); + headers.put(MIME_TYPE_KEY, Collections.singletonList(MIME_TYPE_VALUE)); + + Attachment attachment = AttachmentUtil.createAttachment(transmissionRequest.getPayload(), headers); + + Messaging messaging = messagingProvider.createMessagingHeader( + transmissionRequest , new ArrayList<>(Arrays.asList(attachment)) + ); + + UserMessage userMessage = messaging.getUserMessage().get(0); + + // MessageInfo + XMLGregorianCalendar timestamp = userMessage.getMessageInfo().getTimestamp(); + String messageId = userMessage.getMessageInfo().getMessageId(); + + Assert.assertNotNull(timestamp); + Assert.assertNotNull(messageId); + + + // PartyInfo + String to = userMessage.getPartyInfo().getTo().getPartyId().get(0).getValue(); + String toType = userMessage.getPartyInfo().getTo().getPartyId().get(0).getType(); + String toRole = userMessage.getPartyInfo().getTo().getRole(); + String from = userMessage.getPartyInfo().getFrom().getPartyId().get(0).getValue(); + String fromType = userMessage.getPartyInfo().getFrom().getPartyId().get(0).getType(); + String fromRole = userMessage.getPartyInfo().getFrom().getRole(); + + Assert.assertEquals(to, RECEIVER); + Assert.assertEquals(toType, PARTY_TYPE); + Assert.assertEquals(toRole, TO_ROLE); + Assert.assertEquals(from, SENDER); + Assert.assertEquals(fromType, PARTY_TYPE); + Assert.assertEquals(fromRole, FROM_ROLE); + + + // CollaborationInfo + String action = userMessage.getCollaborationInfo().getAction(); + Service service = userMessage.getCollaborationInfo().getService(); + String conversationId = userMessage.getCollaborationInfo().getConversationId(); + + Assert.assertEquals(action, ACTION); + Assert.assertEquals(service.getType(), SERVICE_TYPE); + Assert.assertEquals(service.getValue(), SERVICE_VALUE); + Assert.assertNotNull(conversationId); + + + // MessageProperties + String finalRecipient = userMessage.getMessageProperties().getProperty().stream() + .filter(p -> "finalRecipient".equalsIgnoreCase(p.getName())) + .map(Property::getValue) + .findFirst() + .get(); + String originalSender = userMessage.getMessageProperties().getProperty().stream() + .filter(p -> "originalSender".equalsIgnoreCase(p.getName())) + .map(Property::getValue) + .findFirst() + .get(); + + Assert.assertEquals(finalRecipient, FINAL_RECIPIENT); + Assert.assertEquals(originalSender, ORIGINAL_SENDER); + + + // PayloadInfo + int payloadCount = userMessage.getPayloadInfo().getPartInfo().size(); + Assert.assertEquals(payloadCount, 1); + + List partInfo = userMessage.getPayloadInfo().getPartInfo().get(0).getPartProperties().getProperty(); + String compressionType = partInfo.stream() + .filter(pi -> COMPRESSION_TYPE_KEY.equalsIgnoreCase(pi.getName())) + .map(Property::getValue) + .findFirst() + .get(); + String mimeType = partInfo.stream() + .filter(pi -> MIME_TYPE_KEY.equalsIgnoreCase(pi.getName())) + .map(Property::getValue) + .findFirst() + .get(); + String contentID = userMessage.getPayloadInfo().getPartInfo().get(0).getHref(); + + Assert.assertEquals(compressionType, COMPRESSION_TYPE_VALUE); + Assert.assertEquals(mimeType, MIME_TYPE_VALUE); + Assert.assertEquals(contentID, "cid:" + Content_ID_VALUE); + } + + public static X509Certificate generateSelfSignedCertificate(String subjectDN) throws Exception + { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(512); + KeyPair kp = keyPairGenerator.generateKeyPair(); + + + X500Name dnName = new X500Name(subjectDN); + BigInteger certSerialNumber = new BigInteger(Long.toString(System.currentTimeMillis())); + + + Date startDate = new Date(); + Calendar calendar = Calendar.getInstance(); + calendar.setTime(startDate); + calendar.add(Calendar.YEAR, 1); // <-- 1 Yr validity + + Date endDate = calendar.getTime(); + + JcaX509v3CertificateBuilder cb = new JcaX509v3CertificateBuilder(dnName, certSerialNumber, startDate, endDate, dnName, kp.getPublic()); + + ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256WithRSA").build(kp.getPrivate()); + + + return new JcaX509CertificateConverter().getCertificate(cb.build(contentSigner)); + } +} diff --git a/src/test/java/no/difi/oxalis/as4/outbound/MessagingProviderTest_CEF_SBDH.java b/src/test/java/no/difi/oxalis/as4/outbound/MessagingProviderTest_CEF_SBDH.java new file mode 100644 index 0000000..9b19e3d --- /dev/null +++ b/src/test/java/no/difi/oxalis/as4/outbound/MessagingProviderTest_CEF_SBDH.java @@ -0,0 +1,72 @@ +package no.difi.oxalis.as4.outbound; + +import no.difi.oxalis.api.settings.Settings; +import no.difi.oxalis.as4.config.As4Conf; +import no.difi.oxalis.as4.util.PeppolConfiguration; + +import javax.inject.Named; +import java.nio.file.Path; + +public class MessagingProviderTest_CEF_SBDH extends AbstractMessagingProviderTest { + + @Override + protected String getPayloadPath() { + return "/cef-sbd.xml"; + } + + @Override + protected PeppolConfiguration getPEPPOLOutboundConfiguration() { + + return new As4OutboundModule().getPeppolOutboundConfiguration(new Settings(){ + @Override + public String getString(As4Conf as4Conf) { + return "cef-connectivity"; + } + + @Override + public int getInt(As4Conf as4Conf) { + return 0; + } + + @Override + public Named getNamed(As4Conf key) { + return null; + } + + @Override + public Path getPath(As4Conf key, Path path) { + return null; + } + }); + } + + @Override + protected String getAction() { + return "submitMessage"; + } + + @Override + protected String getServiceType() { + return "e-delivery"; + } + + @Override + protected String getServiceValue() { + return "http://ec.europa.eu/edelivery/services/connectivity-service"; + } + + @Override + protected String getPartyType() { + return "urn:oasis:names:tc:ebcore:partyid-type:unregistered"; + } + + @Override + protected String getFinalRecipient() { + return "urn:oasis:names:tc:ebcore:partyid-type:unregistered:c4"; + } + + @Override + protected String getOriginalSender() { + return "urn:oasis:names:tc:ebcore:partyid-type:unregistered:c1"; + } +} diff --git a/src/test/java/no/difi/oxalis/as4/outbound/MessagingProviderTest_SIMPLE_SBDH.java b/src/test/java/no/difi/oxalis/as4/outbound/MessagingProviderTest_SIMPLE_SBDH.java new file mode 100644 index 0000000..561d4e6 --- /dev/null +++ b/src/test/java/no/difi/oxalis/as4/outbound/MessagingProviderTest_SIMPLE_SBDH.java @@ -0,0 +1,47 @@ +package no.difi.oxalis.as4.outbound; + +import no.difi.oxalis.as4.util.PeppolConfiguration; + +public class MessagingProviderTest_SIMPLE_SBDH extends AbstractMessagingProviderTest { + + @Override + protected String getPayloadPath() { + return "/simple-sbd.xml"; + } + + @Override + protected PeppolConfiguration getPEPPOLOutboundConfiguration() { + + return new PeppolConfiguration(); + } + + @Override + protected String getAction() { + return "busdox-docid-qns::urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:www.cenbii.eu:transaction:biitrns010:ver2.0:extended:urn:www.peppol.eu:bis:peppol4a:ver2.0::2.1"; + } + + @Override + protected String getServiceType() { + return "cenbii-procid-ubl"; + } + + @Override + protected String getServiceValue() { + return "urn:www.cenbii.eu:profile:bii04:ver2.0"; + } + + @Override + protected String getPartyType() { + return "urn:fdc:peppol.eu:2017:identifiers:ap"; + } + + @Override + protected String getFinalRecipient() { + return "iso6523-actorid-upis::9908:810418052"; + } + + @Override + protected String getOriginalSender() { + return "iso6523-actorid-upis::0088:oxalis"; + } +} diff --git a/src/test/java/no/difi/oxalis/as4/util/TransmissionRequestUtilTest.java b/src/test/java/no/difi/oxalis/as4/util/TransmissionRequestUtilTest.java new file mode 100644 index 0000000..df45151 --- /dev/null +++ b/src/test/java/no/difi/oxalis/as4/util/TransmissionRequestUtilTest.java @@ -0,0 +1,53 @@ +package no.difi.oxalis.as4.util; + +import no.difi.vefa.peppol.common.model.DocumentTypeIdentifier; +import no.difi.vefa.peppol.common.model.ParticipantIdentifier; +import no.difi.vefa.peppol.common.model.ProcessIdentifier; +import no.difi.vefa.peppol.common.model.Scheme; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class TransmissionRequestUtilTest { + + private static String PROVIDED_VALUE = "provided value"; + private static String PROVIDED_SCHEME = "provided scheme"; + + @Test + public void testTranslateDocumentTypeToAction_defaultScheme() { + String result = TransmissionRequestUtil.translateDocumentTypeToAction( DocumentTypeIdentifier.of(PROVIDED_VALUE) ); + Assert.assertEquals(DocumentTypeIdentifier.DEFAULT_SCHEME + "::" + PROVIDED_VALUE, result); + } + + @Test + public void testTranslateDocumentTypeToAction_nullScheme() { + String result = TransmissionRequestUtil.translateDocumentTypeToAction( DocumentTypeIdentifier.of(PROVIDED_VALUE, null) ); + Assert.assertEquals(PROVIDED_VALUE, result); + } + + @Test + public void testTranslateDocumentTypeToAction_providedScheme() { + String result = TransmissionRequestUtil.translateDocumentTypeToAction( DocumentTypeIdentifier.of(PROVIDED_VALUE, Scheme.of(PROVIDED_SCHEME)) ); + Assert.assertEquals(PROVIDED_SCHEME + "::" + PROVIDED_VALUE, result); + } + + + + @Test + public void testTranslateParticipantIdentifierToRecipient_defaultScheme() { + String result = TransmissionRequestUtil.translateParticipantIdentifierToRecipient( ParticipantIdentifier.of(PROVIDED_VALUE) ); + Assert.assertEquals(ParticipantIdentifier.DEFAULT_SCHEME + "::" + PROVIDED_VALUE, result); + } + + @Test + public void testTranslateParticipantIdentifierToRecipient_nullScheme() { + String result = TransmissionRequestUtil.translateParticipantIdentifierToRecipient( ParticipantIdentifier.of(PROVIDED_VALUE, null) ); + Assert.assertEquals(PROVIDED_VALUE, result); + } + + @Test + public void testTranslateParticipantIdentifierToRecipient_providedScheme() { + String result = TransmissionRequestUtil.translateParticipantIdentifierToRecipient( ParticipantIdentifier.of(PROVIDED_VALUE, Scheme.of(PROVIDED_SCHEME)) ); + Assert.assertEquals(PROVIDED_SCHEME + "::" + PROVIDED_VALUE, result); + } + +} diff --git a/src/test/java/no/difi/oxalis/outbound/transmission/DefaultTransmissionRequestFacade.java b/src/test/java/no/difi/oxalis/outbound/transmission/DefaultTransmissionRequestFacade.java new file mode 100644 index 0000000..cfcdd9c --- /dev/null +++ b/src/test/java/no/difi/oxalis/outbound/transmission/DefaultTransmissionRequestFacade.java @@ -0,0 +1,41 @@ +package no.difi.oxalis.outbound.transmission; + +import no.difi.oxalis.api.outbound.TransmissionMessage; +import no.difi.oxalis.api.outbound.TransmissionRequest; +import no.difi.oxalis.api.tag.Tag; +import no.difi.vefa.peppol.common.model.Endpoint; +import no.difi.vefa.peppol.common.model.Header; + +import java.io.InputStream; +import java.io.Serializable; + +public class DefaultTransmissionRequestFacade implements TransmissionRequest, Serializable { + + private static final long serialVersionUID = -4542158937465140099L; + + private DefaultTransmissionRequest defaultTransmissionRequest; + + public DefaultTransmissionRequestFacade(TransmissionMessage transmissionMessage, Endpoint endpoint) { + defaultTransmissionRequest = new DefaultTransmissionRequest(transmissionMessage, endpoint); + } + + @Override + public Endpoint getEndpoint() { + return defaultTransmissionRequest.getEndpoint(); + } + + @Override + public Header getHeader() { + return defaultTransmissionRequest.getHeader(); + } + + @Override + public InputStream getPayload() { + return defaultTransmissionRequest.getPayload(); + } + + @Override + public Tag getTag() { + return defaultTransmissionRequest.getTag(); + } +} diff --git a/src/test/java/no/difi/oxalis/outbound/transmission/MessagingProviderFacade.java b/src/test/java/no/difi/oxalis/outbound/transmission/MessagingProviderFacade.java new file mode 100644 index 0000000..bfd05e6 --- /dev/null +++ b/src/test/java/no/difi/oxalis/outbound/transmission/MessagingProviderFacade.java @@ -0,0 +1,29 @@ +package no.difi.oxalis.outbound.transmission; + +import no.difi.oxalis.api.outbound.TransmissionRequest; +import no.difi.oxalis.as4.api.MessageIdGenerator; +import no.difi.oxalis.as4.lang.OxalisAs4TransmissionException; +import no.difi.oxalis.as4.outbound.MessagingProvider; +import no.difi.oxalis.as4.util.PeppolConfiguration; +import org.apache.cxf.message.Attachment; +import org.oasis_open.docs.ebxml_msg.ebms.v3_0.ns.core._200704.Messaging; + +import java.security.cert.X509Certificate; +import java.util.Collection; + +public class MessagingProviderFacade { + + private MessagingProvider messagingProvider; + + public MessagingProviderFacade(X509Certificate senderCert, MessageIdGenerator messageIdGenerator, PeppolConfiguration peppolConfiguration) { + messagingProvider = new MessagingProvider( + senderCert, + messageIdGenerator, + peppolConfiguration + ); + } + + public Messaging createMessagingHeader(TransmissionRequest request, Collection attachments) throws OxalisAs4TransmissionException { + return messagingProvider.createMessagingHeader(request, attachments); + } +} diff --git a/src/test/resources/cef-sbd.xml b/src/test/resources/cef-sbd.xml new file mode 100644 index 0000000..1e64f62 --- /dev/null +++ b/src/test/resources/cef-sbd.xml @@ -0,0 +1,49 @@ + + + + 1.0 + + + + urn:oasis:names:tc:ebcore:partyid-type:unregistered:C1 + + + + + urn:oasis:names:tc:ebcore:partyid-type:unregistered:C4 + + + + + + NONE + 1.0 + 555bcb4c-940b-4694-9b90-d9b0ae1e937b + CEF Connectivity test + 2019-10-30T11:20:05.304+02:00 + + + + + + + DOCUMENTID + + + + submitMessage + + + + + + PROCESSID + + e-delivery + + http://ec.europa.eu/edelivery/services/connectivity-service + + + + eDelivery AS4 Connectivity test. Sending Message + \ No newline at end of file