├── .dockerignore
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.yml
│ ├── config.yml
│ └── feature_request.yml
└── workflows
│ ├── build-docker.yml
│ ├── codeql-analysis.yml
│ ├── maven.yml
│ ├── publish-docker.yml
│ └── release.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Dockerfile
├── README.md
├── SECURITY.md
├── docs
├── CEF-connectivity.md
├── cef-connectivity
│ └── index.md
├── img
│ ├── cef_static_discovery_form.PNG
│ ├── peppol_testbed1.PNG
│ ├── peppol_testbed2.PNG
│ ├── peppol_testbed3.PNG
│ ├── peppol_testbed4.PNG
│ ├── peppol_testbed5.PNG
│ ├── peppol_testbed6.PNG
│ ├── peppol_testbed7.PNG
│ ├── peppol_testbed8.PNG
│ ├── tomcat_folder.PNG
│ └── tomcat_oxalis_folder.PNG
├── installation
│ ├── index.md
│ ├── server.md
│ ├── standalone.md
│ └── tomcat.md
└── peppol-test-bed
│ └── index.md
├── hooks
└── post_push
├── pom.xml
├── pull_request_template.md
└── src
├── main
├── assembly
│ ├── assembly-dist-zip.xml
│ └── assembly-dist.xml
├── java
│ ├── network
│ │ └── oxalis
│ │ │ └── as4
│ │ │ ├── api
│ │ │ └── MessageIdGenerator.java
│ │ │ ├── common
│ │ │ ├── AS4Constants.java
│ │ │ ├── As4CommonModule.java
│ │ │ ├── As4MessageProperties.java
│ │ │ ├── As4MessageProperty.java
│ │ │ ├── DefaultMessageIdGenerator.java
│ │ │ ├── DummyHeaderParser.java
│ │ │ └── MerlinProvider.java
│ │ │ ├── config
│ │ │ └── As4Conf.java
│ │ │ ├── inbound
│ │ │ ├── AS4MessageContextKey.java
│ │ │ ├── AS4StatusServlet.java
│ │ │ ├── AbstractSetPolicyInterceptor.java
│ │ │ ├── As4EndpointSelector.java
│ │ │ ├── As4EndpointsPublisher.java
│ │ │ ├── As4EndpointsPublisherImpl.java
│ │ │ ├── As4EnvelopeHeader.java
│ │ │ ├── As4FaultInHandler.java
│ │ │ ├── As4InboundHandler.java
│ │ │ ├── As4InboundMetadata.java
│ │ │ ├── As4InboundModule.java
│ │ │ ├── As4Interceptor.java
│ │ │ ├── As4PayloadHeader.java
│ │ │ ├── As4Provider.java
│ │ │ ├── As4Servlet.java
│ │ │ ├── AttachmentCleanupInterceptor.java
│ │ │ ├── MessagingHandler.java
│ │ │ ├── OxalisAS4Version.java
│ │ │ ├── ProsessingContext.java
│ │ │ ├── SetPolicyInInterceptor.java
│ │ │ └── SetPolicyOutInterceptor.java
│ │ │ ├── lang
│ │ │ ├── AS4Error.java
│ │ │ ├── OxalisAs4Exception.java
│ │ │ └── OxalisAs4TransmissionException.java
│ │ │ ├── outbound
│ │ │ ├── ActionProvider.java
│ │ │ ├── As4MessageSender.java
│ │ │ ├── As4MessageSenderFacade.java
│ │ │ ├── As4OutboundModule.java
│ │ │ ├── As4TransmissionRequest.java
│ │ │ ├── As4TransmissionResponse.java
│ │ │ ├── BrowserTypeProvider.java
│ │ │ ├── DefaultActionProvider.java
│ │ │ ├── LoggingBeforeSecurityInInterceptor.java
│ │ │ ├── MessagingProvider.java
│ │ │ └── TransmissionResponseConverter.java
│ │ │ └── util
│ │ │ ├── AS4ErrorCode.java
│ │ │ ├── As4MessageFactory.java
│ │ │ ├── CompressionUtil.java
│ │ │ ├── Constants.java
│ │ │ ├── GeneralUtils.java
│ │ │ ├── InputStreamDataSource.java
│ │ │ ├── Marshalling.java
│ │ │ ├── MessageId.java
│ │ │ ├── MessageIdUtil.java
│ │ │ ├── OxalisAlgorithmSuiteLoader.java
│ │ │ ├── PeppolConfiguration.java
│ │ │ ├── PolicyService.java
│ │ │ ├── SOAPHeaderParser.java
│ │ │ ├── TransmissionRequestUtil.java
│ │ │ └── XMLUtil.java
│ └── org
│ │ └── apache
│ │ └── cxf
│ │ └── attachment
│ │ ├── As4AttachmentDataSource.java
│ │ ├── As4AttachmentDeserializer.java
│ │ ├── As4AttachmentImpl.java
│ │ ├── As4AttachmentInInterceptor.java
│ │ ├── As4AttachmentUtil.java
│ │ ├── As4DelegatingInputStream.java
│ │ └── As4LazyAttachmentCollection.java
├── resources
│ ├── META-INF
│ │ └── javax.xml.ws.spi.Provider
│ ├── eDeliveryAS4Policy.xml
│ ├── eDeliveryAS4Policy_BST.xml
│ ├── oxalis-as4-version.properties
│ ├── reference.conf
│ └── signOnly.xml
└── xsd
│ ├── bindings.xml
│ ├── ebxml
│ ├── ebbp-signals-2.0.xsd
│ └── ebms-header-3_0-200704.xsd
│ ├── w3
│ ├── XMLSchema.dtd
│ ├── datatypes.dtd
│ ├── soap-envelope.xsd
│ ├── xlink.xsd
│ ├── xml.xsd
│ └── xmldsig-core-schema.xsd
│ └── xmlsoap
│ └── envelope.xsd
└── test
├── java
└── network
│ └── oxalis
│ ├── as4
│ ├── SendReceiveTest.java
│ ├── common
│ │ └── DefaultMessageIdGeneratorTest.java
│ ├── inbound
│ │ ├── AS4StatusServletTest.java
│ │ ├── As4InboundHandlerTest.java
│ │ └── As4ServletTest.java
│ ├── outbound
│ │ ├── AbstractMessagingProviderTest.java
│ │ ├── MessagingProviderTest_CEF_SBDH.java
│ │ └── MessagingProviderTest_SIMPLE_SBDH.java
│ └── util
│ │ ├── AS4ErrorCodeTest.java
│ │ ├── CompressionUtilTest.java
│ │ ├── MessageIdUtilTest.java
│ │ └── TransmissionRequestUtilTest.java
│ └── outbound
│ └── transmission
│ ├── DefaultTransmissionRequestFacade.java
│ └── MessagingProviderFacade.java
└── resources
├── as2-peppol-bis-invoice-sbdh.xml
├── cef-sbd.xml
├── logback-test.xml
├── oxalis_home
├── eutest_gateway_truststore.jks
├── fake-oxalis.conf
└── peppol_trust_g2_and_g3.jks
├── reference.conf
└── simple-sbd.xml
/.dockerignore:
--------------------------------------------------------------------------------
1 | target
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.yml:
--------------------------------------------------------------------------------
1 | name: Bug report
2 | description: Create a bug report to help us improve
3 | labels:
4 | - kind/bug
5 | - status/0-triage
6 | body:
7 | - type: markdown
8 | attributes:
9 | value: |
10 | Thank you for taking the time to report a bug...
11 | If this is a security issue please report it to the [oxalis@norstella.no](mailto:oxalis@norstella.no).
12 | - type: textarea
13 | id: description
14 | attributes:
15 | label: Description
16 | description: Please give a clear and concise description of the bug
17 | validations:
18 | required: true
19 | - type: textarea
20 | id: repro
21 | attributes:
22 | label: Reproduce
23 | description: Please list steps to reproduce the bug
24 | placeholder: |
25 | 1. ...
26 | 2. ...
27 | 3. ...
28 | validations:
29 | required: true
30 | - type: textarea
31 | id: expected
32 | attributes:
33 | label: Expected behavior
34 | description: What is the expected behavior?
35 | placeholder: |
36 | E.g. "...."
37 | - type: textarea
38 | id: Oxalis-AS4-version
39 | attributes:
40 | label: Oxalis-AS4 version
41 | description: Mention Oxalis-AS4 version
42 | render: bash
43 | placeholder: |
44 | E.g. "...."
45 | validations:
46 | required: true
47 | - type: textarea
48 | id: JDK-version
49 | attributes:
50 | label: JDK version
51 | description: JDK version where Oxalis-AS4 is running
52 | render: bash
53 | placeholder: |
54 | E.g. "...."
55 | validations:
56 | required: true
57 | - type: textarea
58 | id: additional
59 | attributes:
60 | label: Additional Info
61 | description: Additional info you want to provide such as logs, system info, environment, etc.
62 | validations:
63 | required: false
64 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: Security and Vulnerabilities
4 | url: https://github.com/OxalisCommunity/oxalis-as4/blob/master/SECURITY.md
5 | about: Please report any security issues or vulnerabilities responsibly to the Oxalis Community team. Please do not use the public issue tracker.
6 | - name: Questions and Discussions
7 | url: https://github.com/OxalisCommunity/oxalis-as4/discussions/new
8 | about: Use Github Discussions to ask questions and/or open discussion topics.
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yml:
--------------------------------------------------------------------------------
1 | name: Feature request
2 | description: Missing functionality? Come tell us about it!
3 | labels:
4 | - kind/feature
5 | - status/0-triage
6 | body:
7 | - type: textarea
8 | id: problem-description
9 | attributes:
10 | label: Description
11 | description: A clear and concise description of the feature you want to see?
12 | validations:
13 | required: true
14 | - type: textarea
15 | id: alternative-considered
16 | attributes:
17 | label: Description considered, if any?
18 | description: A clear and concise description of any alternative solutions or features you've considered.
19 | validations:
20 | required: false
21 | - type: textarea
22 | id: additional-context
23 | attributes:
24 | label: Additional context
25 | description: Additional info you want to provide.
26 | validations:
27 | required: false
--------------------------------------------------------------------------------
/.github/workflows/build-docker.yml:
--------------------------------------------------------------------------------
1 | name: Publish to Docker hub
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v4
10 |
11 | - name: Set up QEMU
12 | uses: docker/setup-qemu-action@v1
13 | with:
14 | platforms: all
15 |
16 | - name: Set up Docker Buildx
17 | id: buildx
18 | uses: docker/setup-buildx-action@v1
19 |
20 | - name: Cache Docker layers
21 | uses: actions/cache@v4
22 | with:
23 | path: /tmp/.buildx-cache
24 | key: ${{ runner.os }}-buildx-${{ github.sha }}
25 | restore-keys: |
26 | ${{ runner.os }}-buildx-
27 | - name: Login to DockerHub
28 | if: github.event_name != 'pull_request'
29 | uses: docker/login-action@v1
30 | with:
31 | username: ${{ secrets.DOCKER_HUB_USERNAME }}
32 | password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
33 |
34 | - name: Build and push
35 | id: docker_build
36 | uses: docker/build-push-action@v2
37 | with:
38 | builder: ${{ steps.buildx.outputs.name }}
39 | context: ./
40 | file: ./Dockerfile
41 | platforms: linux/amd64,linux/arm64/v8
42 | push: true
43 | tags: norstella/oxalis-as4:7.2.0-RC4-latest
44 | cache-from: type=local,src=/tmp/.buildx-cache
45 | cache-to: type=local,dest=/tmp/.buildx-cache
46 |
47 | - name: Image digest
48 | run: echo ${{ steps.docker_build.outputs.digest }}
49 |
50 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | #
7 | # ******** NOTE ********
8 | # We have attempted to detect the languages in your repository. Please check
9 | # the `language` matrix defined below to confirm you have the correct set of
10 | # supported CodeQL languages.
11 | #
12 |
13 | name: "CodeQL Analyss for Oxalis AS4"
14 |
15 | on:
16 | push:
17 | branches: [ "master" ]
18 | pull_request:
19 | # The branches below must be a subset of the branches above
20 | branches: [ "master" ]
21 | schedule:
22 | - cron: '19 6 * * 0'
23 |
24 | jobs:
25 | analyze:
26 | name: Analyze
27 | runs-on: ubuntu-latest
28 | permissions:
29 | actions: read
30 | contents: read
31 | security-events: write
32 |
33 | strategy:
34 | fail-fast: false
35 | matrix:
36 | language: [ 'java' ]
37 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
38 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
39 |
40 | steps:
41 | - name: Checkout repository
42 | uses: actions/checkout@v3
43 |
44 | # Initializes the CodeQL tools for scanning.
45 | - name: Initialize CodeQL
46 | uses: github/codeql-action/init@v2
47 | with:
48 | languages: ${{ matrix.language }}
49 | # If you wish to specify custom queries, you can do so here or in a config file.
50 | # By default, queries listed here will override any specified in a config file.
51 | # Prefix the list here with "+" to use these queries and those in the config file.
52 |
53 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
54 | # queries: security-extended,security-and-quality
55 |
56 |
57 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
58 | # If this step fails, then you should remove it and run the build manually (see below)
59 | - name: Autobuild
60 | uses: github/codeql-action/autobuild@v2
61 |
62 | # Command-line programs to run using the OS shell.
63 | # See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
64 |
65 | # If the Autobuild fails above, remove it and uncomment the following three lines.
66 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
67 |
68 | # - run: |
69 | # echo "Run, Build Application using script"
70 | # ./location_of_script_within_repo/buildscript.sh
71 |
72 | - name: Perform CodeQL Analysis
73 | uses: github/codeql-action/analyze@v2
74 |
--------------------------------------------------------------------------------
/.github/workflows/maven.yml:
--------------------------------------------------------------------------------
1 | name: Oxalis-AS4 Master Build
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v4
10 | - name: Set up JDK 11
11 | uses: actions/setup-java@v4
12 | with:
13 | distribution: 'temurin'
14 | java-version: '11'
15 | - name: Build with Maven
16 | run: mvn -B --no-transfer-progress package --file pom.xml
17 |
--------------------------------------------------------------------------------
/.github/workflows/publish-docker.yml:
--------------------------------------------------------------------------------
1 | name: Publish Releases to Docker hub
2 |
3 | # When its time to do a release do a full cross platform build for all supported
4 | # architectures and push all of them to Docker Hub.
5 | # Only trigger on semver shaped tags.
6 | on:
7 | push:
8 | tags:
9 | - "v*.*.*"
10 |
11 | jobs:
12 | docker:
13 | runs-on: ubuntu-latest
14 | steps:
15 | - uses: actions/checkout@v4
16 |
17 | - name: Prepare
18 | id: prep
19 | run: |
20 | DOCKER_IMAGE=norstella/oxalis-as4
21 | VERSION=edge
22 | if [[ $GITHUB_REF == refs/tags/* ]]; then
23 | VERSION=${GITHUB_REF#refs/tags/v}
24 | fi
25 | if [ "${{ github.event_name }}" = "schedule" ]; then
26 | VERSION=nightly
27 | fi
28 | TAGS="${DOCKER_IMAGE}:${VERSION}"
29 | if [[ $VERSION =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
30 | TAGS="$TAGS,${DOCKER_IMAGE}:latest"
31 | fi
32 | echo ::set-output name=tags::${TAGS}
33 |
34 | - name: Set up QEMU
35 | uses: docker/setup-qemu-action@v1
36 | with:
37 | platforms: all
38 |
39 | - name: Set up Docker Buildx
40 | id: buildx
41 | uses: docker/setup-buildx-action@v1
42 |
43 | - name: Cache Docker layers
44 | uses: actions/cache@v4
45 | with:
46 | path: /tmp/.buildx-cache
47 | key: ${{ runner.os }}-buildx-${{ github.sha }}
48 | restore-keys: |
49 | ${{ runner.os }}-buildx-
50 | - name: Login to DockerHub
51 | if: github.event_name != 'pull_request'
52 | uses: docker/login-action@v1
53 | with:
54 | username: ${{ secrets.DOCKER_HUB_USERNAME }}
55 | password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
56 |
57 | - name: Build and push
58 | id: docker_build
59 | uses: docker/build-push-action@v2
60 | with:
61 | builder: ${{ steps.buildx.outputs.name }}
62 | context: ./
63 | file: ./Dockerfile
64 | platforms: linux/amd64,linux/arm64/v8
65 | push: true
66 | tags: norstella/oxalis-as4:7.2.0-RC4
67 | cache-from: type=local,src=/tmp/.buildx-cache
68 | cache-to: type=local,dest=/tmp/.buildx-cache
69 |
70 | - name: Image digest
71 | run: echo ${{ steps.docker_build.outputs.digest }}
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Oxalis-AS4 Release publish
2 | on:
3 | release:
4 | types: [created]
5 | jobs:
6 | publish:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v4
10 | - name: Set up JDK 11
11 | uses: actions/setup-java@v4
12 | with:
13 | distribution: 'temurin'
14 | java-version: '11'
15 | server-id: central
16 | server-username: MAVEN_USERNAME
17 | server-password: MAVEN_PASSWORD
18 | gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
19 | gpg-passphrase: GPG_PASSPHRASE
20 | - name: Publish to the Maven Central Repository
21 | run: mvn --batch-mode deploy -P release-sign-artifacts
22 | env:
23 | MAVEN_USERNAME: ${{ secrets.MAVEN_CENTRAL_USERNAME }}
24 | MAVEN_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }}
25 | GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | target/
3 | oxalis-as4.iml
4 | output.mime
5 | /qodana.yaml
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, religion, or sexual identity
10 | and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | * Demonstrating empathy and kindness toward other people
21 | * Being respectful of differing opinions, viewpoints, and experiences
22 | * Giving and gracefully accepting constructive feedback
23 | * Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | * Focusing on what is best not just for us as individuals, but for the
26 | overall community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | * The use of sexualized language or imagery, and sexual attention or
31 | advances of any kind
32 | * Trolling, insulting or derogatory comments, and personal or political attacks
33 | * Public or private harassment
34 | * Publishing others' private information, such as a physical or email
35 | address, without their explicit permission
36 | * Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | .
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series
86 | of actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or
93 | permanent ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within
113 | the community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120 |
121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
122 | enforcement ladder](https://github.com/mozilla/diversity).
123 |
124 | [homepage]: https://www.contributor-covenant.org
125 |
126 | For answers to common questions about this code of conduct, see the FAQ at
127 | https://www.contributor-covenant.org/faq. Translations are available at
128 | https://www.contributor-covenant.org/translations.
129 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Welcome to Oxalis contributing guide
2 |
3 | Thank you for investing your time in contributing to our project !!!
4 | Any contribution you make will be reflected on [Oxalis-AS4 Releases](https://github.com/OxalisCommunity/oxalis-as4/releases) :sparkles:.
5 |
6 | Read our [Code of Conduct](./CODE_OF_CONDUCT.md) to keep our community approachable and respectable.
7 | In this guide you will get an overview of the contribution workflow from opening an issue, creating a PR, reviewing, and merging the PR.
8 |
9 | ## New contributor guide
10 |
11 | To get an overview of the project, read the [README](./README.md) file. Here are some resources to help you get started with open source contributions:
12 |
13 | - [Finding ways to contribute to open source on GitHub](https://docs.github.com/en/get-started/exploring-projects-on-github/finding-ways-to-contribute-to-open-source-on-github)
14 | - [Set up Git](https://docs.github.com/en/get-started/getting-started-with-git/set-up-git)
15 | - [GitHub flow](https://docs.github.com/en/get-started/using-github/github-flow)
16 | - [Collaborating with pull requests](https://docs.github.com/en/github/collaborating-with-pull-requests)
17 |
18 |
19 | ## Getting started
20 |
21 | Before starting contributing, please make yourself aware of codebase, and also go through WIKI pages.
22 |
23 | ### Issues
24 |
25 | #### Create a new issue
26 |
27 | If you found a bug/issue, before creating [issue](https://github.com/OxalisCommunity/oxalis-as4/issues) first search if such issue already exist or not - Search in both open and [closed](https://github.com/OxalisCommunity/oxalis-as4/issues?q=is%3Aissue%20state%3Aclosed) issues.
28 | If a related issue doesn't exist, you can open a new issue using a relevant [issue form](https://github.com/OxalisCommunity/oxalis-as4/issues/new/choose).
29 |
30 | #### Solve an issue
31 |
32 | Scan through our [existing issue](https://github.com/OxalisCommunity/oxalis-as4/issues) to find one that interests you. You can narrow down the search using `labels` as filters.
33 | As a general rule, we don’t assign issues to anyone. If you find an issue to work on, you are welcome to open a PR with a fix.
34 |
35 | ### Make Changes
36 |
37 | #### Make changes locally
38 |
39 | 1. Fork the repository.
40 | - Using GitHub Desktop:
41 | - [Getting started with GitHub Desktop](https://docs.github.com/en/desktop/installing-and-configuring-github-desktop/getting-started-with-github-desktop) will guide you through setting up Desktop.
42 | - Once Desktop is set up, you can use it to [fork the repo](https://docs.github.com/en/desktop/contributing-and-collaborating-using-github-desktop/cloning-and-forking-repositories-from-github-desktop)!
43 |
44 | - Using the command line:
45 | - [Fork the repo](https://docs.github.com/en/github/getting-started-with-github/fork-a-repo#fork-an-example-repository) so that you can make your changes without affecting the original project until you're ready to merge them.
46 |
47 | 2. Create a working branch and start with your changes!
48 |
49 | ### Pull Request
50 |
51 | When you're finished with the changes, create a pull request, also known as a PR - [Pull Request Template](https://github.com/OxalisCommunity/oxalis-as4/blob/master/pull_request_template.md)
52 |
53 | ### Your PR is merged!
54 |
55 | Congratulations :tada::tada: The Oxalis Community team thanks you :sparkles:.
56 |
57 | Once your PR is merged, your contributions will be publicly visible on the [Oxalis Releases](https://github.com/OxalisCommunity/oxalis-as4/releases).
58 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM maven:3.8.6-jdk-11 AS mvn
2 |
3 | ADD . $MAVEN_HOME
4 |
5 | RUN cd $MAVEN_HOME \
6 | && mvn -B clean package -DskipTests=true \
7 | && cp -r target/$(ls target | grep "\-dist$" | head -1) /dist
8 |
9 |
10 | FROM norstella/oxalis:7.2.0-RC4
11 |
12 | COPY --from=mvn /dist /oxalis/ext
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/OxalisCommunity/oxalis-as4/actions?query=workflow%3A%22oxalis-as4%20Master%20Build%22)
2 | [](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22network.oxalis%22%20AND%20a%3A%22oxalis-as4%22)
3 | ---
4 | # Upcoming Migration Notice: Deprecation of Current Repository
5 | Please be advised that this GitHub repository will no longer be supported after **December 31, 2025**. We strongly encourage all Oxalis users and contributors to begin planning their upgrade to **[Oxalis-NG](https://github.com/OxalisCommunity/oxalis-ng)**.
6 |
7 | ---
8 | # Oxalis-AS4
9 | This repo implement PEPPOL AS4 pMode.
10 | It supports Oxalis version v6.0.0 and above
11 |
12 | AS4 messages is triggered by setting the _transport profile identifier_ of one of your endpoints to "_peppol-transport-as4-v2_0_" in the SMP. No further configuration is needed beyond the standard Oxalis setup.
13 | For general instructions on how to install and use Oxalis, please refer to [oxalis installation guide](https://github.com/difi/oxalis/blob/master/doc/installation.md).
14 |
15 | * [Installation guide](docs/installation/index.md)
16 | * [OpenPEPPOL Test Bed](docs/peppol-test-bed/index.md)
17 | * [CEF connectivity test](docs/cef-connectivity/index.md)
18 |
19 | ---
20 | # Are you Contributor?
21 | We are actively looking for contributors who can contribute to Oxalis-AS4 and associated Git repositories. You can start fixing issues by selecting any existing issue or you can add new feature. Please refer [Pull request Checklist](/pull_request_template.md) while generating new pull request. Team will review your code, if it will meet desired goal, and will be according to standards and guidelines then it will be merged to master.
22 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | The maintainers of the Oxalis Community take security seriously. If you discover a security issue, please bring it to their attention right away!
4 |
5 | ## Reporting a Vulnerability
6 |
7 | Please **DO NOT** file a public issue, instead send your report privately to [oxalis@norstella.no](mailto:oxalis@norstella.no).
8 | Reporter(s) can expect a response within 72 hours, acknowledging the issue was received.
9 |
10 | ## Review Process
11 |
12 | After receiving the report, an initial triage and technical analysis is performed to confirm the report and determine its scope. We may request additional information in this stage of the process.
13 |
14 | Once a reviewer has confirmed the relevance of the report, a draft security advisory will be created on GitHub. The draft advisory will be used to discuss the issue with maintainers, the reporter(s), and where applicable, other affected parties under embargo.
15 |
16 | If the vulnerability is accepted, a timeline for developing a patch, public disclosure, and patch release will be determined. If there is an embargo period on public disclosure before the patch release, the reporter(s) are expected to participate in the discussion of the timeline and abide by agreed upon dates
17 | for public disclosure.
18 |
19 | ## Accreditation
20 |
21 | Security reports are greatly appreciated and we will publicly thank you, although we will keep your name confidential if you request it. We do not currently offer a paid security bounty program at this time.
22 |
--------------------------------------------------------------------------------
/docs/img/cef_static_discovery_form.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OxalisCommunity/Oxalis-AS4/5aecaca2e2f3b92c56b59e645f58a0117908379f/docs/img/cef_static_discovery_form.PNG
--------------------------------------------------------------------------------
/docs/img/peppol_testbed1.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OxalisCommunity/Oxalis-AS4/5aecaca2e2f3b92c56b59e645f58a0117908379f/docs/img/peppol_testbed1.PNG
--------------------------------------------------------------------------------
/docs/img/peppol_testbed2.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OxalisCommunity/Oxalis-AS4/5aecaca2e2f3b92c56b59e645f58a0117908379f/docs/img/peppol_testbed2.PNG
--------------------------------------------------------------------------------
/docs/img/peppol_testbed3.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OxalisCommunity/Oxalis-AS4/5aecaca2e2f3b92c56b59e645f58a0117908379f/docs/img/peppol_testbed3.PNG
--------------------------------------------------------------------------------
/docs/img/peppol_testbed4.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OxalisCommunity/Oxalis-AS4/5aecaca2e2f3b92c56b59e645f58a0117908379f/docs/img/peppol_testbed4.PNG
--------------------------------------------------------------------------------
/docs/img/peppol_testbed5.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OxalisCommunity/Oxalis-AS4/5aecaca2e2f3b92c56b59e645f58a0117908379f/docs/img/peppol_testbed5.PNG
--------------------------------------------------------------------------------
/docs/img/peppol_testbed6.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OxalisCommunity/Oxalis-AS4/5aecaca2e2f3b92c56b59e645f58a0117908379f/docs/img/peppol_testbed6.PNG
--------------------------------------------------------------------------------
/docs/img/peppol_testbed7.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OxalisCommunity/Oxalis-AS4/5aecaca2e2f3b92c56b59e645f58a0117908379f/docs/img/peppol_testbed7.PNG
--------------------------------------------------------------------------------
/docs/img/peppol_testbed8.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OxalisCommunity/Oxalis-AS4/5aecaca2e2f3b92c56b59e645f58a0117908379f/docs/img/peppol_testbed8.PNG
--------------------------------------------------------------------------------
/docs/img/tomcat_folder.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OxalisCommunity/Oxalis-AS4/5aecaca2e2f3b92c56b59e645f58a0117908379f/docs/img/tomcat_folder.PNG
--------------------------------------------------------------------------------
/docs/img/tomcat_oxalis_folder.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OxalisCommunity/Oxalis-AS4/5aecaca2e2f3b92c56b59e645f58a0117908379f/docs/img/tomcat_oxalis_folder.PNG
--------------------------------------------------------------------------------
/docs/installation/index.md:
--------------------------------------------------------------------------------
1 | # Oxalis AS4 installation
2 |
3 | We will be basing this installation guide on Oxalis _5.0.5_ for Oxalis and _5.0.3_ for Oxalis-AS4. Specifically _Oxalis Server_ ([download](https://search.maven.org/artifact/network.oxalis/oxalis-server/5.0.5/jar)) for inbound traffic and _Oxalis Standalone_ ([download](https://search.maven.org/artifact/network.oxalis/oxalis-standalone/5.0.5/jar)) for outbound traffic. The same approach will work for all the other components of Oxalis 5.x
4 |
5 | ## Additional/Alternate download links:
6 | Here are the links to download Oxalis Artifacts maven repositories:
7 | - https://search.maven.org/search?q=g:network.oxalis (Sonatype: Maven Central Repository Search) OR
8 | - https://repo1.maven.org/maven2/network/oxalis/ (Maven Repo) OR
9 | - https://mvnrepository.com/artifact/network.oxalis (Mvn Repository)
10 |
11 | Depending upon how you are using/integrated those artifacts, you can download them GitHub Releases section:
12 | - https://github.com/OxalisCommunity/oxalis/releases/tag/v5.0.5
13 | - https://github.com/OxalisCommunity/Oxalis-AS4/releases/tag/v5.0.3
14 |
15 |
16 | # Inbound
17 | * [Oxalis Inbound (Server)](server.md)
18 | * [Oxalis Inbound (Tomcat 8+)](tomcat.md)
19 | * [Oxalis Inbound (Docker)](https://hub.docker.com/r/norstella/oxalis-as4/)
20 |
21 | # Outbound
22 | * [Oxalis Outbound (Standalone)](standalone.md)
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/docs/installation/server.md:
--------------------------------------------------------------------------------
1 | ### Install Oxalis Inbound (Server)
2 |
3 | Oxalis server comes out of the box with a folder for extensions (named "ext"). Extract the content of _oxalis-as4-6.0.0-dist.zip_ into this folder. No further configuration is needed.
4 |
5 | Start Oxalis server in the normal way, either trough _run.sh_ or _run.bat_.
6 |
7 | The easiest way to see that the AS4 endpoint is up and running is to visit its endpoint address.
8 | If we now visit ``localhost:8080/as4`` we will be greeted with the message ``Hello AS4 world``
--------------------------------------------------------------------------------
/docs/installation/standalone.md:
--------------------------------------------------------------------------------
1 | ### Install Oxalis Outbound (Standalone)
2 |
3 | Oxalis SimpleSender does not come with an extension folder. So we need to add the extension logic that where define in the _run_ scripts our self.
4 |
5 | We make a base folder named oxalis-standalone-as4 with two sub folders:
6 |
7 | oxalis-standalone-as4/ <-- Base folder, we will run our commands from here
8 | ├── standalone/ <-- We will putt our regular Oxalis Standalone application here...
9 | │ ├── oxalis-standalone.jar
10 | │ ├── posibly-other.jar
11 | │ └── ...
12 | └── as4/ <-- ...and our AS4 extension here
13 | ├── oxalis-as4.jar
14 | ├── many-other.jar
15 | └── ...
16 |
17 |
18 | To run our combined application all we need to do is to run the following command (This command assumes we are standing in our base folder):
19 |
20 | java -classpath "standalone/*;as4/*" eu.sendregning.oxalis.Main [followd by the argument like -f c:\some-invoice.xml]
21 |
22 |
23 | All this command does is to tell Java to load the content of both folders, then execute the logic in "_eu.sendregning.oxalis.Main_" (which is the starting point of the Standalone application).
24 | By looking into the run scripts of Oxalis Server form our previous section we can see that this is in fact the same approach that is used there.
25 |
--------------------------------------------------------------------------------
/docs/installation/tomcat.md:
--------------------------------------------------------------------------------
1 | # Install Oxalis Inbound (Tomcat 8+)
2 |
3 | ## Oxalis
4 |
5 | First you should download the [oxalis-war-6.0.0.war](https://github.com/OxalisCommunity/oxalis/releases/download/oxalis-6.0.0/oxalis-war-6.0.0.war) file
6 | from this [page](https://github.com/OxalisCommunity/oxalis/releases) and
7 | put it a directory of your choice. We recommend naming the folder oxalis.
8 |
9 | Then you should download the [Oxalis-AS4 distribution](https://github.com/OxalisCommunity/oxalis-as4/releases/download/6.0.0/oxalis-as4-6.0.0-dist.zip)
10 | from this [page](https://github.com/OxalisCommunity/oxalis-as4/releases) and unzip
11 | the files to a new folder of your choice. We recommend creating a folder named as4 inside the folder containing the WAR file.
12 |
13 | Also create a folder named home inside the oxalis folder and place the oxalis.conf file, together with the necessary JKS files.
14 |
15 | Then you should have something looking like this like this:
16 |
17 | 
18 |
19 | For general instructions on how to install and use Oxalis, please refer to [oxalis installation guide](https://github.com/difi/oxalis/blob/master/doc/installation.md).
20 |
21 | ## Tomcat installation
22 |
23 | First you need to [download](https://tomcat.apache.org/download-90.cgi) Tomcat and unzip the files to a directory.
24 |
25 | 
26 |
27 | Then you should set the CATALINA_BASE environment variable to the chosen installation folder.
28 |
29 | ## Tomcat configuration for Oxalis
30 |
31 | The next step is to create a folder named Catalina in the Tomcat conf directory.
32 |
33 | ```bash
34 | cd conf
35 | mkdir Catalina
36 | ```
37 |
38 | And inside the newly created Catalina folder - create a folder named localhost.
39 |
40 | ```bash
41 | cd Catalina
42 | mkdir localhost
43 | ```
44 |
45 | Inside this localhost folder - create a file named oxalis.xml containing:
46 |
47 | ```xml
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
74 |
75 |
76 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 | ```
90 |
91 | This is only an example deployment XML file for tomcat 8+. Ensure that your file locations match with the paths in the XML.
92 |
93 | Now you are ready to start the Tomcat server.
94 |
95 | # Verifying the installation
96 |
97 | The easiest way to see that the AS4 endpoint is up and running is to visit its endpoint address.
98 | If we now visit ``localhost:8080/oxalis/as4`` we will be greeted with the message ``Hello AS4 world``
99 |
100 |
--------------------------------------------------------------------------------
/hooks/post_push:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | if [ "$SOURCE_BRANCH" = "master" ]; then
4 | exit
5 | fi
6 |
7 | docker tag $IMAGE_NAME $DOCKER_REPO:latest
8 | docker push $DOCKER_REPO:latest
9 |
--------------------------------------------------------------------------------
/pull_request_template.md:
--------------------------------------------------------------------------------
1 | ## Pull Request Description
2 |
3 | Please include a summary of the change request or bug which is supposed to be fixed as part of this pull request
4 |
5 | ## Type of Pull Request
6 |
7 | - [ ] New feature/Enhancement - non-breaking change which adds functionality
8 | - [ ] Bug fix
9 | - [ ] Breaking change (Require Major version change?)
10 |
11 | ## Type of Change
12 |
13 | - [ ] OpenPeppol AS4 specification
14 | - [ ] Oxalis software change or enhancement
15 | - [ ] CEF change
16 |
17 | ## Pull Request Checklist:
18 |
19 | - [ ] My code follows the style guidelines of this project
20 | - [ ] I have commented my code, particularly in hard-to-understand areas. But did not added unnecessary annotation/comment say @author name etc
21 | - [ ] I have checked my code for variable and method name and corrected grammar/spelling mistakes if any
22 | - [ ] I have made corresponding changes to the documentation where needed
23 | - [ ] My changes generate no new/additional warnings
24 | - [ ] My change is not breaking or creating conflict with associated dependencies
25 | - [ ] I have performed a self-review of my own code
26 | - [ ] I ran `mvn clean install` before commit and all tests run successfully
27 | - [ ] I conducted basic QA to assure all features are working fine
28 | - [ ] My pull request generate no conflicts with `master` branch
29 | - [ ] I requested code review from other team members
30 |
--------------------------------------------------------------------------------
/src/main/assembly/assembly-dist-zip.xml:
--------------------------------------------------------------------------------
1 |
2 | dist
3 |
4 | dir
5 | tar.gz
6 | zip
7 |
8 | false
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/main/assembly/assembly-dist.xml:
--------------------------------------------------------------------------------
1 |
2 | dist
3 |
4 | dir
5 | tar.gz
6 | zip
7 |
8 | false
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/api/MessageIdGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010-2017 Norwegian Agency for Public Management and eGovernment (Difi)
3 | *
4 | * Licensed under the EUPL, Version 1.1 or – as soon they
5 | * will be approved by the European Commission - subsequent
6 | * versions of the EUPL (the "Licence");
7 | *
8 | * You may not use this work except in compliance with the Licence.
9 | *
10 | * You may obtain a copy of the Licence at:
11 | *
12 | * https://joinup.ec.europa.eu/community/eupl/og_page/eupl
13 | *
14 | * Unless required by applicable law or agreed to in
15 | * writing, software distributed under the Licence is
16 | * distributed on an "AS IS" basis,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
18 | * express or implied.
19 | * See the Licence for the specific language governing
20 | * permissions and limitations under the Licence.
21 | */
22 |
23 | package network.oxalis.as4.api;
24 |
25 | public interface MessageIdGenerator {
26 |
27 | String generate();
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/common/AS4Constants.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.common;
2 |
3 | import lombok.experimental.UtilityClass;
4 |
5 | @UtilityClass
6 | public final class AS4Constants {
7 |
8 | public static final String PEPPOL = "peppol";
9 | public static final String CEF_CONNECTIVITY = "cef-connectivity";
10 | public static final String CEF_CONFORMANCE = "cef-conformance";
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/common/As4CommonModule.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010-2017 Norwegian Agency for Public Management and eGovernment (Difi)
3 | *
4 | * Licensed under the EUPL, Version 1.1 or – as soon they
5 | * will be approved by the European Commission - subsequent
6 | * versions of the EUPL (the "Licence");
7 | *
8 | * You may not use this work except in compliance with the Licence.
9 | *
10 | * You may obtain a copy of the Licence at:
11 | *
12 | * https://joinup.ec.europa.eu/community/eupl/og_page/eupl
13 | *
14 | * Unless required by applicable law or agreed to in
15 | * writing, software distributed under the Licence is
16 | * distributed on an "AS IS" basis,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
18 | * express or implied.
19 | * See the Licence for the specific language governing
20 | * permissions and limitations under the Licence.
21 | */
22 |
23 | package network.oxalis.as4.common;
24 |
25 | import com.google.inject.Injector;
26 | import com.google.inject.Provides;
27 | import com.google.inject.Singleton;
28 | import lombok.extern.slf4j.Slf4j;
29 | import network.oxalis.as4.api.MessageIdGenerator;
30 | import network.oxalis.as4.outbound.DefaultActionProvider;
31 | import network.oxalis.as4.util.OxalisAlgorithmSuiteLoader;
32 | import network.oxalis.as4.util.PolicyService;
33 | import network.oxalis.as4.util.TransmissionRequestUtil;
34 | import network.oxalis.api.header.HeaderParser;
35 | import network.oxalis.api.settings.Settings;
36 | import network.oxalis.as4.config.As4Conf;
37 | import network.oxalis.as4.outbound.ActionProvider;
38 | import network.oxalis.as4.util.As4MessageFactory;
39 | import network.oxalis.commons.guice.ImplLoader;
40 | import network.oxalis.commons.guice.OxalisModule;
41 | import network.oxalis.vefa.peppol.mode.Mode;
42 | import org.apache.cxf.Bus;
43 | import org.apache.cxf.BusFactory;
44 | import org.apache.cxf.transport.http.HttpServerEngineSupport;
45 | import org.apache.wss4j.dom.engine.WSSConfig;
46 |
47 | import java.security.Security;
48 |
49 | import static network.oxalis.as4.common.AS4Constants.*;
50 |
51 | @Slf4j
52 | public class As4CommonModule extends OxalisModule {
53 |
54 | @Override
55 | protected void configure() {
56 | bindTyped(MessageIdGenerator.class, DefaultMessageIdGenerator.class);
57 | bindTyped(HeaderParser.class, DummyHeaderParser.class);
58 | bind(As4MessageFactory.class);
59 | bindSettings(As4Conf.class);
60 | bind(MerlinProvider.class);
61 |
62 | Bus bus = BusFactory.newInstance().createBus();
63 | bus.setProperty(HttpServerEngineSupport.ENABLE_HTTP2, true);
64 | new OxalisAlgorithmSuiteLoader(bus);
65 | BusFactory.setThreadDefaultBus(bus);
66 |
67 | Security.setProperty("jdk.security.provider.preferred", "AES/GCM/NoPadding:BC");
68 | WSSConfig.init();
69 | }
70 |
71 | @Provides
72 | @Singleton
73 | public MessageIdGenerator getMessageIdGenerator(Injector injector, Settings settings) {
74 | return ImplLoader.get(injector, MessageIdGenerator.class, settings, As4Conf.MSGID_GENERATOR);
75 | }
76 |
77 | @Provides
78 | @Singleton
79 | public PolicyService getPolicyService(Mode mode, Settings settings, ActionProvider actionProvider) {
80 | String type = settings.getString(As4Conf.TYPE);
81 |
82 | if (Mode.PRODUCTION.equals(mode.getIdentifier()) && !PEPPOL.equals(type)) {
83 | throw new IllegalStateException("oxalis.as4.type has to be peppol in PRODUCTION!");
84 | }
85 |
86 | if (CEF_CONNECTIVITY.equalsIgnoreCase(type)) {
87 | return new PolicyService(actionProvider) {
88 | @Override
89 | protected String getDefaultPolicy() {
90 | return "/eDeliveryAS4Policy.xml";
91 | }
92 | };
93 | } else if (CEF_CONFORMANCE.equalsIgnoreCase(type)) {
94 | return new PolicyService(actionProvider) {
95 |
96 | @Override
97 | protected String getPolicyClasspath(String action, String service) {
98 | log.debug("Service = {}, Action = {}", service, action);
99 |
100 | if ("SRV_ONEWAY_SIGNONLY".equals(service)
101 | && "busdox-docid-qns::ACT_ONEWAY_SIGNONLY".equals(action)) {
102 | return "/signOnly.xml";
103 | }
104 |
105 | return getDefaultPolicy();
106 | }
107 |
108 |
109 | @Override
110 | protected String getDefaultPolicy() {
111 | return "/eDeliveryAS4Policy.xml";
112 | }
113 | };
114 | }
115 |
116 | return new PolicyService(actionProvider);
117 | }
118 |
119 | @Provides
120 | @Singleton
121 | public ActionProvider getActionProvider(Settings settings) {
122 | String type = settings.getString(As4Conf.TYPE);
123 | if (CEF_CONNECTIVITY.equalsIgnoreCase(type)) {
124 | return p -> {
125 | String action = TransmissionRequestUtil.translateDocumentTypeToAction(p);
126 |
127 | if (action.startsWith("connectivity::cef##connectivity::")) {
128 | return action.replaceFirst("connectivity::cef##connectivity::", "");
129 | }
130 |
131 | return action;
132 | };
133 | } else if (CEF_CONFORMANCE.equalsIgnoreCase(type)) {
134 | return p -> {
135 | if ("http://docs.oasis-open.org/ebxml-msg/ebms/v3.0/ns/core/200704/test".equals(p.getIdentifier())) {
136 | return "http://docs.oasis-open.org/ebxml-msg/ebms/v3.0/ns/core/200704/test";
137 | }
138 |
139 | return TransmissionRequestUtil.translateDocumentTypeToAction(p);
140 | };
141 | }
142 |
143 | return new DefaultActionProvider();
144 | }
145 | }
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/common/As4MessageProperties.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.common;
2 |
3 | import java.util.ArrayList;
4 |
5 | public class As4MessageProperties extends ArrayList {
6 |
7 | public boolean isMissing(String name) {
8 | return stream().noneMatch(p -> name.equals(p.getName()));
9 | }
10 |
11 | public String getValueByName(String name) {
12 | return stream().filter(p -> name.equals(p.getName())).findAny().map(As4MessageProperty::getValue).orElse(null);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/common/As4MessageProperty.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.common;
2 |
3 | import lombok.EqualsAndHashCode;
4 | import lombok.Value;
5 |
6 | @Value
7 | @EqualsAndHashCode
8 | public class As4MessageProperty {
9 |
10 | String name;
11 | String type;
12 | String value;
13 |
14 | public As4MessageProperty(String name, String value) {
15 | this(name, null, value);
16 | }
17 |
18 | public As4MessageProperty(String name, String type, String value) {
19 | this.name = name;
20 | this.type = type;
21 | this.value = value;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/common/DefaultMessageIdGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010-2017 Norwegian Agency for Public Management and eGovernment (Difi)
3 | *
4 | * Licensed under the EUPL, Version 1.1 or – as soon they
5 | * will be approved by the European Commission - subsequent
6 | * versions of the EUPL (the "Licence");
7 | *
8 | * You may not use this work except in compliance with the Licence.
9 | *
10 | * You may obtain a copy of the Licence at:
11 | *
12 | * https://joinup.ec.europa.eu/community/eupl/og_page/eupl
13 | *
14 | * Unless required by applicable law or agreed to in
15 | * writing, software distributed under the Licence is
16 | * distributed on an "AS IS" basis,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
18 | * express or implied.
19 | * See the Licence for the specific language governing
20 | * permissions and limitations under the Licence.
21 | */
22 |
23 | package network.oxalis.as4.common;
24 |
25 | import com.google.inject.Inject;
26 | import com.google.inject.Singleton;
27 | import lombok.SneakyThrows;
28 | import network.oxalis.as4.api.MessageIdGenerator;
29 | import network.oxalis.api.settings.Settings;
30 | import network.oxalis.api.util.Type;
31 | import network.oxalis.as4.config.As4Conf;
32 |
33 | import java.net.InetAddress;
34 | import java.net.UnknownHostException;
35 | import java.util.UUID;
36 |
37 | @Singleton
38 | @Type("default")
39 | public class DefaultMessageIdGenerator implements MessageIdGenerator {
40 |
41 | private final String hostname;
42 |
43 | public DefaultMessageIdGenerator(String hostname) {
44 | this.hostname = hostname;
45 | }
46 |
47 | @Inject
48 | public DefaultMessageIdGenerator(Settings settings) {
49 | this.hostname = getHostname(settings);
50 | }
51 |
52 | private String getHostname(Settings settings) {
53 | String name = settings.getString(As4Conf.HOSTNAME).trim();
54 | return name.isEmpty() ? getLocalHostName() : name;
55 | }
56 |
57 | @SneakyThrows(UnknownHostException.class)
58 | private String getLocalHostName() {
59 | return InetAddress.getLocalHost().getCanonicalHostName();
60 | }
61 |
62 | @Override
63 | public String generate() {
64 | return String.format("%s@%s", UUID.randomUUID().toString(), hostname);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/common/DummyHeaderParser.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.common;
2 |
3 | import com.google.inject.Singleton;
4 | import lombok.extern.slf4j.Slf4j;
5 | import network.oxalis.api.header.HeaderParser;
6 | import network.oxalis.api.util.Type;
7 | import network.oxalis.vefa.peppol.common.model.*;
8 |
9 | import java.io.IOException;
10 | import java.io.InputStream;
11 | import java.util.Date;
12 |
13 | @Slf4j
14 | @Singleton
15 | @Type("dummy")
16 | public class DummyHeaderParser implements HeaderParser {
17 |
18 | @Override
19 | public Header parse(InputStream inputStream) {
20 |
21 | log.debug("DummyHeaderParser: parse");
22 |
23 | try {
24 | byte[] drain = new byte[500];
25 | inputStream.read(drain);
26 | } catch (IOException e) {
27 | log.error("IOException while parsing header", e);
28 | }
29 |
30 | return Header.of(
31 | ParticipantIdentifier.of("DummySender"),
32 | ParticipantIdentifier.of("DummyReceiver"),
33 | ProcessIdentifier.of("DummyProcess"),
34 | DocumentTypeIdentifier.of("DummyDocument"),
35 | C1CountryIdentifier.of("DummyCountry"),
36 | MlsToIdentifier.of("DummyMlsTo"),
37 | MlsTypeIdentifier.of("DummyMlsType"),
38 | InstanceIdentifier.of("DummyInstance"),
39 | InstanceType.of("Dummy", "InstanceType", "1.0"),
40 | new Date(0L));
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/common/MerlinProvider.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.common;
2 |
3 | import com.google.inject.Inject;
4 | import com.google.inject.Singleton;
5 | import com.google.inject.name.Named;
6 | import lombok.extern.slf4j.Slf4j;
7 | import network.oxalis.api.lang.OxalisLoadingException;
8 | import network.oxalis.vefa.peppol.mode.Mode;
9 | import org.apache.wss4j.common.crypto.Merlin;
10 | import org.bouncycastle.jce.provider.BouncyCastleProvider;
11 |
12 | import java.io.IOException;
13 | import java.io.InputStream;
14 | import java.nio.file.Files;
15 | import java.nio.file.Path;
16 | import java.security.KeyStore;
17 | import java.security.KeyStoreException;
18 | import java.security.NoSuchAlgorithmException;
19 | import java.security.cert.CertificateException;
20 | import java.util.Enumeration;
21 | import java.util.Optional;
22 |
23 | @Slf4j
24 | @Singleton
25 | public class MerlinProvider {
26 |
27 | @Inject
28 | private Mode mode;
29 |
30 | @Inject
31 | @Named("conf")
32 | private Path confFolder;
33 |
34 | @Inject
35 | private KeyStore keyStore;
36 |
37 | @Inject(optional = true)
38 | @Named("truststore-ap")
39 | private KeyStore trustStoreAp;
40 |
41 | private KeyStore cachedTrustStore;
42 |
43 | public Merlin getMerlin() {
44 | Merlin merlin = new Merlin();
45 | merlin.setCryptoProvider(BouncyCastleProvider.PROVIDER_NAME);
46 | merlin.setKeyStore(keyStore);
47 | merlin.setTrustStore(getCachedTrustStore());
48 | return merlin;
49 | }
50 |
51 | private KeyStore getCachedTrustStore() {
52 | if (cachedTrustStore == null) {
53 | cachedTrustStore = getTrustStore();
54 | }
55 |
56 | return cachedTrustStore;
57 | }
58 |
59 | private KeyStore getTrustStore() {
60 | Optional trustStoreExtension = loadTrustStoreApFromConf(mode, confFolder);
61 |
62 | if (trustStoreAp != null) {
63 | trustStoreExtension.ifPresent(p ->
64 | extendKeyStore(trustStoreAp, p)
65 | );
66 |
67 | return trustStoreAp;
68 | }
69 |
70 | return trustStoreExtension
71 | .orElseThrow(() -> new OxalisLoadingException("Expected a truststore. Please specify the property security.truststore.ap"));
72 | }
73 |
74 | private void extendKeyStore(KeyStore trustStoreAp, KeyStore trustStoreExtension) {
75 | try {
76 | Enumeration aliases = trustStoreExtension.aliases();
77 | while (aliases.hasMoreElements()) {
78 | String alias = aliases.nextElement();
79 | if (!trustStoreAp.containsAlias(alias)) {
80 | log.info("Adding {} to truststore", alias);
81 | trustStoreAp.setCertificateEntry(alias, trustStoreExtension.getCertificate(alias));
82 | }
83 | }
84 | } catch (KeyStoreException e) {
85 | throw new OxalisLoadingException("Something went wrong during extension of key store.", e);
86 | }
87 | }
88 |
89 | private Optional loadTrustStoreApFromConf(Mode mode, Path confFolder) {
90 | String truststoreAp = mode.getString("security.truststore.ap");
91 |
92 | if (truststoreAp == null) {
93 | return Optional.empty();
94 | }
95 |
96 | Path path = confFolder.resolve(truststoreAp);
97 |
98 | try {
99 | KeyStore keystore = KeyStore.getInstance("JKS");
100 | if (!path.toFile().exists()) return Optional.empty();
101 |
102 | log.info("Loading TRUSTSTORE: {}", path);
103 |
104 | try (InputStream inputStream = Files.newInputStream(path)) {
105 | keystore.load(inputStream, mode.getString("security.truststore.password").toCharArray());
106 | }
107 | return Optional.of(keystore);
108 | } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException e) {
109 | throw new OxalisLoadingException("Something went wrong during handling of key store.", e);
110 | } catch (IOException e) {
111 | throw new OxalisLoadingException(String.format("Error during reading of '%s'.", path), e);
112 | }
113 | }
114 | }
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/config/As4Conf.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010-2017 Norwegian Agency for Public Management and eGovernment (Difi)
3 | *
4 | * Licensed under the EUPL, Version 1.1 or – as soon they
5 | * will be approved by the European Commission - subsequent
6 | * versions of the EUPL (the "Licence");
7 | *
8 | * You may not use this work except in compliance with the Licence.
9 | *
10 | * You may obtain a copy of the Licence at:
11 | *
12 | * https://joinup.ec.europa.eu/community/eupl/og_page/eupl
13 | *
14 | * Unless required by applicable law or agreed to in
15 | * writing, software distributed under the Licence is
16 | * distributed on an "AS IS" basis,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
18 | * express or implied.
19 | * See the Licence for the specific language governing
20 | * permissions and limitations under the Licence.
21 | */
22 |
23 | package network.oxalis.as4.config;
24 |
25 | import network.oxalis.api.settings.DefaultValue;
26 | import network.oxalis.api.settings.Path;
27 | import network.oxalis.api.settings.Title;
28 |
29 | @Title("AS4")
30 | public enum As4Conf {
31 |
32 | @Path("oxalis.as4.hostname")
33 | @DefaultValue("")
34 | HOSTNAME,
35 |
36 | @Path("oxalis.as4.msgidgen")
37 | @DefaultValue("default")
38 | MSGID_GENERATOR,
39 |
40 | @Path("oxalis.as4.type")
41 | @DefaultValue("peppol")
42 | TYPE
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/inbound/AS4MessageContextKey.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.inbound;
2 |
3 | import lombok.experimental.UtilityClass;
4 |
5 | @UtilityClass
6 | public class AS4MessageContextKey {
7 |
8 | public static final String FIRST_PAYLOAD_PATH = "network.oxalis.as4.first.payload.path";
9 | public static final String FIRST_PAYLOAD_HEADER = "network.oxalis.as4.first.payload.header";
10 | public static final String ENVELOPE_HEADER = "network.oxalis.as4.envelope.header";
11 | public static final String PERSISTED = "network.oxalis.as4.persisted";
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/inbound/AS4StatusServlet.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010-2018 Norwegian Agency for Public Management and eGovernment (Difi)
3 | *
4 | * Licensed under the EUPL, Version 1.1 or – as soon they
5 | * will be approved by the European Commission - subsequent
6 | * versions of the EUPL (the "Licence");
7 | *
8 | * You may not use this work except in compliance with the Licence.
9 | *
10 | * You may obtain a copy of the Licence at:
11 | *
12 | * https://joinup.ec.europa.eu/community/eupl/og_page/eupl
13 | *
14 | * Unless required by applicable law or agreed to in
15 | * writing, software distributed under the Licence is
16 | * distributed on an "AS IS" basis,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
18 | * express or implied.
19 | * See the Licence for the specific language governing
20 | * permissions and limitations under the Licence.
21 | */
22 |
23 | package network.oxalis.as4.inbound;
24 |
25 | import com.google.inject.Inject;
26 | import com.google.inject.Singleton;
27 | import network.oxalis.vefa.peppol.mode.Mode;
28 |
29 | import jakarta.servlet.http.HttpServlet;
30 | import jakarta.servlet.http.HttpServletRequest;
31 | import jakarta.servlet.http.HttpServletResponse;
32 | import java.io.IOException;
33 | import java.io.PrintWriter;
34 |
35 | /**
36 | * Servlet returning diagnostic information to ease operation, support and debugging.
37 | * Since this servlet is public accessible, it should NOT contain any sensitive
38 | * information about it's runtime environment.
39 | */
40 | @Singleton
41 | public class AS4StatusServlet extends HttpServlet {
42 |
43 | private final Mode mode;
44 |
45 | @Inject
46 | public AS4StatusServlet(Mode mode) {
47 | this.mode = mode;
48 | }
49 |
50 | @Override
51 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
52 | resp.setContentType("text/plain");
53 |
54 | PrintWriter writer = resp.getWriter();
55 | writer.println("version.oxalis.as4: " + OxalisAS4Version.getVersion());
56 | writer.println("version.java: " + System.getProperty("java.version"));
57 | writer.println("mode: " + mode.getIdentifier());
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/inbound/AbstractSetPolicyInterceptor.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.inbound;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import network.oxalis.as4.util.Constants;
5 | import network.oxalis.as4.util.Marshalling;
6 | import network.oxalis.as4.util.PolicyService;
7 | import org.apache.cxf.binding.soap.SoapMessage;
8 | import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
9 | import org.apache.cxf.headers.Header;
10 | import org.apache.cxf.interceptor.Fault;
11 | import org.apache.cxf.message.Message;
12 | import org.apache.cxf.ws.policy.PolicyConstants;
13 | import org.apache.neethi.Policy;
14 | import org.oasis_open.docs.ebxml_msg.ebms.v3_0.ns.core._200704.Messaging;
15 | import org.oasis_open.docs.ebxml_msg.ebms.v3_0.ns.core._200704.UserMessage;
16 | import org.w3c.dom.Node;
17 |
18 | import jakarta.xml.bind.JAXBContext;
19 | import jakarta.xml.bind.JAXBException;
20 | import jakarta.xml.bind.Unmarshaller;
21 | import java.util.Collection;
22 | import java.util.Optional;
23 | import java.util.stream.Stream;
24 |
25 | import static org.apache.cxf.ws.security.SecurityConstants.USE_ATTACHMENT_ENCRYPTION_CONTENT_ONLY_TRANSFORM;
26 |
27 | @Slf4j
28 | abstract class AbstractSetPolicyInterceptor extends AbstractSoapInterceptor {
29 |
30 | private final JAXBContext jaxbContext = Marshalling.getInstance();
31 | private final PolicyService policyService;
32 |
33 | public AbstractSetPolicyInterceptor(String phase, PolicyService policyService) {
34 | super(phase);
35 | this.policyService = policyService;
36 | }
37 |
38 | @Override
39 | public void handleMessage(SoapMessage message) throws Fault {
40 | message.put(USE_ATTACHMENT_ENCRYPTION_CONTENT_ONLY_TRANSFORM, true);
41 |
42 | Optional userMessage = getMessaging(message)
43 | .map(Messaging::getUserMessage)
44 | .map(Collection::stream).orElseGet(Stream::empty)
45 | .findFirst();
46 |
47 | try {
48 | Policy policy = userMessage.isPresent()
49 | ? policyService.getPolicy(userMessage.get().getCollaborationInfo())
50 | : policyService.getPolicy();
51 | message.put(PolicyConstants.POLICY_OVERRIDE, policy);
52 | } catch (Exception e) {
53 | throw new Fault(e);
54 | }
55 | }
56 |
57 | private Optional getMessaging(Message message) {
58 | SoapMessage soapMessage = (SoapMessage) message;
59 | Header header = soapMessage.getHeader(Constants.MESSAGING_QNAME);
60 |
61 | if (header == null) {
62 | return Optional.empty();
63 | }
64 |
65 | try {
66 | Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
67 | Messaging messaging = unmarshaller.unmarshal((Node) header.getObject(), Messaging.class).getValue();
68 | return Optional.of(messaging);
69 | } catch (JAXBException e) {
70 | throw new Fault(e);
71 | }
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/inbound/As4EndpointSelector.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.inbound;
2 |
3 | import org.apache.cxf.binding.soap.interceptor.ReadHeadersInterceptor;
4 | import org.apache.cxf.endpoint.Endpoint;
5 | import org.apache.cxf.message.Message;
6 | import org.apache.cxf.phase.Phase;
7 | import org.apache.cxf.wsdl.interceptors.AbstractEndpointSelectionInterceptor;
8 |
9 | import java.util.Set;
10 |
11 | public class As4EndpointSelector extends AbstractEndpointSelectionInterceptor {
12 |
13 | public static final String ENDPOINT_NAME = "Endpoint-name";
14 | public static final String OXALIS_AS4_ENDPOINT_NAME = "Oxalis-AS4";
15 |
16 | public As4EndpointSelector() {
17 | super(Phase.READ);
18 | getAfter().add(ReadHeadersInterceptor.class.getName());
19 | }
20 |
21 | @Override
22 | protected Endpoint selectEndpoint(Message message, Set endpoints) {
23 |
24 | for (Endpoint endpoint : endpoints) {
25 | if (OXALIS_AS4_ENDPOINT_NAME.equals(endpoint.get(ENDPOINT_NAME))) {
26 | return endpoint;
27 | }
28 | }
29 |
30 | return null;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/inbound/As4EndpointsPublisher.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.inbound;
2 |
3 | import org.apache.cxf.Bus;
4 | import org.apache.cxf.jaxws.EndpointImpl;
5 |
6 | public interface As4EndpointsPublisher {
7 |
8 | EndpointImpl publish(Bus bus);
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/inbound/As4EndpointsPublisherImpl.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.inbound;
2 |
3 | import com.google.inject.Inject;
4 | import org.apache.cxf.attachment.As4AttachmentInInterceptor;
5 | import org.apache.cxf.Bus;
6 | import org.apache.cxf.binding.soap.SoapMessage;
7 | import org.apache.cxf.binding.soap.SoapVersion;
8 | import org.apache.cxf.binding.soap.interceptor.CheckFaultInterceptor;
9 | import org.apache.cxf.binding.soap.interceptor.ReadHeadersInterceptor;
10 | import org.apache.cxf.binding.soap.interceptor.StartBodyInterceptor;
11 | import org.apache.cxf.ext.logging.LoggingFeature;
12 | import org.apache.cxf.interceptor.StaxInEndingInterceptor;
13 | import org.apache.cxf.interceptor.StaxInInterceptor;
14 | import org.apache.cxf.jaxws.EndpointImpl;
15 | import org.apache.cxf.jaxws.handler.soap.SOAPHandlerFaultInInterceptor;
16 | import org.apache.cxf.message.Message;
17 | import org.apache.cxf.transport.MultipleEndpointObserver;
18 | import org.apache.cxf.ws.policy.WSPolicyFeature;
19 | import org.apache.cxf.wsdl.interceptors.AbstractEndpointSelectionInterceptor;
20 |
21 | import jakarta.xml.ws.Endpoint;
22 | import java.util.Arrays;
23 |
24 | import static org.apache.cxf.ws.security.SecurityConstants.ENABLE_STREAMING_SECURITY;
25 |
26 | public class As4EndpointsPublisherImpl implements As4EndpointsPublisher {
27 |
28 | @Inject
29 | private As4Provider as4Provider;
30 |
31 | @Inject
32 | private AbstractEndpointSelectionInterceptor endpointSelector;
33 |
34 | @Inject
35 | private As4FaultInHandler as4FaultInHandler;
36 |
37 | @Inject
38 | private As4Interceptor oxalisAs4Interceptor;
39 |
40 | @Inject
41 | private SetPolicyInInterceptor setPolicyInInterceptor;
42 |
43 | @Inject
44 | private SetPolicyOutInterceptor setPolicyOutInterceptor;
45 |
46 | @Override
47 | public EndpointImpl publish(Bus bus) {
48 | EndpointImpl endpoint = (EndpointImpl) Endpoint.publish("/", as4Provider,
49 | new LoggingFeature(),
50 | new WSPolicyFeature());
51 |
52 | endpoint.getServer().getEndpoint().put("allow-multiplex-endpoint", Boolean.TRUE);
53 | endpoint.getServer().getEndpoint().put(ENABLE_STREAMING_SECURITY, false);
54 | endpoint.getServer().getEndpoint()
55 | .put(As4EndpointSelector.ENDPOINT_NAME, As4EndpointSelector.OXALIS_AS4_ENDPOINT_NAME);
56 |
57 | endpoint.getBinding().setHandlerChain(Arrays.asList(as4FaultInHandler, new MessagingHandler()));
58 | endpoint.getInInterceptors().add(oxalisAs4Interceptor);
59 | endpoint.getInInterceptors().add(setPolicyInInterceptor);
60 | endpoint.getInInterceptors().add(new AttachmentCleanupInterceptor());
61 |
62 | endpoint.getOutInterceptors().add(setPolicyOutInterceptor);
63 | endpoint.getInFaultInterceptors().add(setPolicyInInterceptor);
64 | endpoint.getOutFaultInterceptors().add(setPolicyOutInterceptor);
65 |
66 | MultipleEndpointObserver newMO = new MultipleEndpointObserver(bus) {
67 | @Override
68 | protected Message createMessage(Message message) {
69 | return new SoapMessage(message);
70 | }
71 | };
72 |
73 | newMO.getBindingInterceptors().add(new As4AttachmentInInterceptor());
74 | newMO.getBindingInterceptors().add(new StaxInInterceptor());
75 | newMO.getBindingInterceptors().add(new StaxInEndingInterceptor());
76 | newMO.getBindingInterceptors().add(new SOAPHandlerFaultInInterceptor(endpoint.getBinding()));
77 | newMO.getBindingInterceptors().add(new ReadHeadersInterceptor(bus, (SoapVersion) null));
78 | newMO.getBindingInterceptors().add(new StartBodyInterceptor());
79 | newMO.getBindingInterceptors().add(new CheckFaultInterceptor());
80 |
81 |
82 | // Add in a default selection interceptor
83 | newMO.getRoutingInterceptors().add(endpointSelector);
84 | newMO.getEndpoints().add(endpoint.getServer().getEndpoint());
85 |
86 | endpoint.getServer().getDestination().setMessageObserver(newMO);
87 |
88 | return endpoint;
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/inbound/As4EnvelopeHeader.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.inbound;
2 |
3 | import lombok.Data;
4 | import network.oxalis.as4.common.As4MessageProperties;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | @Data
10 | public class As4EnvelopeHeader {
11 |
12 | private String messageId;
13 | private String conversationId;
14 |
15 | private List fromPartyId;
16 | private String fromPartyRole;
17 |
18 | private List toPartyId;
19 | private String toPartyRole;
20 |
21 | private String service;
22 | private String action;
23 |
24 | private As4MessageProperties messageProperties = new As4MessageProperties();
25 |
26 | private List payloadCIDs = new ArrayList<>();
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/inbound/As4FaultInHandler.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.inbound;
2 |
3 | import com.google.inject.Inject;
4 | import com.google.inject.Singleton;
5 | import lombok.extern.slf4j.Slf4j;
6 | import network.oxalis.as4.lang.AS4Error;
7 | import network.oxalis.as4.lang.OxalisAs4Exception;
8 | import network.oxalis.as4.util.AS4ErrorCode;
9 | import network.oxalis.as4.util.As4MessageFactory;
10 | import network.oxalis.as4.util.MessageId;
11 | import network.oxalis.api.model.TransmissionIdentifier;
12 | import network.oxalis.api.persist.PersisterHandler;
13 | import org.apache.cxf.interceptor.Fault;
14 | import org.apache.cxf.message.Exchange;
15 | import org.apache.cxf.message.Message;
16 | import org.apache.cxf.phase.PhaseInterceptorChain;
17 | import org.apache.wss4j.common.ext.WSSecurityException;
18 |
19 | import javax.xml.namespace.QName;
20 | import jakarta.xml.soap.SOAPMessage;
21 | import jakarta.xml.ws.WebServiceException;
22 | import jakarta.xml.ws.handler.MessageContext;
23 | import jakarta.xml.ws.handler.soap.SOAPHandler;
24 | import jakarta.xml.ws.handler.soap.SOAPMessageContext;
25 | import java.nio.file.Path;
26 | import java.util.Collections;
27 | import java.util.Optional;
28 | import java.util.Set;
29 |
30 | @Slf4j
31 | @Singleton
32 | public class As4FaultInHandler implements SOAPHandler {
33 |
34 | private final As4MessageFactory as4MessageFactory;
35 | private final PersisterHandler persisterHandler;
36 |
37 | private static final String CERTIFICATE_ERROR_MSG = "Cannot find key for certificate";
38 | private static final String ERROR_CODE_FAILED_CHECK = "FAILED_CHECK";
39 | private static final String FAULT_CODE_FAILED_CHECK = "FailedCheck";
40 | private static final String PEPPOL_NOT_SERVICED = "PEPPOL:NOT_SERVICED";
41 |
42 | @Inject
43 | public As4FaultInHandler(As4MessageFactory as4MessageFactory, PersisterHandler persisterHandler) {
44 | this.as4MessageFactory = as4MessageFactory;
45 | this.persisterHandler = persisterHandler;
46 | }
47 |
48 | @Override
49 | public Set getHeaders() {
50 | return Collections.emptySet();
51 | }
52 |
53 | @Override
54 | public boolean handleMessage(SOAPMessageContext context) {
55 | return true;
56 | }
57 |
58 | @Override
59 | public boolean handleFault(SOAPMessageContext context) {
60 | String messageId = Optional.ofNullable((MessageId) context.get(MessageId.MESSAGE_ID))
61 | .map(MessageId::getValue)
62 | .orElse(null);
63 |
64 | Exception exception = (Exception) context.get(Exception.class.getName());
65 |
66 | if (exception == null) {
67 | return true;
68 | }
69 |
70 | log.info("handleFault for Exception", exception);
71 |
72 | AS4Error as4Error = toAS4Error(exception);
73 |
74 | handleAS4Error(context, messageId, as4Error);
75 |
76 | if (as4Error instanceof OxalisAs4Exception) {
77 | OxalisAs4Exception oxalisAs4Exception = (OxalisAs4Exception) as4Error;
78 | if (PEPPOL_NOT_SERVICED.equals(oxalisAs4Exception.getMessage())) {
79 | context.put(MessageContext.HTTP_RESPONSE_CODE, 200);
80 | context.setScope(MessageContext.HTTP_RESPONSE_CODE, MessageContext.Scope.APPLICATION);
81 | }
82 | }
83 |
84 | return true;
85 | }
86 |
87 | protected void handleAS4Error(SOAPMessageContext context, String messageId, AS4Error as4Error) {
88 | SOAPMessage errorMessage = as4MessageFactory.createErrorMessage(messageId, as4Error);
89 | context.setMessage(errorMessage);
90 |
91 | Path firstPayloadPath = (Path) context.get(AS4MessageContextKey.FIRST_PAYLOAD_PATH);
92 | As4PayloadHeader firstPayloadHeader = (As4PayloadHeader) context.get(AS4MessageContextKey.FIRST_PAYLOAD_HEADER);
93 |
94 | if (messageId != null && firstPayloadPath != null) {
95 | try {
96 | persisterHandler.persist(TransmissionIdentifier.of(messageId), firstPayloadHeader, firstPayloadPath, as4Error.getException());
97 | } catch (Exception e) {
98 | log.error("Unable to persist exception", e);
99 | }
100 | }
101 | }
102 |
103 | @Override
104 | public void close(MessageContext context) {
105 | // Intentionally left empty
106 | }
107 |
108 | public static AS4Error toAS4Error(Throwable t) {
109 | // Is there a better way of getting the inMessage using JAX-WS?
110 | Optional faultMessage = Optional.ofNullable(PhaseInterceptorChain.getCurrentMessage());
111 | Optional inMessage = faultMessage
112 | .map(Message::getExchange)
113 | .map(Exchange::getInMessage);
114 |
115 | if (t instanceof Fault) {
116 | Fault fault = (Fault) t;
117 | t = fault.getCause();
118 | }
119 |
120 | if (t instanceof WebServiceException) {
121 | WebServiceException webServiceException = (WebServiceException) t;
122 | t = webServiceException.getCause();
123 | }
124 |
125 | if (t instanceof WSSecurityException && inMessage.isPresent()) {
126 |
127 | boolean IsSecurityException = false;
128 | String detailSecurityExceptionMessage = "";
129 |
130 | if (null != t.getMessage()) {
131 | detailSecurityExceptionMessage = t.getMessage();
132 | }
133 |
134 | if (null != ((WSSecurityException) t).getErrorCode()) {
135 | String errorCode = ((WSSecurityException) t).getErrorCode().name();
136 | IsSecurityException = errorCode.equalsIgnoreCase(ERROR_CODE_FAILED_CHECK);
137 | }
138 |
139 | if (null != ((WSSecurityException) t).getFaultCode()) {
140 | String faultCode = (null == ((WSSecurityException) t).getFaultCode().getLocalPart() ? "" : ((WSSecurityException) t).getFaultCode().getLocalPart());
141 | IsSecurityException = faultCode.equalsIgnoreCase(FAULT_CODE_FAILED_CHECK);
142 | }
143 |
144 | if (IsSecurityException || detailSecurityExceptionMessage.equalsIgnoreCase(CERTIFICATE_ERROR_MSG)) {
145 | return new OxalisAs4Exception(PEPPOL_NOT_SERVICED, AS4ErrorCode.EBMS_0004, AS4ErrorCode.Severity.FAILURE);
146 | }
147 |
148 | boolean isCompressionError = (boolean) inMessage.get().getOrDefault("oxalis.as4.compressionErrorDetected", false);
149 | if (isCompressionError) {
150 |
151 | return new OxalisAs4Exception(
152 | "Content cannot be compressed after signature/encryption", AS4ErrorCode.EBMS_0303);
153 | }
154 |
155 | return new OxalisAs4Exception(t.getMessage(), t, AS4ErrorCode.EBMS_0009, AS4ErrorCode.Severity.ERROR);
156 | }
157 |
158 | if (t instanceof AS4Error) {
159 | return (AS4Error) t;
160 | }
161 |
162 | return new OxalisAs4Exception(t.getMessage(), t, AS4ErrorCode.EBMS_0004, AS4ErrorCode.Severity.ERROR);
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/inbound/As4InboundMetadata.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.inbound;
2 |
3 | import network.oxalis.api.inbound.InboundMetadata;
4 | import network.oxalis.api.model.TransmissionIdentifier;
5 | import network.oxalis.api.tag.Tag;
6 | import network.oxalis.api.timestamp.Timestamp;
7 | import network.oxalis.vefa.peppol.common.model.*;
8 |
9 | import java.security.cert.X509Certificate;
10 | import java.util.*;
11 |
12 | public class As4InboundMetadata implements InboundMetadata {
13 |
14 | private final TransmissionIdentifier transmissionIdentifier;
15 | private final String conversationId;
16 | private final Header header;
17 | private final Date timestamp;
18 | private final TransportProfile transportProfile;
19 | private final Digest digest;
20 | private final Receipt primaryReceipt;
21 | private final List receipts;
22 | private final X509Certificate certificate;
23 | private final As4EnvelopeHeader as4EnvelopeHeader;
24 |
25 |
26 | public As4InboundMetadata(TransmissionIdentifier transmissionIdentifier, String conversationId, Header header, Timestamp timestamp,
27 | TransportProfile transportProfile, Digest digest, X509Certificate certificate,
28 | byte[] primaryReceipt, As4EnvelopeHeader as4EnvelopeHeader) {
29 | this.transmissionIdentifier = transmissionIdentifier;
30 | this.conversationId = conversationId;
31 | this.header = header;
32 | this.timestamp = timestamp.getDate();
33 | this.transportProfile = transportProfile;
34 | this.digest = digest;
35 | this.certificate = certificate;
36 | this.primaryReceipt = Receipt.of("message/disposition-notification", primaryReceipt);
37 |
38 | List receipts = new ArrayList<>();
39 | receipts.add(this.primaryReceipt);
40 | if (timestamp.getReceipt().isPresent())
41 | receipts.add(timestamp.getReceipt().get());
42 | this.receipts = Collections.unmodifiableList(receipts);
43 |
44 | this.as4EnvelopeHeader = as4EnvelopeHeader;
45 | }
46 |
47 | @Override
48 | public X509Certificate getCertificate() {
49 | return certificate;
50 | }
51 |
52 | @Override
53 | public TransmissionIdentifier getTransmissionIdentifier() {
54 | return transmissionIdentifier;
55 | }
56 |
57 | public String getConversationId() {
58 | return conversationId;
59 | }
60 |
61 | @Override
62 | public Header getHeader() {
63 | return header;
64 | }
65 |
66 | @Override
67 | public Date getTimestamp() {
68 | return timestamp;
69 | }
70 |
71 | @Override
72 | public Digest getDigest() {
73 | return digest;
74 | }
75 |
76 | @Override
77 | public TransportProtocol getTransportProtocol() {
78 | return TransportProtocol.AS4;
79 | }
80 |
81 | @Override
82 | public TransportProfile getProtocol() {
83 | return transportProfile;
84 | }
85 |
86 | @Override
87 | public List getReceipts() {
88 | return receipts;
89 | }
90 |
91 | @Override
92 | public Receipt primaryReceipt() {
93 | return primaryReceipt;
94 | }
95 |
96 | @Override
97 | public Tag getTag() {
98 | return Tag.NONE;
99 | }
100 |
101 | public As4EnvelopeHeader getAs4EnvelopeHeader() {
102 | return as4EnvelopeHeader;
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/inbound/As4InboundModule.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.inbound;
2 |
3 | import com.google.inject.Key;
4 | import com.google.inject.name.Names;
5 | import com.google.inject.servlet.ServletModule;
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.apache.cxf.wsdl.interceptors.AbstractEndpointSelectionInterceptor;
8 |
9 | import jakarta.servlet.http.HttpServlet;
10 |
11 | @Slf4j
12 | public class As4InboundModule extends ServletModule {
13 |
14 | @Override
15 | protected void configureServlets() {
16 | bind(AbstractEndpointSelectionInterceptor.class).to(As4EndpointSelector.class);
17 |
18 | bind(Key.get(HttpServlet.class, Names.named("oxalis-as4")))
19 | .to(As4Servlet.class)
20 | .asEagerSingleton();
21 |
22 | bind(As4Provider.class);
23 | bind(As4EndpointsPublisher.class).to(As4EndpointsPublisherImpl.class);
24 | bind(As4InboundHandler.class);
25 |
26 | serve("/as4").with(Key.get(HttpServlet.class, Names.named("oxalis-as4")));
27 | serve("/as4/status").with(AS4StatusServlet.class);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/inbound/As4Interceptor.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.inbound;
2 |
3 | import com.google.inject.Inject;
4 | import com.google.inject.Singleton;
5 | import lombok.extern.slf4j.Slf4j;
6 | import network.oxalis.as4.lang.OxalisAs4Exception;
7 | import network.oxalis.as4.util.Constants;
8 | import network.oxalis.as4.util.Marshalling;
9 | import network.oxalis.as4.util.MessageId;
10 | import network.oxalis.as4.util.PolicyService;
11 | import org.apache.cxf.binding.soap.SoapMessage;
12 | import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
13 | import org.apache.cxf.headers.Header;
14 | import org.apache.cxf.interceptor.Fault;
15 | import org.apache.cxf.message.Message;
16 | import org.apache.cxf.phase.Phase;
17 | import org.apache.cxf.ws.policy.AssertionInfoMap;
18 | import org.apache.cxf.ws.security.wss4j.PolicyBasedWSS4JStaxInInterceptor;
19 | import org.apache.neethi.Policy;
20 | import org.oasis_open.docs.ebxml_msg.ebms.v3_0.ns.core._200704.CollaborationInfo;
21 | import org.oasis_open.docs.ebxml_msg.ebms.v3_0.ns.core._200704.MessageInfo;
22 | import org.oasis_open.docs.ebxml_msg.ebms.v3_0.ns.core._200704.Messaging;
23 | import org.oasis_open.docs.ebxml_msg.ebms.v3_0.ns.core._200704.UserMessage;
24 | import org.w3c.dom.Node;
25 |
26 | import jakarta.xml.bind.JAXBContext;
27 | import jakarta.xml.bind.JAXBException;
28 | import jakarta.xml.bind.Unmarshaller;
29 | import java.util.Collection;
30 | import java.util.Optional;
31 | import java.util.stream.Stream;
32 |
33 | @Slf4j
34 | @Singleton
35 | public class As4Interceptor extends AbstractSoapInterceptor {
36 |
37 | private final JAXBContext jaxbContext = Marshalling.getInstance();
38 | private final PolicyService policyService;
39 |
40 | @Inject
41 | public As4Interceptor(PolicyService policyService) {
42 | super(Phase.PRE_PROTOCOL);
43 | this.policyService = policyService;
44 | addBefore(PolicyBasedWSS4JStaxInInterceptor.class.getName());
45 | }
46 |
47 | @Override
48 | public void handleMessage(SoapMessage message) throws Fault {
49 | Messaging messaging = getMessaging(message);
50 |
51 | storeMessageIdInContext(message, messaging);
52 |
53 | Optional userMessage = Optional.ofNullable(messaging)
54 | .map(Messaging::getUserMessage)
55 | .map(Collection::stream).orElseGet(Stream::empty)
56 | .findFirst();
57 |
58 | try {
59 | Policy policy = userMessage.isPresent()
60 | ? policyService.getPolicy(userMessage.get().getCollaborationInfo())
61 | : policyService.getPolicy();
62 | message.put(AssertionInfoMap.class.getName(), new AssertionInfoMap(policy));
63 | } catch (Exception e) {
64 | throw new Fault(e);
65 | }
66 | }
67 |
68 | private Messaging getMessaging(Message message) {
69 | SoapMessage soapMessage = (SoapMessage) message;
70 | Header header = soapMessage.getHeader(Constants.MESSAGING_QNAME);
71 |
72 | try {
73 | Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
74 | return unmarshaller.unmarshal((Node) header.getObject(), Messaging.class).getValue();
75 | } catch (JAXBException e) {
76 | throw new Fault(e);
77 | }
78 | }
79 |
80 | private void storeMessageIdInContext(Message message, Messaging messaging) throws Fault {
81 | String messageId = Optional.ofNullable(messaging)
82 | .map(Messaging::getUserMessage)
83 | .map(Collection::stream).orElseGet(Stream::empty)
84 | .map(UserMessage::getMessageInfo)
85 | .map(MessageInfo::getMessageId)
86 | .findFirst()
87 | .orElseThrow(() -> new Fault(new OxalisAs4Exception("MessageID is missing from UserMessage")));
88 |
89 | message.put(MessageId.MESSAGE_ID, new MessageId(messageId));
90 |
91 | Optional.ofNullable(messaging)
92 | .map(Messaging::getUserMessage)
93 | .map(Collection::stream).orElseGet(Stream::empty)
94 | .map(UserMessage::getCollaborationInfo)
95 | .map(CollaborationInfo::getConversationId)
96 | .findFirst()
97 | .ifPresent(conversationId -> message.put("oxalis.as4.conversationId", conversationId));
98 | }
99 |
100 |
101 | }
102 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/inbound/As4PayloadHeader.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.inbound;
2 |
3 | import lombok.Getter;
4 | import lombok.ToString;
5 | import network.oxalis.vefa.peppol.common.model.*;
6 |
7 | import jakarta.xml.soap.MimeHeader;
8 | import java.util.Collection;
9 | import java.util.Date;
10 | import java.util.List;
11 |
12 | @Getter
13 | @ToString
14 | public class As4PayloadHeader extends Header {
15 |
16 | private final Header header;
17 | private final Collection mimeHeaders;
18 | private final String cid;
19 |
20 | private final String conversationId;
21 |
22 | public As4PayloadHeader(Header header, Collection mimeHeaders, String cid, String conversationId) {
23 | this.header = header;
24 | this.mimeHeaders = mimeHeaders;
25 | this.cid = cid;
26 | this.conversationId = conversationId;
27 | }
28 |
29 | @Override
30 | public Header sender(ParticipantIdentifier sender) {
31 | return header.sender(sender);
32 | }
33 |
34 | @Override
35 | public Header receiver(ParticipantIdentifier receiver) {
36 | return header.receiver(receiver);
37 | }
38 |
39 | @Override
40 | public Header process(ProcessIdentifier process) {
41 | return header.process(process);
42 | }
43 |
44 | @Override
45 | public Header documentType(DocumentTypeIdentifier documentType) {
46 | return header.documentType(documentType);
47 | }
48 |
49 | @Override
50 | public Header identifier(InstanceIdentifier identifier) {
51 | return header.identifier(identifier);
52 | }
53 |
54 | @Override
55 | public Header instanceType(InstanceType instanceType) {
56 | return header.instanceType(instanceType);
57 | }
58 |
59 | @Override
60 | public Header creationTimestamp(Date creationTimestamp) {
61 | return header.creationTimestamp(creationTimestamp);
62 | }
63 |
64 | @Override
65 | public Header c1CountryIdentifier(C1CountryIdentifier c1CountryIdentifier) {
66 | return header.c1CountryIdentifier(c1CountryIdentifier);
67 | }
68 |
69 | @Override
70 | public Header argument(ArgumentIdentifier identifier) {
71 | return header.argument(identifier);
72 | }
73 |
74 | @Override
75 | public Header arguments(List extras) {
76 | return header.arguments(extras);
77 | }
78 |
79 | @Override
80 | public ArgumentIdentifier getArgument(String key) {
81 | return header.getArgument(key);
82 | }
83 |
84 | @Override
85 | public List getArguments() {
86 | return header.getArguments();
87 | }
88 |
89 | @Override
90 | public boolean equals(Object o) {
91 | return header.equals(o);
92 | }
93 |
94 | @Override
95 | public int hashCode() {
96 | return header.hashCode();
97 | }
98 |
99 | @Override
100 | public ParticipantIdentifier getSender() {
101 | return header.getSender();
102 | }
103 |
104 | @Override
105 | public ParticipantIdentifier getReceiver() {
106 | return header.getReceiver();
107 | }
108 |
109 | @Override
110 | public ProcessIdentifier getProcess() {
111 | return header.getProcess();
112 | }
113 |
114 | @Override
115 | public DocumentTypeIdentifier getDocumentType() {
116 | return header.getDocumentType();
117 | }
118 |
119 | @Override
120 | public InstanceIdentifier getIdentifier() {
121 | return header.getIdentifier();
122 | }
123 |
124 | @Override
125 | public InstanceType getInstanceType() {
126 | return header.getInstanceType();
127 | }
128 |
129 | @Override
130 | public Date getCreationTimestamp() {
131 | return header.getCreationTimestamp();
132 | }
133 |
134 | @Override
135 | public C1CountryIdentifier getC1CountryIdentifier() {
136 | return header.getC1CountryIdentifier();
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/inbound/As4Provider.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.inbound;
2 |
3 | import com.google.inject.Inject;
4 | import com.google.inject.Singleton;
5 | import network.oxalis.as4.lang.OxalisAs4Exception;
6 | import org.apache.cxf.transport.http.AbstractHTTPDestination;
7 |
8 | import jakarta.annotation.Resource;
9 | import jakarta.servlet.http.HttpServletResponse;
10 | import jakarta.xml.soap.SOAPMessage;
11 | import jakarta.xml.ws.*;
12 | import jakarta.xml.ws.handler.MessageContext;
13 | import jakarta.xml.ws.soap.SOAPBinding;
14 |
15 | @WebServiceProvider
16 | @ServiceMode(value = Service.Mode.MESSAGE)
17 | @BindingType(value = SOAPBinding.SOAP12HTTP_BINDING)
18 | @Singleton
19 | public class As4Provider implements Provider {
20 |
21 | @Resource
22 | private WebServiceContext context;
23 |
24 | @Inject
25 | private As4InboundHandler handler;
26 |
27 | @Override
28 | public SOAPMessage invoke(SOAPMessage request) {
29 | MessageContext messageContext = context.getMessageContext();
30 | HttpServletResponse httpRes = (HttpServletResponse) messageContext.get(AbstractHTTPDestination.HTTP_RESPONSE);
31 | httpRes.setStatus(HttpServletResponse.SC_OK);
32 |
33 | try {
34 | return handler.handle(request, messageContext);
35 | } catch (OxalisAs4Exception e) {
36 | httpRes.setStatus(HttpServletResponse.SC_BAD_REQUEST);
37 | throw new WebServiceException(e);
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/inbound/As4Servlet.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.inbound;
2 |
3 | import com.google.inject.Inject;
4 | import com.google.inject.Singleton;
5 | import lombok.extern.slf4j.Slf4j;
6 | import network.oxalis.as4.common.MerlinProvider;
7 | import network.oxalis.api.settings.Settings;
8 | import network.oxalis.commons.security.KeyStoreConf;
9 | import org.apache.cxf.BusFactory;
10 | import org.apache.cxf.ext.logging.LoggingFeature;
11 | import org.apache.cxf.jaxws.EndpointImpl;
12 | import org.apache.cxf.transport.servlet.CXFNonSpringServlet;
13 | import org.apache.cxf.ws.security.wss4j.PolicyBasedWSS4JInInterceptor;
14 | import org.apache.cxf.ws.security.wss4j.PolicyBasedWSS4JOutInterceptor;
15 | import org.apache.wss4j.common.crypto.Merlin;
16 |
17 | import jakarta.servlet.ServletConfig;
18 | import jakarta.servlet.ServletException;
19 | import jakarta.servlet.http.HttpServletRequest;
20 | import jakarta.servlet.http.HttpServletResponse;
21 | import java.io.IOException;
22 |
23 | import static org.apache.cxf.rt.security.SecurityConstants.*;
24 |
25 | @Slf4j
26 | @Singleton
27 | public class As4Servlet extends CXFNonSpringServlet {
28 |
29 | @Inject
30 | private Settings settings;
31 |
32 | @Inject
33 | private As4EndpointsPublisher endpointsPublisher;
34 |
35 | @Inject
36 | private MerlinProvider merlinProvider;
37 |
38 | @Override
39 | protected void loadBus(ServletConfig servletConfig) {
40 | this.bus = BusFactory.getThreadDefaultBus();
41 |
42 | EndpointImpl endpointImpl = endpointsPublisher.publish(getBus());
43 |
44 | Merlin merlin = merlinProvider.getMerlin();
45 |
46 | endpointImpl.getProperties().put(SIGNATURE_CRYPTO, merlin);
47 | endpointImpl.getProperties().put(SIGNATURE_PASSWORD, settings.getString(KeyStoreConf.KEY_PASSWORD));
48 | endpointImpl.getProperties().put(SIGNATURE_USERNAME, settings.getString(KeyStoreConf.KEY_ALIAS));
49 |
50 | endpointImpl.getProperties().put(ENCRYPT_CRYPTO, merlin);
51 | endpointImpl.getProperties().put(ENCRYPT_USERNAME, settings.getString(KeyStoreConf.KEY_ALIAS));
52 |
53 | endpointImpl.getInInterceptors().add(new PolicyBasedWSS4JInInterceptor());
54 | endpointImpl.getOutInterceptors().add(new PolicyBasedWSS4JOutInterceptor());
55 |
56 | endpointImpl.getFeatures().add(new LoggingFeature());
57 | }
58 |
59 | @Override
60 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException {
61 | try {
62 | response.setStatus(HttpServletResponse.SC_OK);
63 | response.getWriter().write("Hello AS4 world\n");
64 | } catch (IOException e) {
65 | throw new ServletException("Unable to send response", e);
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/inbound/AttachmentCleanupInterceptor.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.inbound;
2 |
3 | import lombok.SneakyThrows;
4 | import org.apache.cxf.attachment.As4AttachmentDataSource;
5 | import org.apache.cxf.attachment.As4AttachmentDeserializer;
6 | import org.apache.cxf.interceptor.Fault;
7 | import org.apache.cxf.message.Attachment;
8 | import org.apache.cxf.message.Exchange;
9 | import org.apache.cxf.message.Message;
10 | import org.apache.cxf.phase.AbstractPhaseInterceptor;
11 | import org.apache.cxf.phase.Phase;
12 |
13 | import jakarta.activation.DataSource;
14 |
15 | public class AttachmentCleanupInterceptor extends AbstractPhaseInterceptor {
16 |
17 | public AttachmentCleanupInterceptor() {
18 | super(Phase.POST_INVOKE);
19 | }
20 |
21 | public void handleMessage(Message message) throws Fault {
22 | Exchange exchange = message.getExchange();
23 | cleanRequestAttachment(exchange);
24 | }
25 |
26 | private void cleanRequestAttachment(Exchange exchange) {
27 | As4AttachmentDeserializer ad = exchange.getInMessage().get(As4AttachmentDeserializer.class);
28 | ad.getRemoved().forEach(this::close);
29 | }
30 |
31 | @SneakyThrows
32 | private void close(Attachment attachment) {
33 | DataSource dataSource = attachment.getDataHandler().getDataSource();
34 |
35 | if (dataSource instanceof As4AttachmentDataSource) {
36 | As4AttachmentDataSource ads = (As4AttachmentDataSource) dataSource;
37 | ads.closeAll();
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/inbound/MessagingHandler.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.inbound;
2 |
3 | import javax.xml.namespace.QName;
4 | import jakarta.xml.ws.handler.MessageContext;
5 | import jakarta.xml.ws.handler.soap.SOAPHandler;
6 | import jakarta.xml.ws.handler.soap.SOAPMessageContext;
7 | import java.util.Collections;
8 | import java.util.Set;
9 |
10 | public class MessagingHandler implements SOAPHandler {
11 | @Override
12 | public Set getHeaders() {
13 |
14 | QName messagingHeader = new QName(
15 | "http://docs.oasis-open.org/ebxml-msg/ebms/v3.0/ns/core/200704/",
16 | "Messaging"
17 | );
18 |
19 | return Collections.singleton(messagingHeader);
20 | }
21 |
22 | @Override
23 | public boolean handleMessage(SOAPMessageContext context) {
24 | return true;
25 | }
26 |
27 | @Override
28 | public boolean handleFault(SOAPMessageContext context) {
29 | return true;
30 | }
31 |
32 | @Override
33 | public void close(MessageContext context) {
34 |
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/inbound/OxalisAS4Version.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010-2018 Norwegian Agency for Public Management and eGovernment (Difi)
3 | *
4 | * Licensed under the EUPL, Version 1.1 or – as soon they
5 | * will be approved by the European Commission - subsequent
6 | * versions of the EUPL (the "Licence");
7 | *
8 | * You may not use this work except in compliance with the Licence.
9 | *
10 | * You may obtain a copy of the Licence at:
11 | *
12 | * https://joinup.ec.europa.eu/community/eupl/og_page/eupl
13 | *
14 | * Unless required by applicable law or agreed to in
15 | * writing, software distributed under the Licence is
16 | * distributed on an "AS IS" basis,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
18 | * express or implied.
19 | * See the Licence for the specific language governing
20 | * permissions and limitations under the Licence.
21 | */
22 |
23 | package network.oxalis.as4.inbound;
24 |
25 | import network.oxalis.api.lang.OxalisLoadingException;
26 |
27 | import java.io.IOException;
28 | import java.io.InputStream;
29 | import java.util.Properties;
30 |
31 | /**
32 | * Provides access to selected Maven injected properties in the oxalis-as4-version.properties file.
33 | */
34 | public class OxalisAS4Version {
35 |
36 | private static Properties properties;
37 |
38 | static {
39 | try (InputStream inputStream = OxalisAS4Version.class.getResourceAsStream("/oxalis-as4-version.properties")) {
40 | properties = new Properties();
41 | properties.load(inputStream);
42 | } catch (IOException e) {
43 | throw new OxalisLoadingException(e.getMessage(), e);
44 | }
45 | }
46 |
47 | /**
48 | * The Oxalis version, taken from the POM
49 | */
50 | public static String getVersion() {
51 | return properties.getProperty("oxalis.version");
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/inbound/ProsessingContext.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.inbound;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Getter;
5 | import network.oxalis.api.timestamp.Timestamp;
6 | import org.w3.xmldsig.ReferenceType;
7 |
8 | import java.util.List;
9 |
10 | @Getter
11 | @AllArgsConstructor
12 | public class ProsessingContext {
13 |
14 | private Timestamp receiptTimestamp;
15 | private List referenceList;
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/inbound/SetPolicyInInterceptor.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.inbound;
2 |
3 | import com.google.inject.Inject;
4 | import com.google.inject.Singleton;
5 | import lombok.extern.slf4j.Slf4j;
6 | import network.oxalis.as4.util.PolicyService;
7 | import org.apache.cxf.phase.Phase;
8 | import org.apache.cxf.ws.policy.PolicyInInterceptor;
9 |
10 | @Slf4j
11 | @Singleton
12 | public class SetPolicyInInterceptor extends AbstractSetPolicyInterceptor {
13 |
14 | @Inject
15 | public SetPolicyInInterceptor(PolicyService policyService) {
16 | super(Phase.RECEIVE, policyService);
17 | addBefore(PolicyInInterceptor.class.getName());
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/inbound/SetPolicyOutInterceptor.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.inbound;
2 |
3 | import com.google.inject.Inject;
4 | import com.google.inject.Singleton;
5 | import lombok.extern.slf4j.Slf4j;
6 | import network.oxalis.as4.util.PolicyService;
7 | import org.apache.cxf.phase.Phase;
8 | import org.apache.cxf.ws.policy.PolicyOutInterceptor;
9 |
10 | @Slf4j
11 | @Singleton
12 | public class SetPolicyOutInterceptor extends AbstractSetPolicyInterceptor {
13 |
14 | @Inject
15 | public SetPolicyOutInterceptor(PolicyService policyService) {
16 | super(Phase.SETUP, policyService);
17 | addBefore(PolicyOutInterceptor.class.getName());
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/lang/AS4Error.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.lang;
2 |
3 | import network.oxalis.as4.util.AS4ErrorCode;
4 |
5 | public interface AS4Error {
6 |
7 | AS4ErrorCode getErrorCode();
8 |
9 | AS4ErrorCode.Severity getSeverity();
10 |
11 | String getMessage();
12 |
13 | Exception getException();
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/lang/OxalisAs4Exception.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.lang;
2 |
3 | import network.oxalis.api.lang.OxalisException;
4 | import network.oxalis.as4.util.AS4ErrorCode;
5 |
6 | public class OxalisAs4Exception extends OxalisException implements AS4Error {
7 |
8 | private AS4ErrorCode errorCode = AS4ErrorCode.EBMS_0004;
9 | private AS4ErrorCode.Severity severity = AS4ErrorCode.Severity.ERROR;
10 |
11 | public OxalisAs4Exception(String message) {
12 | super(message);
13 | }
14 |
15 | public OxalisAs4Exception(String message, Throwable cause) {
16 | super(message, cause);
17 | }
18 |
19 | public OxalisAs4Exception(String message, AS4ErrorCode errorCode) {
20 | super(message);
21 | this.errorCode = errorCode;
22 | }
23 |
24 | public OxalisAs4Exception(String message, AS4ErrorCode errorCode, AS4ErrorCode.Severity severity) {
25 | super(message);
26 | this.errorCode = errorCode;
27 | this.severity = severity;
28 | }
29 |
30 | public OxalisAs4Exception(String message, Throwable cause, AS4ErrorCode errorCode) {
31 | super(message, cause);
32 | this.errorCode = errorCode;
33 | }
34 |
35 | public OxalisAs4Exception(String message, Throwable cause, AS4ErrorCode errorCode, AS4ErrorCode.Severity severity) {
36 | super(message, cause);
37 | this.errorCode = errorCode;
38 | this.severity = severity;
39 | }
40 |
41 |
42 | public AS4ErrorCode getErrorCode() {
43 | return errorCode;
44 | }
45 |
46 | public AS4ErrorCode.Severity getSeverity() {
47 | return severity;
48 | }
49 |
50 | @Override
51 | public Exception getException() {
52 | return this;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/lang/OxalisAs4TransmissionException.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.lang;
2 |
3 | import network.oxalis.api.lang.OxalisTransmissionException;
4 | import network.oxalis.as4.util.AS4ErrorCode;
5 |
6 | import java.net.URI;
7 |
8 | public class OxalisAs4TransmissionException extends OxalisTransmissionException implements AS4Error {
9 |
10 | private AS4ErrorCode errorCode = AS4ErrorCode.EBMS_0004;
11 | private AS4ErrorCode.Severity severity = AS4ErrorCode.Severity.ERROR;
12 |
13 | public OxalisAs4TransmissionException(String message) {
14 | super(message);
15 | }
16 |
17 | public OxalisAs4TransmissionException(String message, AS4ErrorCode errorCode, AS4ErrorCode.Severity severity) {
18 | super(message);
19 | this.errorCode = errorCode;
20 | this.severity = severity;
21 | }
22 |
23 | public OxalisAs4TransmissionException(String message, Throwable cause) {
24 | super(message, cause);
25 | }
26 |
27 | public OxalisAs4TransmissionException(URI url, Throwable cause) {
28 | super(url, cause);
29 | }
30 |
31 | public OxalisAs4TransmissionException(String msg, URI url, Throwable e) {
32 | super(msg, url, e);
33 | }
34 |
35 | @Override
36 | public AS4ErrorCode getErrorCode() {
37 | return errorCode;
38 | }
39 |
40 | @Override
41 | public AS4ErrorCode.Severity getSeverity() {
42 | return severity;
43 | }
44 |
45 | @Override
46 | public Exception getException() {
47 | return this;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/outbound/ActionProvider.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.outbound;
2 |
3 | import network.oxalis.vefa.peppol.common.model.DocumentTypeIdentifier;
4 |
5 | public interface ActionProvider {
6 |
7 | String getAction(DocumentTypeIdentifier documentTypeIdentifier);
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/outbound/As4MessageSenderFacade.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.outbound;
2 |
3 | import com.google.inject.Inject;
4 | import network.oxalis.api.lang.OxalisTransmissionException;
5 | import network.oxalis.api.outbound.MessageSender;
6 | import network.oxalis.api.outbound.TransmissionRequest;
7 | import network.oxalis.api.outbound.TransmissionResponse;
8 |
9 | public class As4MessageSenderFacade implements MessageSender {
10 |
11 | private As4MessageSender messageSender;
12 |
13 | @Inject
14 | public As4MessageSenderFacade(As4MessageSender messageSender) {
15 | this.messageSender = messageSender;
16 | }
17 |
18 | @Override
19 | public TransmissionResponse send(TransmissionRequest transmissionRequest) throws OxalisTransmissionException {
20 | return messageSender.send(transmissionRequest);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/outbound/As4OutboundModule.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.outbound;
2 |
3 | import com.google.inject.*;
4 | import com.google.inject.name.Names;
5 | import lombok.extern.slf4j.Slf4j;
6 | import network.oxalis.as4.common.AS4Constants;
7 | import network.oxalis.as4.config.As4Conf;
8 | import network.oxalis.as4.util.CompressionUtil;
9 | import network.oxalis.as4.util.PeppolConfiguration;
10 | import network.oxalis.api.outbound.MessageSender;
11 | import network.oxalis.api.settings.Settings;
12 | import org.bouncycastle.jce.provider.BouncyCastleProvider;
13 |
14 | import java.security.Security;
15 | import java.util.concurrent.ExecutorService;
16 | import java.util.concurrent.Executors;
17 |
18 | @Slf4j
19 | public class As4OutboundModule extends AbstractModule {
20 |
21 | @Override
22 | protected void configure() {
23 | if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
24 | Security.addProvider(new BouncyCastleProvider());
25 | }
26 |
27 | bind(Key.get(MessageSender.class, Names.named("oxalis-as4")))
28 | .to(As4MessageSenderFacade.class);
29 |
30 | bind(Key.get(ExecutorService.class, Names.named("compression-pool")))
31 | .toProvider(() -> Executors.newFixedThreadPool(5)).in(Scopes.SINGLETON);
32 |
33 | bind(CompressionUtil.class);
34 |
35 | bind(MessagingProvider.class);
36 |
37 | bind(As4MessageSender.class);
38 |
39 | bind(TransmissionResponseConverter.class);
40 | }
41 |
42 | @Provides
43 | @Singleton
44 | public PeppolConfiguration getPeppolOutboundConfiguration(Settings settings) {
45 | String type = settings.getString(As4Conf.TYPE);
46 |
47 | if (AS4Constants.CEF_CONNECTIVITY.equalsIgnoreCase(type)) {
48 | return new PeppolConfiguration() {
49 |
50 | @Override
51 | public String getPartyIDType() {
52 | return "urn:oasis:names:tc:ebcore:partyid-type:unregistered";
53 | }
54 |
55 | @Override
56 | public String getAgreementRef() {
57 | return null;
58 | }
59 | };
60 | }
61 |
62 | return new PeppolConfiguration();
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/outbound/As4TransmissionRequest.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.outbound;
2 |
3 | import network.oxalis.as4.common.As4MessageProperties;
4 | import network.oxalis.api.outbound.TransmissionRequest;
5 |
6 | import java.nio.charset.Charset;
7 |
8 | public interface As4TransmissionRequest extends TransmissionRequest {
9 |
10 | String getRefToMessageId();
11 |
12 | String getMessageId();
13 |
14 | String getConversationId();
15 |
16 | As4MessageProperties getMessageProperties();
17 |
18 | String getPayloadHref();
19 |
20 | Charset getPayloadCharset();
21 |
22 | String getCompressionType();
23 |
24 | boolean isPing();
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/outbound/As4TransmissionResponse.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.outbound;
2 |
3 | import network.oxalis.api.model.TransmissionIdentifier;
4 | import network.oxalis.api.outbound.TransmissionRequest;
5 | import network.oxalis.api.outbound.TransmissionResponse;
6 | import network.oxalis.api.timestamp.Timestamp;
7 | import network.oxalis.as4.lang.OxalisAs4TransmissionException;
8 | import network.oxalis.vefa.peppol.common.model.*;
9 |
10 | import java.util.ArrayList;
11 | import java.util.Collections;
12 | import java.util.Date;
13 | import java.util.List;
14 |
15 | public class As4TransmissionResponse implements TransmissionResponse {
16 |
17 | // Original transmission request is kept to allow easy access to immutable objects part of the request.
18 | private final TransmissionRequest transmissionRequest;
19 | private final TransmissionIdentifier transmissionIdentifier;
20 | private final Digest digest;
21 | private final Receipt receipt;
22 | private final List receipts;
23 | private final Date timestamp;
24 | private final OxalisAs4TransmissionException transmissionException;
25 |
26 | public As4TransmissionResponse(TransmissionIdentifier transmissionIdentifier,
27 | TransmissionRequest transmissionRequest, Digest digest,
28 | byte[] nativeEvidenceBytes, Timestamp timestamp, Date date) {
29 | this.transmissionIdentifier = transmissionIdentifier;
30 | this.transmissionRequest = transmissionRequest;
31 | this.digest = digest;
32 | this.receipt = Receipt.of("message/disposition-notification", nativeEvidenceBytes);
33 | this.timestamp = date;
34 | this.transmissionException = null;
35 |
36 | List receiptList = new ArrayList<>();
37 | receiptList.add(receipt);
38 | timestamp.getReceipt().ifPresent(receiptList::add);
39 |
40 | this.receipts = Collections.unmodifiableList(receiptList);
41 | }
42 |
43 | public As4TransmissionResponse(TransmissionIdentifier transmissionIdentifier, TransmissionRequest transmissionRequest, OxalisAs4TransmissionException transmissionException) {
44 | this.transmissionRequest = transmissionRequest;
45 | this.transmissionIdentifier = transmissionIdentifier;
46 | this.transmissionException = transmissionException;
47 | this.digest = null;
48 | this.receipt = null;
49 | this.receipts = null;
50 | this.timestamp = null;
51 | }
52 |
53 | @Override
54 | public Header getHeader() {
55 | return transmissionRequest.getHeader();
56 | }
57 |
58 | public TransmissionIdentifier getTransmissionIdentifier() {
59 | return transmissionIdentifier;
60 | }
61 |
62 | @Override
63 | public List getReceipts() {
64 | return receipts;
65 | }
66 |
67 | @Override
68 | public Endpoint getEndpoint() {
69 | return transmissionRequest.getEndpoint();
70 | }
71 |
72 | @Override
73 | public Receipt primaryReceipt() {
74 | return receipt;
75 | }
76 |
77 | @Override
78 | public Digest getDigest() {
79 | return digest;
80 | }
81 |
82 | @Override
83 | public TransportProtocol getTransportProtocol() {
84 | return TransportProtocol.AS4;
85 | }
86 |
87 | @Override
88 | public Date getTimestamp() {
89 | return timestamp;
90 | }
91 |
92 | public OxalisAs4TransmissionException getTransmissionException() {
93 | return transmissionException;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/outbound/BrowserTypeProvider.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.outbound;
2 |
3 | import com.google.inject.Inject;
4 | import com.google.inject.Singleton;
5 | import lombok.extern.slf4j.Slf4j;
6 | import network.oxalis.as4.inbound.OxalisAS4Version;
7 | import network.oxalis.commons.util.OxalisVersion;
8 | import org.bouncycastle.asn1.x500.RDN;
9 | import org.bouncycastle.asn1.x500.X500Name;
10 | import org.bouncycastle.asn1.x500.style.BCStyle;
11 | import org.bouncycastle.asn1.x500.style.IETFUtils;
12 | import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
13 |
14 | import java.security.cert.CertificateEncodingException;
15 | import java.security.cert.X509Certificate;
16 |
17 | @Slf4j
18 | @Singleton
19 | public class BrowserTypeProvider {
20 |
21 | private final X509Certificate certificate;
22 |
23 | @Inject
24 | public BrowserTypeProvider(X509Certificate certificate) {
25 | this.certificate = certificate;
26 | }
27 |
28 | public String getBrowserType() {
29 | return String.format("Oxalis %s / AS4 %s / %s",
30 | OxalisVersion.getVersion(),
31 | OxalisAS4Version.getVersion(),
32 | getCN());
33 | }
34 |
35 | private String getCN() {
36 | try {
37 | X500Name x500name = new JcaX509CertificateHolder(certificate).getSubject();
38 | RDN cn = x500name.getRDNs(BCStyle.CN)[0];
39 | return IETFUtils.valueToString(cn.getFirst().getValue());
40 | } catch (CertificateEncodingException e) {
41 | log.warn("Could not extract CN from certificate", e);
42 | return "Unknown";
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/outbound/DefaultActionProvider.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.outbound;
2 |
3 | import network.oxalis.as4.util.TransmissionRequestUtil;
4 | import network.oxalis.vefa.peppol.common.model.DocumentTypeIdentifier;
5 |
6 | public class DefaultActionProvider implements ActionProvider {
7 | @Override
8 | public String getAction(DocumentTypeIdentifier documentTypeIdentifier) {
9 | return TransmissionRequestUtil.translateDocumentTypeToAction(documentTypeIdentifier);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/outbound/LoggingBeforeSecurityInInterceptor.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.outbound;
2 |
3 | import org.apache.cxf.common.injection.NoJSR250Annotations;
4 | import org.apache.cxf.common.util.StringUtils;
5 | import org.apache.cxf.ext.logging.AbstractLoggingInterceptor;
6 | import org.apache.cxf.ext.logging.event.LogEvent;
7 | import org.apache.cxf.ext.logging.event.LogEventSender;
8 | import org.apache.cxf.ext.logging.event.PrintWriterEventSender;
9 | import org.apache.cxf.ext.logging.slf4j.Slf4jVerboseEventSender;
10 | import org.apache.cxf.interceptor.Fault;
11 | import org.apache.cxf.io.CachedOutputStream;
12 | import org.apache.cxf.io.CachedWriter;
13 | import org.apache.cxf.message.Message;
14 | import org.apache.cxf.phase.Phase;
15 |
16 | import java.io.IOException;
17 | import java.io.PrintWriter;
18 | import java.nio.charset.StandardCharsets;
19 |
20 | @NoJSR250Annotations
21 | public class LoggingBeforeSecurityInInterceptor extends AbstractLoggingInterceptor {
22 |
23 | public LoggingBeforeSecurityInInterceptor() {
24 | this(new Slf4jVerboseEventSender());
25 | }
26 |
27 | public LoggingBeforeSecurityInInterceptor(PrintWriter writer) {
28 | this(new PrintWriterEventSender(writer));
29 | }
30 |
31 | public LoggingBeforeSecurityInInterceptor(LogEventSender sender) {
32 | super(Phase.RECEIVE, sender);
33 | }
34 |
35 | public void handleMessage(Message message) throws Fault {
36 | if (isLoggingDisabledNow(message)) {
37 | return;
38 | }
39 | createExchangeId(message);
40 | final LogEvent event = eventMapper.map(message);
41 | if (shouldLogContent(event)) {
42 | addContent(message, event);
43 | } else {
44 | event.setPayload(AbstractLoggingInterceptor.CONTENT_SUPPRESSED);
45 | }
46 | sender.send(event);
47 | }
48 |
49 | private void addContent(Message message, final LogEvent event) {
50 | try {
51 | CachedOutputStream cos = message.getContent(CachedOutputStream.class);
52 | if (cos != null) {
53 | handleOutputStream(event, message, cos);
54 | } else {
55 | CachedWriter writer = message.getContent(CachedWriter.class);
56 | if (writer != null) {
57 | handleWriter(event, writer);
58 | }
59 | }
60 | } catch (IOException e) {
61 | throw new Fault(e);
62 | }
63 | }
64 |
65 | private void handleOutputStream(final LogEvent event, Message message, CachedOutputStream cos) throws IOException {
66 | String encoding = (String) message.get(Message.ENCODING);
67 | if (StringUtils.isEmpty(encoding)) {
68 | encoding = StandardCharsets.UTF_8.name();
69 | }
70 | StringBuilder payload = new StringBuilder();
71 | cos.writeCacheTo(payload, encoding, limit);
72 | cos.close();
73 | event.setPayload(payload.toString());
74 | boolean isTruncated = cos.size() > limit && limit != -1;
75 | event.setTruncated(isTruncated);
76 | event.setFullContentFile(cos.getTempFile());
77 | }
78 |
79 | private void handleWriter(final LogEvent event, CachedWriter writer) throws IOException {
80 | boolean isTruncated = writer.size() > limit && limit != -1;
81 | StringBuilder payload = new StringBuilder();
82 | writer.writeCacheTo(payload, limit);
83 | writer.close();
84 | event.setPayload(payload.toString());
85 | event.setTruncated(isTruncated);
86 | event.setFullContentFile(writer.getTempFile());
87 | }
88 |
89 | int getWireTapLimit() {
90 | if (limit == -1) {
91 | return -1;
92 | } else if (limit == Integer.MAX_VALUE) {
93 | return limit;
94 | } else {
95 | // add limit +1 as limit for the wiretab in order to read one byte more, so that truncated
96 | // is correctly calculated in LogginInIntecepteor!
97 | // See code line : boolean isTruncated = cos.size() > limit && limit != -1;
98 | // cos is here the outputstream read by the wiretab which will return for cos.size() the
99 | // limit in the truncated case!
100 | return limit + 1;
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/outbound/TransmissionResponseConverter.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.outbound;
2 |
3 | import com.google.inject.Inject;
4 | import network.oxalis.api.lang.TimestampException;
5 | import network.oxalis.api.model.Direction;
6 | import network.oxalis.api.model.TransmissionIdentifier;
7 | import network.oxalis.api.outbound.TransmissionRequest;
8 | import network.oxalis.api.outbound.TransmissionResponse;
9 | import network.oxalis.api.timestamp.Timestamp;
10 | import network.oxalis.api.timestamp.TimestampProvider;
11 | import network.oxalis.as4.lang.OxalisAs4TransmissionException;
12 | import network.oxalis.as4.util.AS4ErrorCode;
13 | import network.oxalis.as4.util.Marshalling;
14 | import network.oxalis.commons.bouncycastle.BCHelper;
15 | import network.oxalis.vefa.peppol.common.code.DigestMethod;
16 | import network.oxalis.vefa.peppol.common.model.Digest;
17 | import org.oasis_open.docs.ebxml_msg.ebms.v3_0.ns.core._200704.Error;
18 | import org.oasis_open.docs.ebxml_msg.ebms.v3_0.ns.core._200704.SignalMessage;
19 | import org.w3c.dom.Node;
20 | import org.w3c.dom.NodeList;
21 |
22 | import jakarta.xml.bind.JAXBContext;
23 | import jakarta.xml.bind.JAXBException;
24 | import jakarta.xml.bind.Unmarshaller;
25 | import jakarta.xml.soap.SOAPException;
26 | import jakarta.xml.soap.SOAPMessage;
27 | import java.io.ByteArrayOutputStream;
28 | import java.io.IOException;
29 | import java.security.MessageDigest;
30 | import java.security.NoSuchAlgorithmException;
31 |
32 | import static network.oxalis.as4.util.Constants.DIGEST_ALGORITHM_SHA256;
33 |
34 | public class TransmissionResponseConverter {
35 |
36 | private final JAXBContext jaxbContext = Marshalling.getInstance();
37 | private final TimestampProvider timestampProvider;
38 |
39 | @Inject
40 | public TransmissionResponseConverter(TimestampProvider timestampProvider) {
41 | this.timestampProvider = timestampProvider;
42 | }
43 |
44 | public TransmissionResponse convert(TransmissionRequest request, SOAPMessage response) throws OxalisAs4TransmissionException {
45 | SignalMessage signalMessage = getSignalMessage(response);
46 |
47 | String refToMessageId = signalMessage.getMessageInfo().getRefToMessageId();
48 | TransmissionIdentifier ti = TransmissionIdentifier.of(refToMessageId);
49 |
50 | if (!signalMessage.getError().isEmpty()) {
51 | Error error = signalMessage.getError().get(0);
52 |
53 | throw new OxalisAs4TransmissionException(
54 | error.getErrorDetail(),
55 | AS4ErrorCode.nameOf(error.getErrorCode()),
56 | AS4ErrorCode.Severity.nameOf(error.getSeverity()));
57 | }
58 |
59 | Timestamp ts = getTimestamp();
60 | Digest digest = getDigest();
61 |
62 | ByteArrayOutputStream bos = new ByteArrayOutputStream();
63 | try {
64 | response.writeTo(bos);
65 | } catch (SOAPException | IOException e) {
66 | throw new OxalisAs4TransmissionException("Could not write response", e);
67 | }
68 |
69 | return new As4TransmissionResponse(
70 | ti,
71 | request,
72 | digest,
73 | bos.toByteArray(),
74 | ts,
75 | ts.getDate()
76 | );
77 | }
78 |
79 | private Digest getDigest() throws OxalisAs4TransmissionException {
80 | try {
81 | MessageDigest md = BCHelper.getMessageDigest(DIGEST_ALGORITHM_SHA256);
82 | return Digest.of(DigestMethod.SHA256, md.digest());
83 | } catch (NoSuchAlgorithmException e) {
84 | throw new OxalisAs4TransmissionException("Could not create message digest", e);
85 | }
86 | }
87 |
88 | private Timestamp getTimestamp() throws OxalisAs4TransmissionException {
89 | try {
90 | return timestampProvider.generate(null, Direction.OUT);
91 | } catch (TimestampException e) {
92 | throw new OxalisAs4TransmissionException("Could not create timestamp", e);
93 | }
94 | }
95 |
96 | private SignalMessage getSignalMessage(SOAPMessage soapMessage) throws OxalisAs4TransmissionException {
97 | Node signalNode = getSignalNode(soapMessage);
98 |
99 | try {
100 | Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
101 | return unmarshaller.unmarshal(signalNode, SignalMessage.class).getValue();
102 | } catch (JAXBException e) {
103 | throw new OxalisAs4TransmissionException("Could not create unmarshaller", e);
104 | }
105 | }
106 |
107 | private Node getSignalNode(SOAPMessage soapMessage) throws OxalisAs4TransmissionException {
108 | try {
109 | NodeList signalNodeList = soapMessage.getSOAPHeader().getElementsByTagNameNS("*", "SignalMessage");
110 | if (signalNodeList.getLength() != 1) {
111 | throw new OxalisAs4TransmissionException("SOAP header contains zero or multiple SignalMessage elements, should only contain one");
112 | }
113 | return signalNodeList.item(0);
114 | } catch (SOAPException e) {
115 | throw new OxalisAs4TransmissionException("Could not access response body", e);
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/util/AS4ErrorCode.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.util;
2 |
3 | import static network.oxalis.as4.util.AS4ErrorCode.Category.*;
4 | import static network.oxalis.as4.util.AS4ErrorCode.Origin.EBMS;
5 | import static network.oxalis.as4.util.AS4ErrorCode.Origin.SECURITY;
6 |
7 | public enum AS4ErrorCode {
8 |
9 | EBMS_0001("EBMS:0001", "ValueNotRecognized", CONTENT, EBMS),
10 | EBMS_0002("EBMS:0002", "FeatureNotSupported", CONTENT, EBMS),
11 | EBMS_0003("EBMS:0003", "ValueInconsistent", CONTENT, EBMS),
12 | EBMS_0004("EBMS:0004", "Other", CONTENT, EBMS),
13 | EBMS_0005("EBMS:0005", "ConnectionFailure", COMMUNICATION, EBMS),
14 | EBMS_0006("EBMS:0006", "EmptyMessagePartitionFlow", COMMUNICATION, EBMS),
15 | EBMS_0007("EBMS:0007", "MimeInconsistency", UNPACKAGING, EBMS),
16 | EBMS_0008("EBMS:0008", "FeatureNotSupported", UNPACKAGING, EBMS),
17 | EBMS_0009("EBMS:0009", "InvalidHeader", UNPACKAGING, EBMS),
18 | EBMS_0010("EBMS:0010", "ProcessingModeMismatch", PROCESSING, EBMS),
19 |
20 | EBMS_0101("EBMS:0101", "FailedAuthentication", PROCESSING, SECURITY),
21 | EBMS_0102("EBMS:0102", "FailedDecryption", PROCESSING, SECURITY),
22 | EBMS_0103("EBMS:0103", "PolicyNoncompliance", PROCESSING, SECURITY),
23 | EBMS_0201("EBMS:0201", "DysfunctionalReliability", PROCESSING, SECURITY),
24 | EBMS_0202("EBMS:0202", "DeliveryFailure", COMMUNICATION, SECURITY),
25 |
26 | EBMS_0301("EBMS:0301", "MissingReceipt", COMMUNICATION, EBMS),
27 | EBMS_0303("EBMS:0303", "DecompressionFailure", COMMUNICATION, EBMS);
28 |
29 | private String errorCode;
30 | private String shortDescription;
31 | private Category catgory;
32 | private Origin origin;
33 |
34 | AS4ErrorCode(String errorCode, String shortDescription, Category category, Origin origin){
35 | this.errorCode = errorCode;
36 | this.shortDescription = shortDescription;
37 | this.catgory = category;
38 | this.origin = origin;
39 | }
40 |
41 | public String getErrorCode() {
42 | return errorCode;
43 | }
44 |
45 | public String getShortDescription() {
46 | return shortDescription;
47 | }
48 |
49 | public Category getCatgory() {
50 | return catgory;
51 | }
52 |
53 | public Origin getOrigin() {
54 | return origin;
55 | }
56 |
57 | public static AS4ErrorCode nameOf(String name){
58 | for(AS4ErrorCode errorCode : AS4ErrorCode.values()){
59 | if (errorCode.toString().equalsIgnoreCase(name)){
60 | return errorCode;
61 | }
62 | }
63 |
64 | return null;
65 | }
66 |
67 |
68 | @Override
69 | public String toString() {
70 | return getErrorCode();
71 | }
72 |
73 | public enum Category{
74 | CONTENT,
75 | COMMUNICATION,
76 | UNPACKAGING,
77 | PROCESSING;
78 |
79 | @Override
80 | public String toString() {
81 | return name().substring(0,1).toUpperCase() + name().substring(1).toLowerCase();
82 | }
83 | }
84 |
85 | public enum Origin{
86 | EBMS,
87 | SECURITY,
88 | RELIABILITY;
89 |
90 | @Override
91 | public String toString() {
92 | return name().toLowerCase();
93 | }
94 | }
95 |
96 | public enum Severity{
97 | ERROR,
98 | FAILURE,
99 | WARNING;
100 |
101 | @Override
102 | public String toString() {
103 | return name().toLowerCase();
104 | }
105 |
106 | public static Severity nameOf(String name){
107 | for(Severity severity : Severity.values()){
108 | if (severity.toString().equalsIgnoreCase(name)){
109 | return severity;
110 | }
111 | }
112 |
113 | return null;
114 | }
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/util/As4MessageFactory.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.util;
2 |
3 | import com.google.inject.Inject;
4 | import com.google.inject.Singleton;
5 | import network.oxalis.as4.api.MessageIdGenerator;
6 | import network.oxalis.as4.lang.AS4Error;
7 | import network.oxalis.as4.lang.OxalisAs4Exception;
8 | import network.oxalis.as4.inbound.ProsessingContext;
9 | import org.apache.cxf.interceptor.Fault;
10 | import org.oasis_open.docs.ebxml_bp.ebbp_signals_2.MessagePartNRInformation;
11 | import org.oasis_open.docs.ebxml_bp.ebbp_signals_2.NonRepudiationInformation;
12 | import org.oasis_open.docs.ebxml_msg.ebms.v3_0.ns.core._200704.Error;
13 | import org.oasis_open.docs.ebxml_msg.ebms.v3_0.ns.core._200704.*;
14 |
15 | import jakarta.xml.bind.JAXBContext;
16 | import jakarta.xml.bind.JAXBElement;
17 | import javax.xml.datatype.XMLGregorianCalendar;
18 | import jakarta.xml.soap.*;
19 | import java.util.Date;
20 | import java.util.List;
21 | import java.util.stream.Collectors;
22 |
23 | @Singleton
24 | public class As4MessageFactory {
25 |
26 | private final MessageIdGenerator messageIdGenerator;
27 | private final MessageFactory messageFactory;
28 | private final JAXBContext jaxbContext;
29 |
30 | @Inject
31 | public As4MessageFactory(MessageIdGenerator messageIdGenerator) throws SOAPException {
32 | this(
33 | messageIdGenerator,
34 | MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL),
35 | Marshalling.getInstance()
36 | );
37 | }
38 |
39 | public As4MessageFactory(MessageIdGenerator messageIdGenerator, MessageFactory messageFactory, JAXBContext jaxbContext) {
40 | this.messageFactory = messageFactory;
41 | this.jaxbContext = jaxbContext;
42 | this.messageIdGenerator = messageIdGenerator;
43 | }
44 |
45 | public SOAPMessage createReceiptMessage(UserMessage inUserMessage, ProsessingContext prosessingContext) throws OxalisAs4Exception {
46 |
47 | XMLGregorianCalendar xmlGc = XMLUtil.dateToXMLGeorgianCalendar(
48 | prosessingContext.getReceiptTimestamp().getDate()
49 | );
50 |
51 | MessageInfo messageInfo = new MessageInfo();
52 | messageInfo.setTimestamp(xmlGc);
53 | messageInfo.setMessageId(messageIdGenerator.generate());
54 | messageInfo.setRefToMessageId(inUserMessage.getMessageInfo().getMessageId());
55 |
56 | List mpList = prosessingContext.getReferenceList().stream()
57 | .map(reference -> {
58 | MessagePartNRInformation messagePartNRInformation = new MessagePartNRInformation();
59 | messagePartNRInformation.setReference(reference);
60 | return messagePartNRInformation;
61 | })
62 | .collect(Collectors.toList());
63 |
64 | NonRepudiationInformation nri = new NonRepudiationInformation();
65 | nri.getMessagePartNRInformation().addAll(mpList);
66 |
67 | Receipt receipt = new Receipt();
68 | receipt.getAny().add(nri);
69 |
70 | SignalMessage signalMessage = new SignalMessage();
71 | signalMessage.setMessageInfo(messageInfo);
72 | signalMessage.setReceipt(receipt);
73 |
74 | return marshalSignalMessage(signalMessage);
75 | }
76 |
77 |
78 | public SOAPMessage createErrorMessage(String messageId, AS4Error as4Error) {
79 | try {
80 |
81 | XMLGregorianCalendar currentDate = XMLUtil.dateToXMLGeorgianCalendar(new Date());
82 |
83 |
84 | MessageInfo messageInfo = new MessageInfo();
85 | messageInfo.setRefToMessageId(messageId);
86 | messageInfo.setTimestamp(currentDate);
87 | messageInfo.setMessageId(messageIdGenerator.generate());
88 |
89 | Error error = new Error();
90 | error.setRefToMessageInError(messageId);
91 | error.setErrorCode(as4Error.getErrorCode().toString());
92 | error.setErrorDetail(getErrorDetail(as4Error));
93 | error.setShortDescription(as4Error.getErrorCode().getShortDescription());
94 | error.setOrigin(as4Error.getErrorCode().getOrigin().toString());
95 | error.setCategory(as4Error.getErrorCode().getCatgory().toString());
96 | error.setSeverity(as4Error.getSeverity().toString());
97 |
98 | SignalMessage signalMessage = new SignalMessage();
99 | signalMessage.setMessageInfo(messageInfo);
100 | signalMessage.getError().add(error);
101 |
102 | return marshalSignalMessage(signalMessage);
103 |
104 | } catch (OxalisAs4Exception e) {
105 | throw new Fault(e.getCause());
106 | }
107 | }
108 |
109 | private String getErrorDetail(AS4Error as4Error) {
110 | StringBuilder sb = new StringBuilder();
111 |
112 | sb.append(as4Error.getMessage());
113 |
114 | Throwable throwable = as4Error.getException();
115 |
116 | while (throwable.getCause() != null) {
117 | throwable = throwable.getCause();
118 | sb.append("\ncause: ").append(throwable.getMessage());
119 | }
120 |
121 | return sb.toString();
122 | }
123 |
124 | public SOAPMessage marshalSignalMessage(SignalMessage signalMessage) throws OxalisAs4Exception {
125 | try {
126 | SOAPMessage message = messageFactory.createMessage();
127 | SOAPHeader soapHeader = message.getSOAPHeader();
128 |
129 | SOAPHeaderElement messagingHeader = soapHeader.addHeaderElement(Constants.MESSAGING_QNAME);
130 | messagingHeader.setMustUnderstand(true);
131 |
132 | JAXBElement userMessageJAXBElement = new JAXBElement<>(
133 | Constants.SIGNAL_MESSAGE_QNAME,
134 | SignalMessage.class,
135 | signalMessage
136 | );
137 |
138 | jaxbContext.createMarshaller().marshal(userMessageJAXBElement, messagingHeader);
139 |
140 | return message;
141 | } catch (Exception e) {
142 | throw new OxalisAs4Exception("Unable to marshal SignalMessage", e, AS4ErrorCode.EBMS_0004);
143 | }
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/util/CompressionUtil.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.util;
2 |
3 | import org.apache.cxf.helpers.IOUtils;
4 | import org.apache.cxf.io.CacheSizeExceededException;
5 | import org.apache.cxf.io.CachedOutputStream;
6 |
7 | import java.io.IOException;
8 | import java.io.InputStream;
9 | import java.util.zip.GZIPOutputStream;
10 |
11 | public class CompressionUtil {
12 |
13 | /**
14 | * Gets Compressed Stream for given input Stream
15 | *
16 | * @param sourceStream : Input Stream to be compressed to
17 | * @return Compressed Stream
18 | * @throws IOException when some thing bad happens
19 | */
20 | public InputStream getCompressedStream(final InputStream sourceStream) throws IOException {
21 |
22 | if (sourceStream == null) {
23 | throw new IllegalArgumentException("Source Stream cannot be NULL");
24 | }
25 |
26 | CachedOutputStream cache = new CachedOutputStream();
27 |
28 | try (GZIPOutputStream gzipOutputStream = new GZIPOutputStream(cache)) {
29 | IOUtils.copyAndCloseInput(sourceStream, gzipOutputStream);
30 | gzipOutputStream.flush();
31 | gzipOutputStream.finish();
32 | return cache.getInputStream();
33 | } catch (CacheSizeExceededException | IOException cee) {
34 | sourceStream.close();
35 | throw cee;
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/util/Constants.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.util;
2 |
3 | import lombok.experimental.UtilityClass;
4 |
5 | import javax.xml.namespace.QName;
6 |
7 | @UtilityClass
8 | public class Constants {
9 |
10 | public static final String EBMS_NAMESPACE = "http://docs.oasis-open.org/ebxml-msg/ebms/v3.0/ns/core/200704/";
11 |
12 | public static final QName MESSAGING_QNAME = new QName(EBMS_NAMESPACE, "Messaging", "eb");
13 | public static final QName USER_MESSAGE_QNAME = new QName(EBMS_NAMESPACE, "UserMessage");
14 | public static final QName SIGNAL_MESSAGE_QNAME = new QName(EBMS_NAMESPACE, "SignalMessage");
15 |
16 | public static final String DIGEST_ALGORITHM_SHA256 = "sha256";
17 |
18 | public static final String TEST_SERVICE = "http://docs.oasis-open.org/ebxml-msg/ebms/v3.0/ns/core/200704/service";
19 | public static final String TEST_ACTION = "http://docs.oasis-open.org/ebxml-msg/ebms/v3.0/ns/core/200704/test";
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/util/GeneralUtils.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.util;
2 |
3 | import lombok.experimental.UtilityClass;
4 |
5 | import java.util.Iterator;
6 | import java.util.Spliterators;
7 | import java.util.stream.Stream;
8 | import java.util.stream.StreamSupport;
9 |
10 | @UtilityClass
11 | public class GeneralUtils {
12 |
13 | public static Stream iteratorToStreamOfUnknownSize(Iterator iterator, int characteristics, boolean parallel) {
14 | return StreamSupport.stream(
15 | Spliterators.spliteratorUnknownSize(iterator, characteristics),
16 | parallel);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/util/InputStreamDataSource.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.util;
2 |
3 | import jakarta.activation.DataSource;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 | import java.io.OutputStream;
7 |
8 | public class InputStreamDataSource implements DataSource {
9 |
10 | private final InputStream inputStream;
11 |
12 | private final String contentType;
13 |
14 | public InputStreamDataSource(InputStream inputStream, String contentType) {
15 | this.inputStream = inputStream;
16 | this.contentType = contentType;
17 | }
18 |
19 | @Override
20 | public InputStream getInputStream () throws IOException {
21 | return inputStream;
22 | }
23 |
24 | @Override
25 | public OutputStream getOutputStream () {
26 | throw new UnsupportedOperationException("Read-only");
27 | }
28 |
29 | @Override
30 | public String getContentType () {
31 | return contentType;
32 | }
33 |
34 | @Override
35 | public String getName () {
36 | throw new UnsupportedOperationException("DataSource name not available");
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/util/Marshalling.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.util;
2 |
3 | import lombok.experimental.UtilityClass;
4 | import network.oxalis.peppol.sbdh.jaxb.StandardBusinessDocument;
5 | import org.oasis_open.docs.ebxml_bp.ebbp_signals_2.NonRepudiationInformation;
6 | import org.oasis_open.docs.ebxml_msg.ebms.v3_0.ns.core._200704.Messaging;
7 | import org.w3.xmldsig.ReferenceType;
8 | import org.xmlsoap.schemas.soap.envelope.Envelope;
9 |
10 | import jakarta.xml.bind.JAXBContext;
11 | import jakarta.xml.bind.JAXBException;
12 |
13 | @UtilityClass
14 | public class Marshalling {
15 |
16 | public static JAXBContext getInstance() {
17 | return InitializedMarshaller.instance;
18 | }
19 |
20 | public static JAXBContext createMarshaller() {
21 | try {
22 | return JAXBContext.newInstance(
23 | StandardBusinessDocument.class,
24 | Envelope.class,
25 | org.w3.soap.Envelope.class,
26 | ReferenceType.class,
27 | NonRepudiationInformation.class,
28 | Messaging.class
29 | );
30 | } catch (JAXBException e) {
31 | throw new RuntimeException("Unable to create marshaller for AS4 documents", e);
32 | }
33 | }
34 |
35 | private static class InitializedMarshaller {
36 | private static final JAXBContext instance = createMarshaller();
37 | }
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/util/MessageId.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.util;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Getter;
5 |
6 | @Getter
7 | @AllArgsConstructor
8 | public class MessageId {
9 | public static final String MESSAGE_ID = "oxalis.as4.messageId";
10 |
11 | private String value;
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/util/MessageIdUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010-2017 Norwegian Agency for Public Management and eGovernment (Difi)
3 | *
4 | * Licensed under the EUPL, Version 1.1 or – as soon they
5 | * will be approved by the European Commission - subsequent
6 | * versions of the EUPL (the "Licence");
7 | *
8 | * You may not use this work except in compliance with the Licence.
9 | *
10 | * You may obtain a copy of the Licence at:
11 | *
12 | * https://joinup.ec.europa.eu/community/eupl/og_page/eupl
13 | *
14 | * Unless required by applicable law or agreed to in
15 | * writing, software distributed under the Licence is
16 | * distributed on an "AS IS" basis,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
18 | * express or implied.
19 | * See the Licence for the specific language governing
20 | * permissions and limitations under the Licence.
21 | */
22 |
23 | package network.oxalis.as4.util;
24 |
25 | import lombok.experimental.UtilityClass;
26 |
27 | import java.util.regex.Pattern;
28 |
29 | @UtilityClass
30 | public class MessageIdUtil {
31 |
32 | private static final String ATEXT = "[A-Za-z0-9!#\\$%&'\\*\\+\\-/=\\?\\^_`\\{}\\|~]+";
33 |
34 | private static final Pattern PATTERN =
35 | Pattern.compile("^" + ATEXT + "(\\." + ATEXT + ")*@" + ATEXT + "(\\." + ATEXT + ")*$");
36 |
37 | public static boolean verify(String identifier) {
38 | return PATTERN.matcher(identifier).matches();
39 | }
40 |
41 | public static String wrap(String cid) {
42 | if (cid == null) {
43 | return null;
44 | }
45 |
46 | if (cid.startsWith("<") && cid.endsWith(">")) {
47 | return cid;
48 | }
49 |
50 | return String.format("<%s>", cid);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/util/PeppolConfiguration.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.util;
2 |
3 | import lombok.Getter;
4 | import network.oxalis.api.tag.Tag;
5 |
6 | import java.util.Arrays;
7 | import java.util.List;
8 |
9 | import static org.apache.wss4j.dom.handler.WSHandlerConstants.ENCRYPT;
10 | import static org.apache.wss4j.dom.handler.WSHandlerConstants.SIGNATURE;
11 |
12 | @Getter
13 | public class PeppolConfiguration implements Tag {
14 | public static final String IDENTIFIER = "AS4.OUTBOUND.PEPPOL";
15 |
16 | private List actions = Arrays.asList(SIGNATURE, ENCRYPT);
17 |
18 | private String partyIDType = "urn:fdc:peppol.eu:2017:identifiers:ap";
19 | private String agreementRef = "urn:fdc:peppol.eu:2017:agreements:tia:ap_provider";
20 |
21 | private String fromRole = "http://docs.oasis-open.org/ebxml-msg/ebms/v3.0/ns/core/200704/initiator";
22 | private String toRole = "http://docs.oasis-open.org/ebxml-msg/ebms/v3.0/ns/core/200704/responder";
23 |
24 |
25 | @Override
26 | public String getIdentifier() {
27 | return IDENTIFIER;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/util/PolicyService.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.util;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import network.oxalis.as4.lang.OxalisAs4TransmissionException;
5 | import network.oxalis.api.outbound.TransmissionRequest;
6 | import network.oxalis.as4.outbound.ActionProvider;
7 | import network.oxalis.vefa.peppol.common.model.ProcessIdentifier;
8 | import org.apache.cxf.Bus;
9 | import org.apache.cxf.BusFactory;
10 | import org.apache.cxf.ws.policy.PolicyBuilder;
11 | import org.apache.neethi.Policy;
12 | import org.oasis_open.docs.ebxml_msg.ebms.v3_0.ns.core._200704.CollaborationInfo;
13 | import org.xml.sax.SAXException;
14 |
15 | import javax.xml.parsers.ParserConfigurationException;
16 | import java.io.IOException;
17 | import java.io.InputStream;
18 |
19 | @Slf4j
20 | public class PolicyService {
21 |
22 | private final ActionProvider actionProvider;
23 |
24 | public PolicyService(ActionProvider actionProvider) {
25 | this.actionProvider = actionProvider;
26 | }
27 |
28 | public Policy getPolicy() throws OxalisAs4TransmissionException {
29 | Bus bus = BusFactory.getThreadDefaultBus();
30 | return getPolicy(bus);
31 | }
32 |
33 | public Policy getPolicy(Bus bus) throws OxalisAs4TransmissionException {
34 | return getPolicy(getDefaultPolicy(), bus);
35 | }
36 |
37 | public Policy getPolicy(TransmissionRequest request) throws OxalisAs4TransmissionException {
38 | Bus bus = BusFactory.getThreadDefaultBus();
39 | return getPolicy(request, bus);
40 | }
41 |
42 | public Policy getPolicy(TransmissionRequest request, Bus bus) throws OxalisAs4TransmissionException {
43 | String action = actionProvider.getAction(request.getHeader().getDocumentType());
44 | ProcessIdentifier process = request.getHeader().getProcess();
45 | String service = process.getIdentifier();
46 | return getPolicy(getPolicyClasspath(action, service), bus);
47 | }
48 |
49 | public Policy getPolicy(CollaborationInfo collaborationInfo) throws OxalisAs4TransmissionException {
50 | Bus bus = BusFactory.getThreadDefaultBus();
51 | return getPolicy(collaborationInfo, bus);
52 | }
53 |
54 | public Policy getPolicy(CollaborationInfo collaborationInfo, Bus bus) throws OxalisAs4TransmissionException {
55 | return getPolicy(getPolicyClasspath(collaborationInfo.getAction(), collaborationInfo.getService().getValue()), bus);
56 | }
57 |
58 | private Policy getPolicy(String policyClasspath, Bus bus) throws OxalisAs4TransmissionException {
59 | try {
60 | log.debug("Policy classpath: {}", policyClasspath);
61 | InputStream policyStream = getClass().getResourceAsStream(policyClasspath);
62 | PolicyBuilder builder = bus.getExtension(PolicyBuilder.class);
63 | return builder.getPolicy(policyStream);
64 | } catch (SAXException | ParserConfigurationException | IOException e) {
65 | throw new OxalisAs4TransmissionException("Failed to get WS Policy", e);
66 | }
67 | }
68 |
69 | protected String getPolicyClasspath(String action, String service) {
70 | return getDefaultPolicy();
71 | }
72 |
73 | protected String getDefaultPolicy() {
74 | return "/eDeliveryAS4Policy_BST.xml";
75 | }
76 | }
77 |
78 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/util/TransmissionRequestUtil.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.util;
2 |
3 | import lombok.experimental.UtilityClass;
4 | import network.oxalis.as4.common.As4MessageProperty;
5 | import network.oxalis.vefa.peppol.common.model.DocumentTypeIdentifier;
6 | import network.oxalis.vefa.peppol.common.model.ParticipantIdentifier;
7 |
8 | @UtilityClass
9 | public class TransmissionRequestUtil {
10 |
11 | public static String translateDocumentTypeToAction(DocumentTypeIdentifier documentTypeIdentifier) {
12 | return documentTypeIdentifier.getScheme() == null ||
13 | documentTypeIdentifier.getScheme().getIdentifier() == null ||
14 | documentTypeIdentifier.getScheme().getIdentifier().trim().isEmpty() ?
15 |
16 | documentTypeIdentifier.getIdentifier() :
17 | documentTypeIdentifier.toString();
18 | }
19 |
20 | public static As4MessageProperty toAs4MessageProperty(String name, ParticipantIdentifier documentTypeIdentifier) {
21 | return documentTypeIdentifier.getScheme() == null ||
22 | documentTypeIdentifier.getScheme().getIdentifier() == null ||
23 | documentTypeIdentifier.getScheme().getIdentifier().trim().isEmpty()
24 | ? new As4MessageProperty(name, documentTypeIdentifier.getIdentifier())
25 | : new As4MessageProperty(name, documentTypeIdentifier.getScheme().getIdentifier(), documentTypeIdentifier.getIdentifier());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/network/oxalis/as4/util/XMLUtil.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.util;
2 |
3 | import lombok.experimental.UtilityClass;
4 | import network.oxalis.as4.lang.OxalisAs4Exception;
5 |
6 | import javax.xml.datatype.DatatypeConfigurationException;
7 | import javax.xml.datatype.DatatypeFactory;
8 | import javax.xml.datatype.XMLGregorianCalendar;
9 | import java.util.Date;
10 | import java.util.GregorianCalendar;
11 |
12 | @UtilityClass
13 | public class XMLUtil {
14 |
15 | public static XMLGregorianCalendar dateToXMLGeorgianCalendar(Date date) throws OxalisAs4Exception {
16 | try {
17 | GregorianCalendar gc = new GregorianCalendar();
18 | gc.setTime(date);
19 |
20 | return DatatypeFactory.newInstance().newXMLGregorianCalendar(gc);
21 | } catch (DatatypeConfigurationException e) {
22 | throw new OxalisAs4Exception("Unable to convert timestamp to XML", e);
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/org/apache/cxf/attachment/As4AttachmentDataSource.java:
--------------------------------------------------------------------------------
1 | package org.apache.cxf.attachment;
2 |
3 | import lombok.Getter;
4 | import lombok.SneakyThrows;
5 |
6 | import java.io.IOException;
7 | import java.io.InputStream;
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | @Getter
12 | public class As4AttachmentDataSource extends AttachmentDataSource {
13 |
14 | List inputStreams = new ArrayList<>();
15 |
16 | public As4AttachmentDataSource(String ctParam, InputStream inParam) throws IOException {
17 | super(ctParam, inParam);
18 | }
19 |
20 | @Override
21 | public InputStream getInputStream() {
22 | InputStream inputStream = super.getInputStream();
23 | inputStreams.add(inputStream);
24 | return inputStream;
25 | }
26 |
27 | public void closeAll() {
28 | inputStreams.forEach(this::close);
29 | }
30 |
31 | @SneakyThrows
32 | private void close(InputStream inputStream) {
33 | inputStream.close();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/org/apache/cxf/attachment/As4AttachmentImpl.java:
--------------------------------------------------------------------------------
1 | package org.apache.cxf.attachment;
2 |
3 | import org.apache.cxf.attachment.AttachmentImpl;
4 |
5 | public class As4AttachmentImpl extends AttachmentImpl {
6 | public As4AttachmentImpl(String idParam) {
7 | super(idParam);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/org/apache/cxf/attachment/As4AttachmentInInterceptor.java:
--------------------------------------------------------------------------------
1 | package org.apache.cxf.attachment;
2 |
3 | import org.apache.cxf.common.logging.LogUtils;
4 | import org.apache.cxf.interceptor.AttachmentInInterceptor;
5 | import org.apache.cxf.interceptor.Fault;
6 | import org.apache.cxf.message.Message;
7 | import org.apache.cxf.phase.AbstractPhaseInterceptor;
8 | import org.apache.cxf.phase.Phase;
9 |
10 | import java.io.IOException;
11 | import java.io.InputStream;
12 | import java.util.Collections;
13 | import java.util.List;
14 | import java.util.logging.Logger;
15 |
16 | public class As4AttachmentInInterceptor extends AbstractPhaseInterceptor {
17 |
18 | private static final Logger LOG = LogUtils.getL7dLogger(AttachmentInInterceptor.class);
19 |
20 | private static final List TYPES = Collections.singletonList("multipart/related");
21 |
22 | public As4AttachmentInInterceptor() {
23 | super(Phase.RECEIVE);
24 | }
25 |
26 | public void handleMessage(Message message) {
27 | if (isGET(message)) {
28 | LOG.fine("As4AttachmentInInterceptor skipped in HTTP GET method");
29 | return;
30 | }
31 | if (message.getContent(InputStream.class) == null) {
32 | return;
33 | }
34 |
35 | String contentType = (String) message.get(Message.CONTENT_TYPE);
36 | if (AttachmentUtil.isTypeSupported(contentType, getSupportedTypes())) {
37 | As4AttachmentDeserializer ad = new As4AttachmentDeserializer(message, getSupportedTypes());
38 | try {
39 | ad.initializeAttachments();
40 | } catch (IOException e) {
41 | throw new Fault(e);
42 | }
43 |
44 | message.put(As4AttachmentDeserializer.class, ad);
45 | }
46 | }
47 |
48 | public void handleFault(Message messageParam) {
49 | }
50 |
51 | protected List getSupportedTypes() {
52 | return TYPES;
53 | }
54 | }
55 |
56 |
--------------------------------------------------------------------------------
/src/main/java/org/apache/cxf/attachment/As4AttachmentUtil.java:
--------------------------------------------------------------------------------
1 | package org.apache.cxf.attachment;
2 |
3 | import org.apache.cxf.common.util.StringUtils;
4 | import org.apache.cxf.helpers.FileUtils;
5 | import org.apache.cxf.message.Attachment;
6 |
7 | import jakarta.activation.DataHandler;
8 | import jakarta.activation.DataSource;
9 | import java.io.IOException;
10 | import java.io.InputStream;
11 | import java.util.List;
12 | import java.util.Map;
13 |
14 | public final class As4AttachmentUtil {
15 |
16 | private As4AttachmentUtil() {
17 |
18 | }
19 |
20 | static String getHeaderValue(List v) {
21 | if (v != null && !v.isEmpty()) {
22 | return v.get(0);
23 | }
24 | return null;
25 | }
26 |
27 | static String getHeaderValue(List v, String delim) {
28 | if (v != null && !v.isEmpty()) {
29 | return String.join(delim, v);
30 | }
31 | return null;
32 | }
33 |
34 | static String getHeader(Map> headers, String h) {
35 | return getHeaderValue(headers.get(h));
36 | }
37 |
38 | static String getHeader(Map> headers, String h, String delim) {
39 | return getHeaderValue(headers.get(h), delim);
40 | }
41 |
42 | public static Attachment createAttachment(InputStream stream, Map> headers)
43 | throws IOException {
44 |
45 | String id = AttachmentUtil.cleanContentId(getHeader(headers, "Content-ID"));
46 |
47 | As4AttachmentImpl att = new As4AttachmentImpl(id);
48 |
49 | final String ct = getHeader(headers, "Content-Type");
50 | String cd = getHeader(headers, "Content-Disposition");
51 | String fileName = getContentDispositionFileName(cd);
52 |
53 | String encoding = null;
54 |
55 | for (Map.Entry> e : headers.entrySet()) {
56 | String name = e.getKey();
57 | if ("Content-Transfer-Encoding".equalsIgnoreCase(name)) {
58 | encoding = getHeader(headers, name);
59 | if ("binary".equalsIgnoreCase(encoding)) {
60 | att.setXOP(true);
61 | }
62 | }
63 | att.setHeader(name, getHeaderValue(e.getValue()));
64 | }
65 | if (encoding == null) {
66 | encoding = "binary";
67 | }
68 | InputStream ins = AttachmentUtil.decode(stream, encoding);
69 | if (ins != stream) {
70 | headers.remove("Content-Transfer-Encoding");
71 | }
72 | DataSource source = new As4AttachmentDataSource(ct, ins);
73 | if (!StringUtils.isEmpty(fileName)) {
74 | ((As4AttachmentDataSource) source).setName(FileUtils.stripPath(fileName));
75 | }
76 | att.setDataHandler(new DataHandler(source));
77 | return att;
78 | }
79 |
80 | static String getContentDispositionFileName(String cd) {
81 | if (StringUtils.isEmpty(cd)) {
82 | return null;
83 | }
84 | ContentDisposition c = new ContentDisposition(cd);
85 | String s = c.getParameter("filename");
86 | if (s == null) {
87 | s = c.getParameter("name");
88 | }
89 | return s;
90 | }
91 | }
92 |
93 |
--------------------------------------------------------------------------------
/src/main/java/org/apache/cxf/attachment/As4DelegatingInputStream.java:
--------------------------------------------------------------------------------
1 | package org.apache.cxf.attachment;
2 |
3 | import org.apache.cxf.helpers.IOUtils;
4 | import org.apache.cxf.io.Transferable;
5 |
6 | import java.io.File;
7 | import java.io.IOException;
8 | import java.io.InputStream;
9 |
10 | public class As4DelegatingInputStream extends InputStream implements Transferable {
11 | private InputStream is;
12 | private As4AttachmentDeserializer deserializer;
13 | private boolean isClosed;
14 |
15 | As4DelegatingInputStream(InputStream is, As4AttachmentDeserializer ads) {
16 | this.is = is;
17 | deserializer = ads;
18 | }
19 |
20 | @Override
21 | public void close() throws IOException {
22 | IOUtils.consume(is);
23 | is.close();
24 | if (!isClosed && deserializer != null) {
25 | deserializer.markClosed(this);
26 | }
27 | isClosed = true;
28 | }
29 |
30 | public void transferTo(File destinationFile) throws IOException {
31 | if (isClosed) {
32 | throw new IOException("Stream is closed");
33 | }
34 | IOUtils.transferTo(is, destinationFile);
35 | }
36 |
37 | public boolean isClosed() {
38 | return isClosed;
39 | }
40 |
41 | public void setClosed(boolean closed) {
42 | this.isClosed = closed;
43 | }
44 |
45 | public int read() throws IOException {
46 | return this.is.read();
47 | }
48 |
49 | @Override
50 | public int available() throws IOException {
51 | return this.is.available();
52 | }
53 |
54 | @Override
55 | public synchronized void mark(int arg0) {
56 | this.is.mark(arg0);
57 | }
58 |
59 | @Override
60 | public boolean markSupported() {
61 | return this.is.markSupported();
62 | }
63 |
64 | @Override
65 | public int read(byte[] bytes, int arg1, int arg2) throws IOException {
66 | return this.is.read(bytes, arg1, arg2);
67 | }
68 |
69 | @Override
70 | public int read(byte[] bytes) throws IOException {
71 | return this.is.read(bytes);
72 | }
73 |
74 | @Override
75 | public synchronized void reset() throws IOException {
76 | this.is.reset();
77 | }
78 |
79 | @Override
80 | public long skip(long n) throws IOException {
81 | return this.is.skip(n);
82 | }
83 |
84 | public void setInputStream(InputStream inputStream) {
85 | this.is = inputStream;
86 | }
87 |
88 |
89 | public InputStream getInputStream() {
90 | return is;
91 | }
92 | }
--------------------------------------------------------------------------------
/src/main/resources/META-INF/javax.xml.ws.spi.Provider:
--------------------------------------------------------------------------------
1 | org.apache.cxf.jaxws.spi.ProviderImpl
--------------------------------------------------------------------------------
/src/main/resources/eDeliveryAS4Policy.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
40 |
41 |
42 |
43 |
44 |
45 |
48 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/src/main/resources/eDeliveryAS4Policy_BST.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
40 |
41 |
42 |
43 |
44 |
45 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/src/main/resources/oxalis-as4-version.properties:
--------------------------------------------------------------------------------
1 | oxalis.version=${project.version}
2 |
--------------------------------------------------------------------------------
/src/main/resources/reference.conf:
--------------------------------------------------------------------------------
1 | oxalis.module.as4.common = {
2 | class = network.oxalis.as4.common.As4CommonModule
3 | }
4 |
5 | oxalis.module.as4.inbound = {
6 | class = network.oxalis.as4.inbound.As4InboundModule
7 | dependency = inbound.servlet
8 | }
9 |
10 | oxalis.module.as4.outbound = {
11 | class = network.oxalis.as4.outbound.As4OutboundModule
12 | dependency = outbound.lookup
13 | }
14 |
15 | defaults.transport.as4_peppol_v2 = {
16 | profile: peppol-transport-as4-v2_0
17 | sender: oxalis-as4
18 | weight: 9001
19 | }
--------------------------------------------------------------------------------
/src/main/resources/signOnly.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/src/main/xsd/bindings.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/src/main/xsd/w3/datatypes.dtd:
--------------------------------------------------------------------------------
1 |
9 |
10 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
69 |
70 |
80 |
81 |
82 |
83 |
84 |
85 |
88 |
89 |
92 |
93 |
94 |
96 |
101 |
102 |
106 |
110 |
119 |
120 |
124 |
128 |
129 |
133 |
137 |
138 |
139 |
143 |
144 |
148 |
149 |
150 |
154 |
155 |
159 |
160 |
161 |
165 |
166 |
170 |
171 |
172 |
176 |
177 |
181 |
182 |
186 |
187 |
188 |
189 |
192 |
193 |
194 |
198 |
199 |
200 |
201 |
204 |
--------------------------------------------------------------------------------
/src/main/xsd/w3/soap-envelope.xsd:
--------------------------------------------------------------------------------
1 |
17 |
18 |
22 |
23 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | Elements replacing the wildcard MUST be namespace qualified, but can be in the targetNamespace
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
60 |
61 |
62 |
63 |
64 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | Fault reporting structure
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
106 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
126 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
--------------------------------------------------------------------------------
/src/main/xsd/xmlsoap/envelope.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
35 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | Prose in the spec does not specify that attributes are allowed on the Body element
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 | 'encodingStyle' indicates any canonicalization conventions followed in the contents of the containing element. For example, the value 'http://schemas.xmlsoap.org/soap/encoding/' indicates the pattern described in SOAP specification
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 | Fault reporting structure
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
--------------------------------------------------------------------------------
/src/test/java/network/oxalis/as4/common/DefaultMessageIdGeneratorTest.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.common;
2 |
3 | import org.junit.Assert;
4 | import org.junit.Before;
5 | import org.junit.Test;
6 | import org.junit.runner.RunWith;
7 |
8 | import org.powermock.core.classloader.annotations.PrepareForTest;
9 | import org.powermock.modules.junit4.PowerMockRunner;
10 |
11 | import java.util.UUID;
12 |
13 | import static org.powermock.api.mockito.PowerMockito.*;
14 |
15 | @RunWith(PowerMockRunner.class)
16 | @PrepareForTest(DefaultMessageIdGenerator.class)
17 | public class DefaultMessageIdGeneratorTest {
18 |
19 | private DefaultMessageIdGenerator generator;
20 |
21 | @Before
22 | public void setUp() {
23 | UUID fixedUUID = UUID.fromString("8196c8e2-820f-4aec-a1ca-288a4d1d4020");
24 |
25 | mockStatic(UUID.class);
26 | when(UUID.randomUUID()).thenReturn(fixedUUID);
27 |
28 | generator = new DefaultMessageIdGenerator("seller.eu");
29 | }
30 |
31 | @Test
32 | public void testGenerateByTransmissionRequest() {
33 | Assert.assertEquals("8196c8e2-820f-4aec-a1ca-288a4d1d4020@seller.eu", generator.generate());
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/test/java/network/oxalis/as4/inbound/AS4StatusServletTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010-2018 Norwegian Agency for Public Management and eGovernment (Difi)
3 | *
4 | * Licensed under the EUPL, Version 1.1 or – as soon they
5 | * will be approved by the European Commission - subsequent
6 | * versions of the EUPL (the "Licence");
7 | *
8 | * You may not use this work except in compliance with the Licence.
9 | *
10 | * You may obtain a copy of the Licence at:
11 | *
12 | * https://joinup.ec.europa.eu/community/eupl/og_page/eupl
13 | *
14 | * Unless required by applicable law or agreed to in
15 | * writing, software distributed under the Licence is
16 | * distributed on an "AS IS" basis,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
18 | * express or implied.
19 | * See the Licence for the specific language governing
20 | * permissions and limitations under the Licence.
21 | */
22 |
23 | package network.oxalis.as4.inbound;
24 |
25 | import com.google.inject.AbstractModule;
26 | import com.google.inject.Guice;
27 | import com.google.inject.Injector;
28 | import com.google.inject.util.Modules;
29 | import network.oxalis.api.inbound.InboundService;
30 | import network.oxalis.commons.guice.GuiceModuleLoader;
31 | import network.oxalis.test.jetty.AbstractJettyServerTest;
32 | import org.testng.Assert;
33 | import org.testng.annotations.Test;
34 |
35 | import jakarta.servlet.http.HttpServletResponse;
36 | import java.net.HttpURLConnection;
37 | import java.net.URL;
38 |
39 | @Test
40 | public class AS4StatusServletTest extends AbstractJettyServerTest {
41 |
42 | @Override
43 | public Injector getInjector() {
44 | return Guice.createInjector(
45 | new As4InboundModule(),
46 | Modules.override(new GuiceModuleLoader()).with(new AbstractModule() {
47 | @Override
48 | protected void configure() {
49 | // bind(ReceiptPersister.class).toInstance((m, p) -> {
50 | // });
51 | // bind(PayloadPersister.class).toInstance(temporaryFilePersister);
52 | bind(InboundService.class).toInstance(p -> {});
53 | // bind(MessageIdGenerator.class).toInstance(new DefaultMessageIdGenerator("test.com"));
54 | }
55 | })
56 | );
57 | }
58 |
59 | @Test
60 | public void get() throws Exception {
61 | HttpURLConnection httpURLConnection =
62 | (HttpURLConnection) new URL("http://localhost:8080/as4/status").openConnection();
63 |
64 | Assert.assertEquals(httpURLConnection.getResponseCode(), HttpServletResponse.SC_OK);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/test/java/network/oxalis/as4/inbound/As4InboundHandlerTest.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.inbound;
2 |
3 | import network.oxalis.as4.lang.OxalisAs4Exception;
4 | import org.oasis_open.docs.ebxml_msg.ebms.v3_0.ns.core._200704.PartInfo;
5 | import org.oasis_open.docs.ebxml_msg.ebms.v3_0.ns.core._200704.PartProperties;
6 | import org.oasis_open.docs.ebxml_msg.ebms.v3_0.ns.core._200704.PayloadInfo;
7 | import org.oasis_open.docs.ebxml_msg.ebms.v3_0.ns.core._200704.Property;
8 | import org.testng.annotations.Test;
9 |
10 | import static org.testng.Assert.*;
11 |
12 | public class As4InboundHandlerTest {
13 |
14 | @Test()
15 | public void testValidateMessageId_withValidHref() throws Exception{
16 |
17 | Property property = new Property();
18 | property.setName("MimeType");
19 | property.setValue("Dummy");
20 |
21 | PartProperties partProperties = new PartProperties();
22 | partProperties.getProperty().add(property);
23 |
24 | PartInfo partInfo = new PartInfo();
25 | partInfo.setHref("cid:attachedPayload");
26 | partInfo.setPartProperties(partProperties);
27 |
28 | PayloadInfo payloadInfo = new PayloadInfo();
29 | payloadInfo.getPartInfo().add(partInfo);
30 |
31 | As4InboundHandler.validatePayloads(payloadInfo);
32 | }
33 |
34 | @Test( expectedExceptions = {OxalisAs4Exception.class} )
35 | public void testValidateMessageId_withInvalidHref() throws Exception{
36 | PartInfo partInfo = new PartInfo();
37 | partInfo.setHref("http://difi.no");
38 |
39 | PayloadInfo payloadInfo = new PayloadInfo();
40 | payloadInfo.getPartInfo().add(partInfo);
41 |
42 | As4InboundHandler.validatePayloads(payloadInfo);
43 |
44 | fail();
45 | }
46 |
47 |
48 | }
--------------------------------------------------------------------------------
/src/test/java/network/oxalis/as4/inbound/As4ServletTest.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.inbound;
2 |
3 | import org.mockito.InjectMocks;
4 | import org.mockito.Mock;
5 | import org.mockito.MockitoAnnotations;
6 | import org.powermock.reflect.Whitebox;
7 | import org.testng.annotations.BeforeMethod;
8 | import org.testng.annotations.BeforeTest;
9 |
10 | import java.nio.file.Path;
11 | import java.security.KeyStore;
12 |
13 | public class As4ServletTest {
14 |
15 | @Mock
16 | private Path confFolder;
17 |
18 | private KeyStore trustStore = null;
19 |
20 | @InjectMocks
21 | private As4Servlet servlet = new As4Servlet();
22 |
23 |
24 | private KeyStore generateEmptyKeyStore() {
25 | try {
26 | KeyStore ks = KeyStore.getInstance("jks");
27 | ks.load(null, null);
28 |
29 | return ks;
30 | } catch (Exception e) {
31 | return null;
32 | }
33 | }
34 |
35 | @BeforeTest
36 | public void beforeTest() {
37 | MockitoAnnotations.initMocks(this);
38 | }
39 |
40 | @BeforeMethod
41 | public void beforeMethod() {
42 | trustStore = generateEmptyKeyStore();
43 | Whitebox.setInternalState(servlet, "trustStore", trustStore);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/test/java/network/oxalis/as4/outbound/MessagingProviderTest_CEF_SBDH.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.outbound;
2 |
3 | import network.oxalis.api.settings.Settings;
4 | import network.oxalis.as4.config.As4Conf;
5 | import network.oxalis.as4.util.PeppolConfiguration;
6 |
7 | import jakarta.inject.Named;
8 | import java.nio.file.Path;
9 |
10 | public class MessagingProviderTest_CEF_SBDH extends AbstractMessagingProviderTest {
11 |
12 | @Override
13 | protected String getPayloadPath() {
14 | return "/cef-sbd.xml";
15 | }
16 |
17 | @Override
18 | protected PeppolConfiguration getPEPPOLOutboundConfiguration() {
19 |
20 | return new As4OutboundModule().getPeppolOutboundConfiguration(new Settings(){
21 | @Override
22 | public String getString(As4Conf as4Conf) {
23 | return "cef-connectivity";
24 | }
25 |
26 | @Override
27 | public int getInt(As4Conf as4Conf) {
28 | return 0;
29 | }
30 |
31 | @Override
32 | public Named getNamed(As4Conf key) {
33 | return null;
34 | }
35 |
36 | @Override
37 | public Path getPath(As4Conf key, Path path) {
38 | return null;
39 | }
40 | });
41 | }
42 |
43 | @Override
44 | protected String getAction() {
45 | return "submitMessage";
46 | }
47 |
48 | @Override
49 | protected String getServiceType() {
50 | return "e-delivery";
51 | }
52 |
53 | @Override
54 | protected String getServiceValue() {
55 | return "http://ec.europa.eu/edelivery/services/connectivity-service";
56 | }
57 |
58 | @Override
59 | protected String getPartyType() {
60 | return "urn:oasis:names:tc:ebcore:partyid-type:unregistered";
61 | }
62 |
63 | @Override
64 | protected String getFinalRecipient() {
65 | return "urn:oasis:names:tc:ebcore:partyid-type:unregistered:c4";
66 | }
67 |
68 | @Override
69 | protected String getOriginalSender() {
70 | return "urn:oasis:names:tc:ebcore:partyid-type:unregistered:c1";
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/test/java/network/oxalis/as4/outbound/MessagingProviderTest_SIMPLE_SBDH.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.outbound;
2 |
3 | import network.oxalis.as4.util.PeppolConfiguration;
4 |
5 | public class MessagingProviderTest_SIMPLE_SBDH extends AbstractMessagingProviderTest {
6 |
7 | @Override
8 | protected String getPayloadPath() {
9 | return "/simple-sbd.xml";
10 | }
11 |
12 | @Override
13 | protected PeppolConfiguration getPEPPOLOutboundConfiguration() {
14 |
15 | return new PeppolConfiguration();
16 | }
17 |
18 | @Override
19 | protected String getAction() {
20 | 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";
21 | }
22 |
23 | @Override
24 | protected String getServiceType() {
25 | return "cenbii-procid-ubl";
26 | }
27 |
28 | @Override
29 | protected String getServiceValue() {
30 | return "urn:www.cenbii.eu:profile:bii04:ver2.0";
31 | }
32 |
33 | @Override
34 | protected String getPartyType() {
35 | return "urn:fdc:peppol.eu:2017:identifiers:ap";
36 | }
37 |
38 | @Override
39 | protected String getFinalRecipient() {
40 | return "iso6523-actorid-upis::9908:810418052";
41 | }
42 |
43 | @Override
44 | protected String getOriginalSender() {
45 | return "iso6523-actorid-upis::0088:oxalis";
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/test/java/network/oxalis/as4/util/AS4ErrorCodeTest.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.util;
2 |
3 | import org.testng.annotations.Test;
4 |
5 | import static org.testng.Assert.*;
6 |
7 | public class AS4ErrorCodeTest {
8 |
9 | @Test
10 | public void nameOf_validNames_Test(){
11 |
12 | assertEquals(AS4ErrorCode.nameOf("EBMS:0303"), AS4ErrorCode.EBMS_0303);
13 | assertEquals(AS4ErrorCode.nameOf("EBMS:0004"), AS4ErrorCode.EBMS_0004);
14 |
15 | assertEquals(AS4ErrorCode.nameOf("ebms:0303"), AS4ErrorCode.EBMS_0303);
16 | assertEquals(AS4ErrorCode.nameOf("ebms:0004"), AS4ErrorCode.EBMS_0004);
17 | }
18 |
19 | @Test
20 | public void nameOf_invalidNames_Test(){
21 |
22 | assertNull(AS4ErrorCode.nameOf("EBMS:9999"));
23 | assertNull(AS4ErrorCode.nameOf("ebms:9999"));
24 | }
25 |
26 | @Test
27 | public void toString_Test(){
28 |
29 | assertEquals(AS4ErrorCode.EBMS_0004.toString(), "EBMS:0004");
30 | assertEquals(AS4ErrorCode.EBMS_0303.toString(), "EBMS:0303");
31 | }
32 |
33 | @Test
34 | public void toString_and_getErrorCode_equality_Test(){
35 |
36 | assertEquals(AS4ErrorCode.EBMS_0004.toString(), AS4ErrorCode.EBMS_0004.getErrorCode());
37 | assertEquals(AS4ErrorCode.EBMS_0303.toString(), AS4ErrorCode.EBMS_0303.getErrorCode());
38 | }
39 |
40 | }
--------------------------------------------------------------------------------
/src/test/java/network/oxalis/as4/util/CompressionUtilTest.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.util;
2 |
3 | import org.apache.commons.io.IOUtils;
4 | import org.testng.Assert;
5 | import org.testng.annotations.Test;
6 |
7 | import java.io.ByteArrayInputStream;
8 | import java.io.InputStream;
9 | import java.util.Random;
10 | import java.util.zip.GZIPInputStream;
11 |
12 | public class CompressionUtilTest {
13 | @Test
14 | public void simple() throws Exception {
15 | byte[] before = "Lorem ipsum dolor sit amet".getBytes();
16 | InputStream sourceStream = new ByteArrayInputStream(before);
17 | InputStream compressedStream = new CompressionUtil().getCompressedStream(sourceStream);
18 | try (GZIPInputStream decompressedStream = new GZIPInputStream(compressedStream)) {
19 | byte[] after = IOUtils.toByteArray(decompressedStream);
20 | Assert.assertEquals(before, after);
21 | }
22 | }
23 |
24 | @Test
25 | public void cachedInTempFile() throws Exception {
26 | byte[] before = new byte[1024 * 1024];
27 | new Random().nextBytes(before);
28 | InputStream sourceStream = new ByteArrayInputStream(before);
29 | InputStream compressedStream = new CompressionUtil().getCompressedStream(sourceStream);
30 | try (GZIPInputStream decompressedStream = new GZIPInputStream(compressedStream)) {
31 | byte[] after = IOUtils.toByteArray(decompressedStream);
32 | Assert.assertEquals(before, after);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/test/java/network/oxalis/as4/util/MessageIdUtilTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010-2017 Norwegian Agency for Public Management and eGovernment (Difi)
3 | *
4 | * Licensed under the EUPL, Version 1.1 or – as soon they
5 | * will be approved by the European Commission - subsequent
6 | * versions of the EUPL (the "Licence");
7 | *
8 | * You may not use this work except in compliance with the Licence.
9 | *
10 | * You may obtain a copy of the Licence at:
11 | *
12 | * https://joinup.ec.europa.eu/community/eupl/og_page/eupl
13 | *
14 | * Unless required by applicable law or agreed to in
15 | * writing, software distributed under the Licence is
16 | * distributed on an "AS IS" basis,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
18 | * express or implied.
19 | * See the Licence for the specific language governing
20 | * permissions and limitations under the Licence.
21 | */
22 |
23 | package network.oxalis.as4.util;
24 |
25 | import org.testng.Assert;
26 | import org.testng.annotations.Test;
27 |
28 | public class MessageIdUtilTest {
29 |
30 | @Test
31 | public void testVerify() {
32 | Assert.assertTrue(MessageIdUtil.verify("1060501332.515.1528302064500@de77cf5d0088"));
33 | Assert.assertTrue(MessageIdUtil.verify("OpenPEPPOL-06062018160101+0300-0447@APP_1000000200_APP_2000000300"));
34 | Assert.assertTrue(MessageIdUtil.verify("a397-ca2a711dff5b@seller.eu"));
35 | Assert.assertTrue(MessageIdUtil.verify("8196c8e2-820f-4aec-a1ca-288a4d1d4020@seller.eu"));
36 |
37 | Assert.assertFalse(MessageIdUtil.verify("1060501332..515.1528302064500@de77cf5d0088"));
38 | Assert.assertFalse(MessageIdUtil.verify(" 1060501332.515.1528302064500@de77cf5d0088"));
39 | Assert.assertFalse(MessageIdUtil.verify("1060501332.515.1528302064500_de77cf5d0088"));
40 |
41 | Assert.assertTrue(MessageIdUtil.verify("Aa1!#$%&'*+-/=?^_`{|}~.Aa1!#$%&'*+-/=?^_`{|}~@Aa1!#$%&'*+-/=?^_`{|}~.Aa1!#$%&'*+-/=?^_`{|}~"));
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/test/java/network/oxalis/as4/util/TransmissionRequestUtilTest.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.as4.util;
2 |
3 | import network.oxalis.as4.common.As4MessageProperty;
4 | import network.oxalis.vefa.peppol.common.model.DocumentTypeIdentifier;
5 | import network.oxalis.vefa.peppol.common.model.ParticipantIdentifier;
6 | import network.oxalis.vefa.peppol.common.model.Scheme;
7 | import org.testng.Assert;
8 | import org.testng.annotations.Test;
9 |
10 | public class TransmissionRequestUtilTest {
11 |
12 | private static String PROVIDED_VALUE = "provided value";
13 | private static String PROVIDED_SCHEME = "provided scheme";
14 |
15 | @Test
16 | public void testTranslateDocumentTypeToAction_defaultScheme() {
17 | String result = TransmissionRequestUtil.translateDocumentTypeToAction(DocumentTypeIdentifier.of(PROVIDED_VALUE));
18 | Assert.assertEquals(DocumentTypeIdentifier.DEFAULT_SCHEME + "::" + PROVIDED_VALUE, result);
19 | }
20 |
21 | @Test
22 | public void testTranslateDocumentTypeToAction_nullScheme() {
23 | String result = TransmissionRequestUtil.translateDocumentTypeToAction(DocumentTypeIdentifier.of(PROVIDED_VALUE, null));
24 | Assert.assertEquals(PROVIDED_VALUE, result);
25 | }
26 |
27 | @Test
28 | public void testTranslateDocumentTypeToAction_providedScheme() {
29 | String result = TransmissionRequestUtil.translateDocumentTypeToAction(DocumentTypeIdentifier.of(PROVIDED_VALUE, Scheme.of(PROVIDED_SCHEME)));
30 | Assert.assertEquals(PROVIDED_SCHEME + "::" + PROVIDED_VALUE, result);
31 | }
32 |
33 |
34 | @Test
35 | public void testTranslateParticipantIdentifierToRecipient_defaultScheme() {
36 | As4MessageProperty result = TransmissionRequestUtil.toAs4MessageProperty("hello", ParticipantIdentifier.of(PROVIDED_VALUE));
37 |
38 | Assert.assertEquals("hello", result.getName());
39 | Assert.assertEquals("iso6523-actorid-upis", result.getType());
40 | Assert.assertEquals(PROVIDED_VALUE, result.getValue());
41 | }
42 |
43 | @Test
44 | public void testTranslateParticipantIdentifierToRecipient_nullScheme() {
45 | As4MessageProperty result = TransmissionRequestUtil.toAs4MessageProperty("hello", ParticipantIdentifier.of(PROVIDED_VALUE, null));
46 |
47 | Assert.assertEquals("hello", result.getName());
48 | Assert.assertNull(result.getType());
49 | Assert.assertEquals(PROVIDED_VALUE, result.getValue());
50 | }
51 |
52 | @Test
53 | public void testTranslateParticipantIdentifierToRecipient_providedScheme() {
54 | As4MessageProperty result = TransmissionRequestUtil.toAs4MessageProperty("hello", ParticipantIdentifier.of(PROVIDED_VALUE, Scheme.of(PROVIDED_SCHEME)));
55 |
56 | Assert.assertEquals("hello", result.getName());
57 | Assert.assertEquals(PROVIDED_SCHEME, result.getType());
58 | Assert.assertEquals(PROVIDED_VALUE, result.getValue());
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/test/java/network/oxalis/outbound/transmission/DefaultTransmissionRequestFacade.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.outbound.transmission;
2 |
3 | import network.oxalis.api.outbound.TransmissionMessage;
4 | import network.oxalis.api.outbound.TransmissionRequest;
5 | import network.oxalis.api.tag.Tag;
6 | import network.oxalis.vefa.peppol.common.model.Endpoint;
7 | import network.oxalis.vefa.peppol.common.model.Header;
8 |
9 | import java.io.InputStream;
10 | import java.io.Serializable;
11 |
12 | public class DefaultTransmissionRequestFacade implements TransmissionRequest, Serializable {
13 |
14 | private static final long serialVersionUID = -4542158937465140099L;
15 |
16 | private DefaultTransmissionRequest defaultTransmissionRequest;
17 |
18 | public DefaultTransmissionRequestFacade(TransmissionMessage transmissionMessage, Endpoint endpoint) {
19 | defaultTransmissionRequest = new DefaultTransmissionRequest(transmissionMessage, endpoint);
20 | }
21 |
22 | @Override
23 | public Endpoint getEndpoint() {
24 | return defaultTransmissionRequest.getEndpoint();
25 | }
26 |
27 | @Override
28 | public Header getHeader() {
29 | return defaultTransmissionRequest.getHeader();
30 | }
31 |
32 | @Override
33 | public InputStream getPayload() {
34 | return defaultTransmissionRequest.getPayload();
35 | }
36 |
37 | @Override
38 | public Tag getTag() {
39 | return defaultTransmissionRequest.getTag();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/test/java/network/oxalis/outbound/transmission/MessagingProviderFacade.java:
--------------------------------------------------------------------------------
1 | package network.oxalis.outbound.transmission;
2 |
3 | import network.oxalis.api.outbound.TransmissionRequest;
4 | import network.oxalis.as4.api.MessageIdGenerator;
5 | import network.oxalis.as4.lang.OxalisAs4TransmissionException;
6 | import network.oxalis.as4.outbound.DefaultActionProvider;
7 | import network.oxalis.as4.outbound.MessagingProvider;
8 | import network.oxalis.as4.util.PeppolConfiguration;
9 | import org.apache.cxf.message.Attachment;
10 | import org.oasis_open.docs.ebxml_msg.ebms.v3_0.ns.core._200704.Messaging;
11 |
12 | import java.security.cert.X509Certificate;
13 | import java.util.Collection;
14 |
15 | public class MessagingProviderFacade {
16 |
17 | private MessagingProvider messagingProvider;
18 |
19 | public MessagingProviderFacade(X509Certificate senderCert, MessageIdGenerator messageIdGenerator, PeppolConfiguration peppolConfiguration) {
20 | messagingProvider = new MessagingProvider(
21 | senderCert,
22 | messageIdGenerator,
23 | peppolConfiguration,
24 | new DefaultActionProvider());
25 | }
26 |
27 | public Messaging createMessagingHeader(TransmissionRequest request, Collection attachments) throws OxalisAs4TransmissionException {
28 | return messagingProvider.createMessagingHeader(request, attachments);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/test/resources/cef-sbd.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1.0
5 |
6 |
7 |
8 | urn:oasis:names:tc:ebcore:partyid-type:unregistered:C1
9 |
10 |
11 |
12 |
13 | urn:oasis:names:tc:ebcore:partyid-type:unregistered:C4
14 |
15 |
16 |
17 |
18 |
19 | NONE
20 | 1.0
21 | 555bcb4c-940b-4694-9b90-d9b0ae1e937b
22 | CEF Connectivity test
23 | 2019-10-30T11:20:05.304+02:00
24 |
25 |
26 |
27 |
28 |
29 |
30 | DOCUMENTID
31 |
32 |
33 |
34 | submitMessage
35 |
36 |
37 |
38 |
39 |
40 | PROCESSID
41 |
42 | e-delivery
43 |
44 | http://ec.europa.eu/edelivery/services/connectivity-service
45 |
46 |
47 |
48 | eDelivery AS4 Connectivity test. Sending Message
49 |
--------------------------------------------------------------------------------
/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
24 |
25 |
26 |
27 |
28 |
29 | %d %p [%c] %m %n
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/src/test/resources/oxalis_home/eutest_gateway_truststore.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OxalisCommunity/Oxalis-AS4/5aecaca2e2f3b92c56b59e645f58a0117908379f/src/test/resources/oxalis_home/eutest_gateway_truststore.jks
--------------------------------------------------------------------------------
/src/test/resources/oxalis_home/fake-oxalis.conf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OxalisCommunity/Oxalis-AS4/5aecaca2e2f3b92c56b59e645f58a0117908379f/src/test/resources/oxalis_home/fake-oxalis.conf
--------------------------------------------------------------------------------
/src/test/resources/oxalis_home/peppol_trust_g2_and_g3.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OxalisCommunity/Oxalis-AS4/5aecaca2e2f3b92c56b59e645f58a0117908379f/src/test/resources/oxalis_home/peppol_trust_g2_and_g3.jks
--------------------------------------------------------------------------------
/src/test/resources/reference.conf:
--------------------------------------------------------------------------------
1 | brave.reporter = noop
2 | oxalis.statistics.service = noop
3 | oxalis.persister.payload = noop
4 | oxalis.persister.receipt = noop
5 |
6 | oxalis.http.pool.max_route = 10
7 |
8 | oxalis.truststore.path=peppol_trust_g2_and_g3.jks
9 | oxalis.truststore.password=changeit
10 |
--------------------------------------------------------------------------------
/src/test/resources/simple-sbd.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1.0
5 |
6 | 0088:oxalis
7 |
8 |
9 | 9908:810418052
10 |
11 |
12 | urn:oasis:names:specification:ubl:schema:xsd:Invoice-2
13 | 2.1
14 | 555bcb4c-940b-4694-9b90-d9b0ae1e937b
15 | Invoice
16 | 2016-10-19T11:20:05.304+02:00
17 |
18 |
19 |
20 | DOCUMENTID
21 | 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
22 |
23 |
24 | PROCESSID
25 | urn:www.cenbii.eu:profile:bii04:ver2.0
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------