Skip to content

Testing Without Peppol Network

Philip Helger edited this page May 21, 2026 · 1 revision

Testing Without the Peppol Network

This page describes how to operate phoss AP for local or closed-circle testing — that is, without joining the official Peppol network (SML) and without performing live exchanges against real Peppol Service Providers.

A related guide for phase4 (the underlying AS4 engine) is available at phase4 Testing. phoss AP adds two constraints on top of phase4 that change the picture: a mandatory startup-time AP certificate chain check, and a mandatory SMP lookup for every outbound transaction.

Can phoss AP run without a Peppol-issued AP certificate?

No — not with the current configuration surface. phoss AP enforces two hard checks that reject any AP certificate that does not chain to one of the official Peppol CAs:

  • At startup, the configured AP certificate is verified against PeppolTrustedCA.peppolProductionAP() or PeppolTrustedCA.peppolTestAP() (depending on peppol.stage). A self-signed certificate causes startup to fail with InitializationException (APServletInit.java#L271-L280).
  • On every outbound transmission, the remote AP certificate returned by the SMP is checked against the same Peppol CA set (OutboundOrchestrator.java#L666-L667).

This is different from raw phase4, where the receiver-side check can be disabled per send.

The closest practical setup is therefore: use Peppol Test AP certificates on both ends (these are issued during the regular Peppol onboarding/testbed process) and replace the network — SML, SMP, and trust roots for SMP signatures — with components you control. The rest of this page describes that setup.

Can the SMP lookup on outbound be skipped?

No. All outbound submission endpoints (POST /api/outbound/submit/..., POST /api/outbound/submit-sbd, POST /api/outbound/submit-s3) funnel into OutboundOrchestrator.processPendingOutbound(), which always performs NAPTR/SMP lookup before the AS4 send. There is no parameter to inject a pre-resolved endpoint URL and AP certificate.

For local testing this means a local SMP instance is required. The simplest option is phoss SMP, which can be run locally and configured to publish your test participant.

Required components for a closed-circle test setup

For a two-instance test (Instance A sending to Instance B) you need:

  1. Two Peppol Test AP certificates — one per AP instance. These are the standard certificates issued by the Peppol PKI for the Test environment.
  2. A local SMP (e.g. phoss SMP) that:
    • Publishes service group entries for the test participants you want to exchange messages between.
    • Returns the URL and AP certificate of the receiving AP instance.
    • Signs SMP responses with a key whose CA you control (this can be self-signed since the trust anchor is configurable — see below).
  3. A custom SMP truststore (.p12 / .jks) containing the CA that signs your local SMP's responses.
  4. DNS resolution for the participants — either by registering them in a Peppol SML test instance (most realistic), or by directing peppol.dns.servers to a DNS server you control that answers NAPTR queries for your participants.

Configuration on each AP instance

Peppol stage and AP keystore

# Must stay 'test' — 'prod' would require Production AP certificates
peppol.stage=test

# AP keystore — your Peppol Test AP certificate
org.apache.wss4j.crypto.merlin.keystore.type=pkcs12
org.apache.wss4j.crypto.merlin.keystore.file=keystore/your-test-ap.p12
org.apache.wss4j.crypto.merlin.keystore.password=...
org.apache.wss4j.crypto.merlin.keystore.alias=...
org.apache.wss4j.crypto.merlin.keystore.private.password=...

# AP truststore — keep the standard Peppol Test AP truststore.
# The other instance's AP certificate must also chain to the Peppol Test AP CA,
# so the bundled truststore already covers it.
org.apache.wss4j.crypto.merlin.truststore.type=pkcs12
org.apache.wss4j.crypto.merlin.truststore.file=truststore/2025/ap-test-truststore.p12
org.apache.wss4j.crypto.merlin.truststore.password=peppol

SMP client — point at your local SMP

The SMP signature is verified against the truststore configured via smpclient.truststore.path. Replace the bundled Peppol Test SMP truststore with a custom truststore containing the CA that signs your local SMP:

smpclient.truststore.type=PKCS12
smpclient.truststore.path=keystore/local-smp-truststore.p12
smpclient.truststore.password=...

Note: the AP certificate returned in the SMP response is still validated against PeppolTrustedCA.peppolTestAP() — i.e., the remote AP certificate the SMP publishes must be a real Peppol Test AP certificate. You can swap the SMP signer freely, but you cannot swap the remote AP CA.

Receiver check mode (inbound only)

The inbound SMP cross-check verifies that this AP is actually registered for the inbound receiver. For a closed-circle test where DNS/SML may not list your participants, set:

peppol.receiver-check.mode=none

This disables the inbound SMP lookup; the AP will accept any inbound AS4 message whose signature is valid against the AP truststore and whose receiver participant is well-formed. Acceptable for testing — see Security Considerations before using anywhere else.

Alternatively, point the check at your local SMP:

peppol.receiver-check.mode=smp
peppol.smp.url=http://localhost:8080
phase4.endpoint.address=https://your-ap.example.com/as4

DNS for NAPTR resolution

If your local SMP is not registered in a real SML, outbound NAPTR lookups will fail. Either:

  • Point peppol.dns.servers at a private DNS server that publishes the NAPTR records pointing to your local SMP, or
  • Register the test participants in a Peppol SML test instance (the same SML you would use for testbed onboarding).
peppol.dns.servers=10.0.0.53

Send-only or receive-only modes

If a given instance only needs to play one role, disable the other side to remove unused configuration:

# Receive-only AP (no outbound) — avoids needing an SMP for outbound at all
peppol.sending.enabled=false

# Send-only AP (no inbound)
peppol.receiving.enabled=false

A receive-only AP avoids the outbound SMP lookup entirely, which makes it the simplest configuration to validate inbound AS4 reception against a sender you control.

Minimum viable test flows

Flow 1: receive-only AP, sender is plain phase4

The least amount of moving parts. Use phase4 as the sender (where checkReceiverAPCertificate(false) and .receiverEndpointDetails(cert, url) allow bypassing SMP entirely), and phoss AP as a receive-only endpoint.

  • Configure phoss AP with peppol.sending.enabled=false and peppol.receiver-check.mode=none.
  • phase4 sender connects directly to the AP's /as4 endpoint with the AP's public Peppol Test certificate.

Flow 2: two phoss AP instances + one local SMP

Full bidirectional flow.

  • Two instances, each with its own Peppol Test AP certificate.
  • One local SMP publishing both participants and pointing each participant at the correct AP's phase4.endpoint.address.
  • Both instances configured with smpclient.truststore.path pointing at the truststore containing the local SMP's signing CA.
  • peppol.receiver-check.mode=none (or smp pointed at the local SMP).
  • peppol.dns.servers pointed at a DNS server that resolves the participants' NAPTR records to the local SMP — or use a real test SML.

What does not work

  • Self-signed AP certificates. Startup fails.
  • Sending without an SMP. There is no API parameter to provide a pre-resolved endpoint URL + remote AP certificate. Every outbound transaction performs SMP/NAPTR lookup.
  • Outbound to a counterparty whose AP certificate is not Peppol-issued. The check at OutboundOrchestrator.java:666-667 rejects the remote certificate even if your SMP returns it.

Related pages

Clone this wiki locally