├── .trivyignore
├── .gitattributes
├── ballerina
├── icon.png
├── modules
│ ├── wssec
│ │ ├── tests
│ │ │ ├── resources
│ │ │ │ ├── wss40.p12
│ │ │ │ ├── keystore.jks
│ │ │ │ ├── keystore.p12
│ │ │ │ ├── keystoretest.jks
│ │ │ │ ├── mykeystore.jks
│ │ │ │ ├── private_key.pem
│ │ │ │ ├── invalid_keystore.jks
│ │ │ │ ├── x509_certificate.p12
│ │ │ │ ├── x509_certificate_2.p12
│ │ │ │ ├── x509_certificate_2.crt
│ │ │ │ ├── x509_certificate.crt
│ │ │ │ ├── xml
│ │ │ │ │ └── soap_envelope.xml
│ │ │ │ ├── certificate.pem
│ │ │ │ └── private_key1.pem
│ │ │ └── test_utils.bal
│ │ ├── error.bal
│ │ ├── init.bal
│ │ ├── sec_header.bal
│ │ ├── encryption.bal
│ │ ├── document.bal
│ │ ├── types.bal
│ │ ├── ws_security.bal
│ │ ├── signature.bal
│ │ ├── records.bal
│ │ └── ws_security_methods.bal
│ ├── soap12
│ │ ├── tests
│ │ │ ├── http_secured_service.bal
│ │ │ └── http_soap_service.bal
│ │ ├── error.bal
│ │ ├── soap12.bal
│ │ └── README.md
│ └── soap11
│ │ ├── tests
│ │ ├── http_secured_service.bal
│ │ └── http_soap_service.bal
│ │ ├── error.bal
│ │ ├── soap11.bal
│ │ └── README.md
├── constants.bal
├── error.bal
├── Ballerina.toml
├── configs.bal
├── types.bal
├── build.gradle
├── Dependencies.toml
├── README.md
└── soap_utils.bal
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── codecov.yml
├── .github
├── pull_request_template.md
├── CODEOWNERS
└── workflows
│ ├── trivy-scan.yml
│ ├── build-timestamped-master.yml
│ ├── pull-request.yml
│ ├── publish-release.yml
│ ├── central-publish.yml
│ ├── build-with-bal-test-graalvm.yml
│ └── update_specs.yml
├── .gitignore
├── changelog.md
├── issue_template.md
├── spotbugs-exclude.xml
├── native
├── src
│ └── main
│ │ ├── java
│ │ ├── module-info.java
│ │ ├── org
│ │ │ └── wssec
│ │ │ │ ├── ModuleUtils.java
│ │ │ │ ├── Utils.java
│ │ │ │ ├── WsSecurityHeader.java
│ │ │ │ ├── Signature.java
│ │ │ │ ├── DocumentBuilder.java
│ │ │ │ ├── Encryption.java
│ │ │ │ ├── Constants.java
│ │ │ │ └── WsSecurityUtils.java
│ │ └── io
│ │ │ └── ballerina
│ │ │ └── lib
│ │ │ └── soap
│ │ │ └── Soap.java
│ │ └── resources
│ │ └── META-INF
│ │ └── native-image
│ │ └── io.ballerina.stdlib
│ │ └── soap-native
│ │ └── resource-config.json
└── build.gradle
├── gradle.properties
├── settings.gradle
├── pull_request_template.md
├── gradlew.bat
├── gradlew
├── LICENSE
└── README.md
/.trivyignore:
--------------------------------------------------------------------------------
1 | # False positive
2 | CVE-2014-3623
3 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Ensure all Java files use LF.
2 | *.java eol=lf
3 |
--------------------------------------------------------------------------------
/ballerina/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ballerina-platform/module-ballerina-soap/HEAD/ballerina/icon.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ballerina-platform/module-ballerina-soap/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | coverage:
2 | precision: 2
3 | round: down
4 | range: "60...80"
5 | status:
6 | project:
7 | default:
8 | target: 80
--------------------------------------------------------------------------------
/ballerina/modules/wssec/tests/resources/wss40.p12:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ballerina-platform/module-ballerina-soap/HEAD/ballerina/modules/wssec/tests/resources/wss40.p12
--------------------------------------------------------------------------------
/ballerina/modules/wssec/tests/resources/keystore.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ballerina-platform/module-ballerina-soap/HEAD/ballerina/modules/wssec/tests/resources/keystore.jks
--------------------------------------------------------------------------------
/ballerina/modules/wssec/tests/resources/keystore.p12:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ballerina-platform/module-ballerina-soap/HEAD/ballerina/modules/wssec/tests/resources/keystore.p12
--------------------------------------------------------------------------------
/ballerina/modules/wssec/tests/resources/keystoretest.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ballerina-platform/module-ballerina-soap/HEAD/ballerina/modules/wssec/tests/resources/keystoretest.jks
--------------------------------------------------------------------------------
/ballerina/modules/wssec/tests/resources/mykeystore.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ballerina-platform/module-ballerina-soap/HEAD/ballerina/modules/wssec/tests/resources/mykeystore.jks
--------------------------------------------------------------------------------
/ballerina/modules/wssec/tests/resources/private_key.pem:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ballerina-platform/module-ballerina-soap/HEAD/ballerina/modules/wssec/tests/resources/private_key.pem
--------------------------------------------------------------------------------
/ballerina/modules/wssec/tests/resources/invalid_keystore.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ballerina-platform/module-ballerina-soap/HEAD/ballerina/modules/wssec/tests/resources/invalid_keystore.jks
--------------------------------------------------------------------------------
/ballerina/modules/wssec/tests/resources/x509_certificate.p12:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ballerina-platform/module-ballerina-soap/HEAD/ballerina/modules/wssec/tests/resources/x509_certificate.p12
--------------------------------------------------------------------------------
/ballerina/modules/wssec/tests/resources/x509_certificate_2.p12:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ballerina-platform/module-ballerina-soap/HEAD/ballerina/modules/wssec/tests/resources/x509_certificate_2.p12
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | ## Purpose
2 |
3 | ## Examples
4 |
5 | ## Checklist
6 | - [ ] Linked to an issue
7 | - [ ] Updated the changelog
8 | - [ ] Added tests
9 | - [ ] Updated the spec
10 | - [ ] Checked native-image compatibility
11 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # Lines starting with '#' are comments.
2 | # Each line is a file pattern followed by one or more owners.
3 |
4 | # See: https://help.github.com/articles/about-codeowners/
5 |
6 | # These owners will be the default owners for everything in the repo.
7 | * @NipunaRanasinghe @Nuvindu @shafreenAnfar
8 |
--------------------------------------------------------------------------------
/.github/workflows/trivy-scan.yml:
--------------------------------------------------------------------------------
1 | name: Trivy
2 |
3 | on:
4 | workflow_dispatch:
5 | schedule:
6 | - cron: "30 20 * * *"
7 |
8 | jobs:
9 | call_workflow:
10 | name: Run Trivy Scan Workflow
11 | if: ${{ github.repository_owner == 'ballerina-platform' }}
12 | uses: ballerina-platform/ballerina-library/.github/workflows/trivy-scan-template.yml@main
13 | secrets: inherit
14 |
--------------------------------------------------------------------------------
/.github/workflows/build-timestamped-master.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | paths-ignore:
8 | - '*.md'
9 | workflow_dispatch:
10 |
11 | jobs:
12 | call_workflow:
13 | name: Run Build Workflow
14 | if: ${{ github.repository_owner == 'ballerina-platform' }}
15 | uses: ballerina-platform/ballerina-library/.github/workflows/build-timestamp-master-template.yml@main
16 | secrets: inherit
17 |
--------------------------------------------------------------------------------
/.github/workflows/pull-request.yml:
--------------------------------------------------------------------------------
1 | name: PR Build
2 |
3 | concurrency:
4 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
5 | cancel-in-progress: true
6 |
7 | on: pull_request
8 |
9 | jobs:
10 | call_workflow:
11 | name: Run PR Build Workflow
12 | if: ${{ github.repository_owner == 'ballerina-platform' }}
13 | uses: ballerina-platform/ballerina-library/.github/workflows/pull-request-build-template.yml@main
14 | secrets: inherit
15 |
--------------------------------------------------------------------------------
/.github/workflows/publish-release.yml:
--------------------------------------------------------------------------------
1 | name: Publish Release
2 |
3 | on:
4 | workflow_dispatch:
5 | repository_dispatch:
6 | types: [stdlib-release-pipeline]
7 |
8 | jobs:
9 | call_workflow:
10 | name: Run Release Workflow
11 | if: ${{ github.repository_owner == 'ballerina-platform' }}
12 | uses: ballerina-platform/ballerina-library/.github/workflows/release-package-template.yml@main
13 | secrets: inherit
14 | with:
15 | package-name: soap
16 | package-org: ballerina
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled class file
2 | *.class
3 |
4 | # Log file
5 | *.log
6 |
7 | # BlueJ files
8 | *.ctxt
9 |
10 | # Mobile Tools for Java (J2ME)
11 | .mtj.tmp/
12 |
13 | # Package Files #
14 | !gradle/wrapper/gradle-wrapper.jar
15 | *.jar
16 | *.war
17 | *.nar
18 | *.ear
19 | *.zip
20 | *.tar.gz
21 | *.rar
22 |
23 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
24 | hs_err_pid*
25 |
26 | build
27 | .gradle/
28 | target
29 | # IDEA Files
30 | .idea/
31 | *.iml
32 | *.ipr
33 | *.iws
34 |
35 | # MacOS
36 | *.DS_Store
37 |
38 | # Ballerina
39 | velocity.log*
40 | *Ballerina.lock
41 |
42 | .vscode
43 | config-dir
44 |
--------------------------------------------------------------------------------
/.github/workflows/central-publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish to the Ballerina central
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | environment:
7 | type: choice
8 | description: Select Environment
9 | required: true
10 | options:
11 | - DEV CENTRAL
12 | - STAGE CENTRAL
13 |
14 | jobs:
15 | call_workflow:
16 | name: Run Central Publish Workflow
17 | if: ${{ github.repository_owner == 'ballerina-platform' }}
18 | uses: ballerina-platform/ballerina-library/.github/workflows/central-publish-template.yml@main
19 | secrets: inherit
20 | with:
21 | environment: ${{ github.event.inputs.environment }}
22 |
--------------------------------------------------------------------------------
/changelog.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 | This file contains all the notable changes done to the Ballerina SOAP package through the releases.
3 |
4 | ## [Unreleased]
5 |
6 | ### Changed
7 | - [Make some of the Java classes proper utility classes](https://github.com/ballerina-platform/ballerina-standard-library/issues/5075)
8 |
9 | ## [0.8.0] - 2023-10-16
10 |
11 | ### Added
12 | - [Introduce soap standard library module](https://github.com/ballerina-platform/ballerina-standard-library/issues/4500)
13 | - [Introduce basic soap client](https://github.com/ballerina-platform/ballerina-standard-library/issues/4618)
14 |
15 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
16 |
--------------------------------------------------------------------------------
/ballerina/modules/wssec/error.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | # Represents any error related to the wssec module.
18 | public type Error distinct error;
19 |
--------------------------------------------------------------------------------
/issue_template.md:
--------------------------------------------------------------------------------
1 | **Description:**
2 |
3 |
4 | **Suggested Labels:**
5 |
6 |
7 | **Suggested Assignees:**
8 |
9 |
10 | **Affected Product Version:**
11 |
12 | **OS, DB, other environment details and versions:**
13 |
14 | **Steps to reproduce:**
15 |
16 |
17 | **Related Issues:**
18 |
--------------------------------------------------------------------------------
/ballerina/constants.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import soap.wssec;
18 |
19 | const SOAP_ACTION = "SOAPAction";
20 | const ACTION = "action";
21 | const wssec:NoPolicy NO_POLICY = "NoPolicy";
22 |
--------------------------------------------------------------------------------
/spotbugs-exclude.xml:
--------------------------------------------------------------------------------
1 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/ballerina/modules/wssec/init.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import ballerina/jballerina.java;
18 |
19 | isolated function init() {
20 | setModule();
21 | }
22 |
23 | isolated function setModule() = @java:Method {
24 | 'class: "org.wssec.ModuleUtils"
25 | } external;
26 |
--------------------------------------------------------------------------------
/ballerina/modules/soap12/tests/http_secured_service.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com)
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import ballerina/http;
18 |
19 | service / on new http:Listener(9091) {
20 |
21 | resource function post .(http:Request request) returns xml|error {
22 | return check request.getXmlPayload();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/ballerina/modules/soap11/tests/http_secured_service.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com).
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import ballerina/http;
18 |
19 | service / on new http:Listener(9091) {
20 |
21 | resource function post .(http:Request request) returns xml|error {
22 | return check request.getXmlPayload();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/ballerina/error.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | # Defines the common error type for the module.
18 | public type Error distinct error;
19 |
20 | const SOAP_RESPONSE_ERROR = "Failed to create SOAP response";
21 | const INVALID_PROTOCOL_ERROR = "Invalid protocol detected: Please use the `https` protocol instead of `http`.";
22 |
--------------------------------------------------------------------------------
/native/src/main/java/module-info.java:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | module soap {
18 | requires io.ballerina.runtime;
19 | requires org.apache.wss4j.dom;
20 | requires org.apache.wss4j.common;
21 | requires org.apache.santuario.xmlsec;
22 | requires java.xml;
23 | requires java.xml.crypto;
24 | requires org.apache.commons.codec;
25 | }
26 |
--------------------------------------------------------------------------------
/native/src/main/resources/META-INF/native-image/io.ballerina.stdlib/soap-native/resource-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "resources":{
3 | "includes":[{
4 | "pattern":"\\QMETA-INF/axiom.xml\\E"
5 | }, {
6 | "pattern":"\\QMETA-INF/services/javax.xml.stream.XMLInputFactory\\E"
7 | }, {
8 | "pattern":"\\QMETA-INF/services/javax.xml.stream.XMLOutputFactory\\E"
9 | }, {
10 | "pattern":"\\QMETA-INF/services/org.slf4j.spi.SLF4JServiceProvider\\E"
11 | }, {
12 | "pattern":"\\Qlogging.properties\\E"
13 | }, {
14 | "pattern":"java.base:\\Qjdk/internal/icu/impl/data/icudt67b/nfc.nrm\\E"
15 | }, {
16 | "pattern":"java.base:\\Qjdk/internal/icu/impl/data/icudt67b/nfkc.nrm\\E"
17 | }, {
18 | "pattern":"java.xml:\\Qcom/sun/org/apache/xml/internal/serializer/Encodings.properties\\E"
19 | }]},
20 | "bundles":[{
21 | "name":"com.sun.org.apache.xml.internal.serializer.XMLEntities",
22 | "locales":[""]
23 | }, {
24 | "name":"messages.wss4j_errors",
25 | "locales":[""]
26 | }, {
27 | "name":"org/apache/xml/security/resource/xmlsecurity",
28 | "locales":["en"]
29 | }]
30 | }
31 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.caching=true
2 | group=io.ballerina.stdlib
3 | version=2.3.1-SNAPSHOT
4 |
5 | checkstylePluginVersion=10.12.0
6 | spotbugsPluginVersion=6.0.18
7 | shadowJarPluginVersion=8.1.1
8 | downloadPluginVersion=5.4.0
9 | releasePluginVersion=2.8.0
10 | ballerinaGradlePluginVersion=2.3.0
11 |
12 | ballerinaLangVersion=2201.12.0
13 |
14 | stdlibIoVersion=1.8.0
15 | stdlibTimeVersion=2.7.0
16 | stdlibUrlVersion=2.6.0
17 |
18 | stdlibConstraintVersion=1.7.0
19 | stdlibCryptoVersion=2.9.0
20 | stdlibLogVersion=2.12.0
21 | stdlibOsVersion=1.10.0
22 | stdlibRandomVersion=1.7.0
23 | stdlibTaskVersion=2.7.0
24 |
25 | stdlibCacheVersion=3.10.0
26 | stdlibFileVersion=1.12.0
27 | stdlibMimeVersion=2.12.0
28 | stdlibUuidVersion=1.10.0
29 |
30 | stdlibAuthVersion=2.14.0
31 | stdlibDataJsonDataVersion=1.1.0
32 | stdlibJwtVersion=2.15.0
33 | stdlibOAuth2Version=2.14.0
34 |
35 | stdlibHttpVersion=2.14.0
36 |
37 | wsSecurityDomVersion=3.0.1
38 | wsSecurityCommonVersion=3.0.1
39 | xmlSecVersion=3.0.3
40 | guavaVersion=32.1.1-jre
41 |
42 | # Ballerinax Observer
43 | observeVersion=1.5.0
44 | observeInternalVersion=1.5.0
45 |
--------------------------------------------------------------------------------
/ballerina/modules/soap12/error.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | # Defines the common error type for the SOAP 1.2 module.
18 | public type Error distinct error;
19 |
20 | const SOAP_RESPONSE_ERROR = "Failed to create SOAP response";
21 | const SOAP_CLIENT_ERROR = "Failed to initialize SOAP 1.2 client";
22 | const SOAP_ERROR = "Failed to generate a response";
23 | const INVALID_OUTBOUND_SECURITY_ERROR = "Outbound security configurations do not match with the SOAP response";
24 |
--------------------------------------------------------------------------------
/ballerina/modules/soap11/error.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | # Defines the common error type for the SOAP 1.1 module.
18 | public type Error distinct error;
19 |
20 | const SOAP_RESPONSE_ERROR = "Failed to create SOAP response";
21 | const SOAP_CLIENT_ERROR = "Failed to initialize SOAP 1.1 client";
22 | const SOAP_ERROR = "Error occurred while executing the API";
23 | const INVALID_OUTBOUND_SECURITY_ERROR = "Outbound security configurations do not match with the SOAP response";
24 |
--------------------------------------------------------------------------------
/ballerina/Ballerina.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | org = "ballerina"
3 | name = "soap"
4 | version = "2.3.0"
5 | authors = ["Ballerina"]
6 | export=["soap", "soap.soap11", "soap.soap12"]
7 | keywords = ["soap"]
8 | repository = "https://github.com/ballerina-platform/module-ballerina-soap"
9 | icon = "icon.png"
10 | license = ["Apache-2.0"]
11 | distribution = "2201.12.0"
12 |
13 | [build-options]
14 | observabilityIncluded = true
15 |
16 | [platform.java21]
17 | graalvmCompatible = true
18 |
19 | [[platform.java21.dependency]]
20 | groupId = "io.ballerina.stdlib"
21 | artifactId = "soap-native"
22 | version = "2.3.0"
23 | path = "../native/build/libs/soap-native-2.3.0.jar"
24 |
25 | [[platform.java21.dependency]]
26 | groupId = "org.apache.wss4j"
27 | artifactId = "wss4j-ws-security-dom"
28 | version = "3.0.1"
29 | path = "./lib/wss4j-ws-security-dom-3.0.1.jar"
30 |
31 | [[platform.java21.dependency]]
32 | groupId = "org.apache.wss4j"
33 | artifactId = "wss4j-ws-security-common"
34 | version = "3.0.1"
35 | path = "./lib/wss4j-ws-security-common-3.0.1.jar"
36 |
37 | [[platform.java21.dependency]]
38 | groupId = "org.apache.santuario"
39 | artifactId = "xmlsec"
40 | version = "3.0.3"
41 | path = "./lib/xmlsec-3.0.3.jar"
42 |
--------------------------------------------------------------------------------
/native/src/main/java/org/wssec/ModuleUtils.java:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | package org.wssec;
18 |
19 | import io.ballerina.runtime.api.Environment;
20 | import io.ballerina.runtime.api.Module;
21 |
22 | public class ModuleUtils {
23 |
24 | private static Module module;
25 |
26 | private ModuleUtils() {}
27 |
28 | public static void setModule(Environment environment) {
29 | module = environment.getCurrentModule();
30 | }
31 |
32 | public static Module getModule() {
33 | return module;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/ballerina/modules/wssec/tests/resources/x509_certificate_2.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDETCCAfkCFDKN6J0IJE2sBxy0yoWYwwpBdhxBMA0GCSqGSIb3DQEBCwUAMEUx
3 | CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl
4 | cm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMjMwOTAzMjEyNjI1WhcNMjMxMDAzMjEy
5 | NjI1WjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UE
6 | CgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOC
7 | AQ8AMIIBCgKCAQEAxG2CEtglz5hRwN3Yybb1gnsd5eJNBAm2nlzPFL1tazM6eAg1
8 | k5QggDKh5VV9XIAejEv3xVnSMACWgKEJvwDJjNivta7qTBOqPi/EM3oj0CR3IK4/
9 | U51p2z3JPaVSRapmkXpJX1k5Bf6n2n7laztOJxj2wwt5LkgJAmjDXLuiVScnPyzo
10 | Nsg08R8BBFqmFWI+ulyaR0Kza+m70e2K9Cj6s2C3thPyEQ4252qZY0JdgftGQmL2
11 | QGsMYEDmTNT0caZHbosdw1AlQ1l2JXcAfi2T07iXJkojSWVzf1SkVJ6A4j1+J3ON
12 | pT9zutZzjpkGRJkGxs1A4jZKWoSxXSv5J7KObwIDAQABMA0GCSqGSIb3DQEBCwUA
13 | A4IBAQAIKHVsFujOyXhn8nWenrg8xgJHJ1t76i1h91S8dtJz12u3OjvhHKt78mZq
14 | DOtOWKevY/h/StGu5Qmm/hDfTRKA4g+fIDYIf/WGAs6PO3Kac1GfWaTAwtDBfeP2
15 | Sl4Jy47w5oAlUPu0LKszrpN/tPVfteSvhuo/ObTnj6lW4z/nArzPrrTDirzrpxVW
16 | CIJrTpKr2N8EoBufE2XVA54w249nVjd1pPgPJ8bpBVD2UgNZ95nZDYCCTKb4CDdc
17 | JZ69CxnWq+SwRk4Gy0A3YOIjzocTzEDaGlBYaSd33zRDbOuEb8S85Tg3dzATPPtm
18 | 7yQGi2sB6Lrs3qL9lc2fE/t7Sjgj
19 | -----END CERTIFICATE-----
20 |
--------------------------------------------------------------------------------
/ballerina/configs.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import ballerina/http;
18 |
19 | # SOAP client configurations.
20 | #
21 | # + httpConfig - HTTP Configuration
22 | # + outboundSecurity - Web service security configurations for SOAP requests
23 | # + inboundSecurity - Web service security configurations to decrypt and verify SOAP responses
24 | public type ClientConfig record {|
25 | http:ClientConfiguration httpConfig = {};
26 | OutboundSecurityConfig|OutboundSecurityConfig[] outboundSecurity = NO_POLICY;
27 | InboundSecurityConfig inboundSecurity = {};
28 | |};
29 |
--------------------------------------------------------------------------------
/ballerina/modules/wssec/sec_header.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import ballerina/jballerina.java;
18 |
19 | isolated class WSSecurityHeader {
20 |
21 | private handle nativeSecHeader;
22 |
23 | isolated function init(Document document) returns Error? {
24 | self.nativeSecHeader = newSecHeader(document);
25 | }
26 |
27 | isolated function insertSecHeader() returns Error? = @java:Method {
28 | 'class: "org.wssec.WsSecurityHeader"
29 | } external;
30 | }
31 |
32 | isolated function newSecHeader(Document document) returns handle = @java:Constructor {
33 | 'class: "org.wssec.WsSecurityHeader"
34 | } external;
35 |
--------------------------------------------------------------------------------
/ballerina/modules/wssec/tests/resources/x509_certificate.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDazCCAlOgAwIBAgIUHYnC3ALHIdLNO+JlFu/8usNrq2owDQYJKoZIhvcNAQEL
3 | BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
4 | GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMzA4MjUwNzE5NDVaFw0yNDA4
5 | MjQwNzE5NDVaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
6 | HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
7 | AQUAA4IBDwAwggEKAoIBAQDdfueteXm2iSP+Pjr0+tK4G5pCxshqq0Z/ldDRpMzx
8 | vCAOFWIDS/ewcigUx5gMM7KHZfSzVXjlxahF5gqDbriunTSymFPfAQHimM13q1XZ
9 | uBCdHh1ayKmXuP4H/T1zp35rfElyGlfocWNx/Lef4y5ZFJN0BMScVdtue4+vCtst
10 | 5NLOBaFBoZU3DGk7muu6+7+ml8P4WqSW7CR0usTvrmPssDHUqXCA7vARlGoGgTHy
11 | trp7e7epNf5AZD3QjSWpLEIb6DuY9LyQYeC2Yry6GGN129lNJjh4HsXG6ldu0QQU
12 | rCkma6oP9JSCHI0Dm0i0lDVTFYLjJ60tap7r5dXEKBXRAgMBAAGjUzBRMB0GA1Ud
13 | DgQWBBTEWR0+4AmZuo10dDXp0D9bVeDGlDAfBgNVHSMEGDAWgBTEWR0+4AmZuo10
14 | dDXp0D9bVeDGlDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAi
15 | NlCjK/OQaKPanfyacR+v8k3RU4qs7CJJ78el8iN7ZWAQn9Z3o5VIwnHWCNYIBZr9
16 | CWSzV72EO7j9qXSLkbQL594a6+lDSxF7vwsEx8N1ktxz4Dkg0GPyrViBDTlcloOG
17 | g5/ZNKsP++QczspdnJuyOTCL3DLd/P1d3WzfJF+NefvtDhmcpZxZL1YPKpeAobqf
18 | nRLQVeWhZbNn/XbiWnrwx4LfN+r8aQh5kiO4xl31lPzg9cflPGhTHqG3Undeis9k
19 | upnsjgsfBNas54lgYpOadP0f8Ooc0nJvT7ry0LbUgbkk7dGkWm9Qh2eu2e5v7Fw8
20 | 0qWPT/H83ANtk/4Y5XCA
21 | -----END CERTIFICATE-----
22 |
--------------------------------------------------------------------------------
/.github/workflows/build-with-bal-test-graalvm.yml:
--------------------------------------------------------------------------------
1 | name: GraalVM Check
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | lang_tag:
7 | description: Branch/Release Tag of the Ballerina Lang
8 | required: true
9 | default: master
10 | lang_version:
11 | description: Ballerina Lang Version (If given ballerina lang build will be skipped)
12 | required: false
13 | default: ''
14 | native_image_options:
15 | description: Default native-image options
16 | required: false
17 | default: ''
18 | schedule:
19 | - cron: '30 18 * * *'
20 | pull_request:
21 | branches:
22 | - master
23 | types: [opened, synchronize, reopened, labeled, unlabeled]
24 |
25 | concurrency:
26 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
27 | cancel-in-progress: true
28 |
29 | jobs:
30 | call_stdlib_workflow:
31 | name: Run StdLib Workflow
32 | if: ${{ github.event_name != 'schedule' || (github.event_name == 'schedule' && github.repository_owner == 'ballerina-platform') }}
33 | uses: ballerina-platform/ballerina-library/.github/workflows/build-with-bal-test-graalvm-template.yml@main
34 | with:
35 | lang_tag: ${{ inputs.lang_tag }}
36 | lang_version: ${{ inputs.lang_version }}
37 | native_image_options: ${{ inputs.native_image_options }}
38 |
--------------------------------------------------------------------------------
/.github/workflows/update_specs.yml:
--------------------------------------------------------------------------------
1 | name: Update Specifications
2 |
3 | env:
4 | SPEC_FOLDER_PATH: 'docs/spec'
5 |
6 | on:
7 | workflow_dispatch:
8 | push:
9 | branches:
10 | - master
11 | paths:
12 | - 'docs/spec/**'
13 |
14 | jobs:
15 | update_specs:
16 | name: Update Specifications
17 | if: github.repository_owner == 'ballerina-platform'
18 | runs-on: ubuntu-latest
19 |
20 | steps:
21 | - name: Checkout Repository
22 | uses: actions/checkout@v2
23 |
24 | - name: Get current date
25 | id: date
26 | run: echo "::set-output name=date::$(date +'%Y-%m-%d')"
27 |
28 | - name: Get Repo Name
29 | id: repo_name
30 | run: |
31 | MODULE=${{ github.event.repository.name }}
32 | echo "::set-output name=short_name::${MODULE##*-}"
33 |
34 | - name: Trigger Workflow
35 | run: |
36 | curl --request POST \
37 | 'https://api.github.com/repos/ballerina-platform/ballerina-dev-website/dispatches' \
38 | -H 'Accept: application/vnd.github.v3+json' \
39 | -H 'Authorization: Bearer ${{ secrets.BALLERINA_BOT_TOKEN }}' \
40 | --data "{
41 | \"event_type\": \"update-stdlib-specs\",
42 | \"client_payload\": {
43 | \"module_name\": \"${{ github.event.repository.name }}\",
44 | \"short_name\": \"${{ steps.repo_name.outputs.short_name }}\",
45 | \"file_dir\": \"${{ github.event.repository.name }}/${{ env.SPEC_FOLDER_PATH }}\",
46 | \"release_date\": \"${{ steps.date.outputs.date }}\"
47 | }
48 | }"
49 |
--------------------------------------------------------------------------------
/ballerina/modules/wssec/encryption.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import ballerina/jballerina.java;
18 |
19 | isolated class Encryption {
20 |
21 | private handle nativeEncryption;
22 |
23 | isolated function init() returns Error? {
24 | self.nativeEncryption = newEncryption();
25 | }
26 |
27 | public isolated function setEncryptionAlgorithm(string encryptionAlgorithm) = @java:Method {
28 | 'class: "org.wssec.Encryption"
29 | } external;
30 |
31 | public isolated function setEncryptedData(byte[] encryptedData) = @java:Method {
32 | 'class: "org.wssec.Encryption"
33 | } external;
34 |
35 | public isolated function getEncryptedKeyElements(byte[] encryptedKey) returns string|Error = @java:Method {
36 | 'class: "org.wssec.Encryption"
37 | } external;
38 | }
39 |
40 | isolated function newEncryption() returns handle = @java:Constructor {
41 | 'class: "org.wssec.Encryption"
42 | } external;
43 |
--------------------------------------------------------------------------------
/ballerina/modules/wssec/tests/resources/xml/soap_envelope.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | 3c9c5c6d-2123-405f-ab25-7399001e9512
10 | 2023-08-08T16:15:36.806+02:00
11 |
12 | MunicipalityCitizenRight
13 |
14 |
15 | 01051537140
16 |
17 | 2024-08-08+02:00
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/ballerina/modules/wssec/tests/resources/certificate.pem:
--------------------------------------------------------------------------------
1 | Bag Attributes
2 | friendlyName: mykey
3 | localKeyID: 54 69 6D 65 20 31 37 32 38 32 32 31 33 34 37 35 35 38
4 | subject=C=Unknown, ST=Unknown, L=Unknown, O=Unknown, OU=Unknown, CN=Unknown
5 | issuer=C=Unknown, ST=Unknown, L=Unknown, O=Unknown, OU=Unknown, CN=Unknown
6 | -----BEGIN CERTIFICATE-----
7 | MIIDezCCAmOgAwIBAgIIZbI69qIsxNgwDQYJKoZIhvcNAQELBQAwbDEQMA4GA1UE
8 | BhMHVW5rbm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQ
9 | MA4GA1UEChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5r
10 | bm93bjAeFw0yNDEwMDYxMzI3MzhaFw0yNTEwMDYxMzI3MzhaMGwxEDAOBgNVBAYT
11 | B1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vua25vd24xEDAO
12 | BgNVBAoTB1Vua25vd24xEDAOBgNVBAsTB1Vua25vd24xEDAOBgNVBAMTB1Vua25v
13 | d24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7rrO9u6/H4VboCxbs
14 | WX7eF/Kbjhzjx61zd2gIot4t+/e7j4R/4Hejn9+cgB++NY3uHtJ5wlVYtSDn5XJO
15 | XwjyNClqv8adBCkiCiwGClzgd+pUk6w+8ObbCgT7NZzVU7oh6LNpzYZXYsr4FkPr
16 | tRwopksO1pFGMJtDxWEkUAIj/NjscwgTmZJ+Tt2ISWx8Vv0h3rYVSyLqHdgjIl/W
17 | FAPMbHgiPL2lqWRK7/sOUqtn+hHuj2W+T1rzSf70642Ng++DHKwiGc+N33AMXyvH
18 | 0qkhCBytC1Bd6JeWwZaonZKkdWj/4qhWhLcKGxJWrMDLIDhEo/I2aB4DUgAEFgkv
19 | GaUNAgMBAAGjITAfMB0GA1UdDgQWBBTxqECeIvo1iOqIh+ewk2O9H9+PTDANBgkq
20 | hkiG9w0BAQsFAAOCAQEAGUbw159JMWFavJulqNaBzDe70Zd5Rtp+uGP9xgQN3Gqa
21 | TBK/UhlmnMJw+0ess9iHELDJsMAexcJFajZc2p2W3qCrGvWtMglB7FGWjJU9N5SQ
22 | eX1d5wXSLg4i2G0DFx6bQcRbbBqwoF392JQjx6aiPXfP90hp/R3OkznNUXhpFFmq
23 | AFFe/eg3RtI3aDBYxlDDHh92JxwVrq1QMh2vaGuLJFGV3AEa+Zn4lSRX5cB2NcxI
24 | 1PZSCQx/cl8AO8x0WRyU+xvMVCtXG/Izz+iCUSnkC7tSVTAccaJgnIVPHRx+UkGm
25 | vBX2ttTLDhFUrDYMYEEyXu+aqmEIXPoIHwa2qevgtQ==
26 | -----END CERTIFICATE-----
27 |
--------------------------------------------------------------------------------
/native/src/main/java/org/wssec/Utils.java:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | package org.wssec;
18 |
19 | import io.ballerina.runtime.api.creators.ErrorCreator;
20 | import io.ballerina.runtime.api.utils.StringUtils;
21 | import io.ballerina.runtime.api.values.BError;
22 |
23 | import static org.wssec.ModuleUtils.getModule;
24 |
25 | public class Utils {
26 |
27 | private Utils() {
28 | }
29 |
30 | public static final String ERROR_TYPE = "Error";
31 | public static final String POLICY_NOT_SUPPORTED_ERROR = "Given ws security policy is currently not supported";
32 |
33 | public static BError createError(String message) {
34 | return ErrorCreator.createError(getModule(), ERROR_TYPE,
35 | StringUtils.fromString(message), null, null);
36 | }
37 |
38 | public static BError createError(String message, BError cause) {
39 | return ErrorCreator.createError(getModule(), ERROR_TYPE, StringUtils.fromString(message), cause, null);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * This file was generated by the Gradle 'init' task.
3 | *
4 | * The settings file is used to specify which projects to include in your build.
5 | *
6 | * Detailed information about configuring a multi-project build in Gradle can be found
7 | * in the user manual at https://docs.gradle.org/6.3/userguide/multi_project_builds.html
8 | */
9 |
10 | pluginManagement {
11 | plugins {
12 | id "com.github.spotbugs" version "${spotbugsPluginVersion}"
13 | id "com.github.johnrengelman.shadow" version "${shadowJarPluginVersion}"
14 | id "de.undercouch.download" version "${downloadPluginVersion}"
15 | id "net.researchgate.release" version "${releasePluginVersion}"
16 | id "io.ballerina.plugin" version "${ballerinaGradlePluginVersion}"
17 | }
18 |
19 | repositories {
20 | gradlePluginPortal()
21 | maven {
22 | url = 'https://maven.pkg.github.com/ballerina-platform/*'
23 | credentials {
24 | username System.getenv("packageUser")
25 | password System.getenv("packagePAT")
26 | }
27 | }
28 | }
29 | }
30 |
31 | plugins {
32 | id "com.gradle.enterprise" version "3.13.2"
33 | }
34 |
35 | include ':checkstyle'
36 | include ':soap-native'
37 | include ':soap-ballerina'
38 |
39 | project(':checkstyle').projectDir = file("build-config${File.separator}checkstyle")
40 | project(':soap-native').projectDir = file('native')
41 | project(':soap-ballerina').projectDir = file('ballerina')
42 |
43 | gradleEnterprise {
44 | buildScan {
45 | termsOfServiceUrl = 'https://gradle.com/terms-of-service'
46 | termsOfServiceAgree = 'yes'
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/ballerina/modules/wssec/document.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import ballerina/jballerina.java;
18 |
19 | public isolated class Document {
20 |
21 | public isolated function init(xml xmlPayload) returns Error? {
22 | handle|error documentBuilder = newDocument(self, xmlPayload);
23 | if documentBuilder is error {
24 | return error Error(documentBuilder.message());
25 | }
26 | }
27 |
28 | public isolated function getEnvelope() returns xml|Error = @java:Method {
29 | 'class: "org.wssec.DocumentBuilder"
30 | } external;
31 |
32 | public isolated function getEncryptedData() returns byte[] = @java:Method {
33 | 'class: "org.wssec.DocumentBuilder"
34 | } external;
35 |
36 | public isolated function getSignatureData() returns byte[] = @java:Method {
37 | 'class: "org.wssec.DocumentBuilder"
38 | } external;
39 | }
40 |
41 | isolated function newDocument(Document doc, xml xmlPayload) returns handle|error = @java:Constructor {
42 | 'class: "org.wssec.DocumentBuilder"
43 | } external;
44 |
--------------------------------------------------------------------------------
/ballerina/modules/wssec/tests/resources/private_key1.pem:
--------------------------------------------------------------------------------
1 | Bag Attributes
2 | friendlyName: mykey
3 | localKeyID: 54 69 6D 65 20 31 37 32 38 32 32 31 33 34 37 35 35 38
4 | Key Attributes:
5 | -----BEGIN PRIVATE KEY-----
6 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC7rrO9u6/H4Vbo
7 | CxbsWX7eF/Kbjhzjx61zd2gIot4t+/e7j4R/4Hejn9+cgB++NY3uHtJ5wlVYtSDn
8 | 5XJOXwjyNClqv8adBCkiCiwGClzgd+pUk6w+8ObbCgT7NZzVU7oh6LNpzYZXYsr4
9 | FkPrtRwopksO1pFGMJtDxWEkUAIj/NjscwgTmZJ+Tt2ISWx8Vv0h3rYVSyLqHdgj
10 | Il/WFAPMbHgiPL2lqWRK7/sOUqtn+hHuj2W+T1rzSf70642Ng++DHKwiGc+N33AM
11 | XyvH0qkhCBytC1Bd6JeWwZaonZKkdWj/4qhWhLcKGxJWrMDLIDhEo/I2aB4DUgAE
12 | FgkvGaUNAgMBAAECggEALm7cfTZwGM2BSMtlknfZ0WyvUxjnwNrn6MdD788LlOjf
13 | s4GgUFrifpLRKdDxCYgKYz0w6XrQzq+RQo4bp5QPjIynKofjxXkADDHkDmKF8+r3
14 | CJG4baIAG3TxIo1zDbw3Mqh1qtl0QS5p9NLdXvVh0BTEQRmIu4rO/wdYLzm0Ld61
15 | nnB8TCxdgniJfFyHP86bZuOOtFT2X7FpDxP+4UMZzR+9rjvfFezuCZin8Gf4oq18
16 | Yf+6evBYSIPwAlAm9QbM5iwLREdVbAceNe1/utrIIl//OAH10DOzYGrLpLH2/D7v
17 | aYjWT8FlCt5Yspsv50W1m8f44xn+cpdVDsFzEt73QQKBgQDJtd8QCjohjNzViKn/
18 | LN43EYuvDH2tal+vg2lOrz8OcQDHiz8DFJzoxAwoSwcwcN+JPOVIJqKov+ztgVYq
19 | S1+9lK+6Gv4JasTcypPMCLN27bchp7KsZCBu2wHdr8sp19+vfEu1X48Ubb0fkX/c
20 | 4huiAV1wjaaa+nmOpcA4/oo+VQKBgQDuMkgjqqEgsO56vM3iRM0A9stgVnUP3yyC
21 | vSL6pgblwROLO913l/bKDV5B1hXAFBcLLlTRGdMbVzNgnNpdZdwKkfufQfWyMKx1
22 | z2SoRlxgwlxrBtfmunHdMqLT+piwwuRLlbYWSmyDL9ghDEo/22oAHn57rJAZlmlb
23 | tHB/waCT2QKBgQClu+HD9CM/XdY1PU0wdVVAOhJjigfZbQWh2H+2Pxe4bfEOA8OK
24 | bG1gc3TpxnvpuVRyFq7tUZFkxg2OOC7sIXJQ+tJIP9VrN2b5Yxl9E8khdsB5zqho
25 | LPzZGOm3lLGBd/Y64g3ywMl3J5O1VH+SpdW+jxCPYlP6EsO+CUKfkcVU4QKBgQDm
26 | 96Kz0vRCes4D/ae1y/jtAmHanHsOVN0YOMX+PZdamYmV7QqmuJf4/FV1iV21zsU5
27 | dkeQKnZlgHy1JeMnxWlEZqGSn6bajg/sfJmiAff5av2qWgxoEknurvbsjYYZgCFW
28 | mWji3G+0FWSBRyWIHf3+95K14XIpHYwz/BdKCjrmoQKBgDwoPA5+foz6BH/Ut/KV
29 | Hj+zqrJO8M0p4Ys4/+vB7r4Mcin8hcdY920dYxPmkmz2pMEnplOas8GZUzE/KyX5
30 | wOSNzobJN+Rj3q851+u1fgl/vO78nXod2e9tvojXVz9a8EW23i17fsRt9221Nfdv
31 | 6RlOnqnMghUgVz8D7irlWLnD
32 | -----END PRIVATE KEY-----
33 |
--------------------------------------------------------------------------------
/ballerina/modules/wssec/types.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | public enum PasswordType {
18 | TEXT,
19 | DIGEST,
20 | DERIVED_KEY_TEXT,
21 | DERIVED_KEY_DIGEST
22 | }
23 |
24 | public enum SignatureAlgorithm {
25 | RSA_SHA1 = "http://www.w3.org/2000/09/xmldsig#rsa-sha1",
26 | RSA_SHA256 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
27 | RSA_SHA384 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384",
28 | RSA_SHA512 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"
29 | }
30 |
31 | public enum CanonicalizationAlgorithm {
32 | C14N_OMIT_COMMENTS = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315",
33 | C14N_WITH_COMMENTS = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments",
34 | C14N_EXCL_OMIT_COMMENTS = "http://www.w3.org/2001/10/xml-exc-c14n#",
35 | C14N_EXCL_WITH_COMMENTS = "http://www.w3.org/2001/10/xml-exc-c14n#WithComments"
36 | }
37 |
38 | public enum DigestAlgorithm {
39 | SHA1 = "http://www.w3.org/2000/09/xmldsig#sha1",
40 | SHA256 = "http://www.w3.org/2001/04/xmlenc#sha256",
41 | SHA384 = "http://www.w3.org/2001/04/xmldsig-more#sha384",
42 | SHA512 = "http://www.w3.org/2001/04/xmlenc#sha512"
43 | }
44 |
45 | public enum EncryptionAlgorithm {
46 | TRIPLE_DES = "http://www.w3.org/2001/04/xmlenc#tripledes-cbc",
47 | AES_128 = "http://www.w3.org/2001/04/xmlenc#aes128-cbc",
48 | AES_256 = "http://www.w3.org/2001/04/xmlenc#aes256-cbc"
49 | }
50 |
--------------------------------------------------------------------------------
/native/src/main/java/org/wssec/WsSecurityHeader.java:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | package org.wssec;
18 |
19 | import io.ballerina.runtime.api.utils.StringUtils;
20 | import io.ballerina.runtime.api.values.BError;
21 | import io.ballerina.runtime.api.values.BHandle;
22 | import io.ballerina.runtime.api.values.BObject;
23 | import org.apache.wss4j.common.ext.WSSecurityException;
24 | import org.apache.wss4j.dom.message.WSSecHeader;
25 | import org.w3c.dom.Document;
26 |
27 | import static org.wssec.Constants.NATIVE_DOCUMENT;
28 | import static org.wssec.Constants.NATIVE_SEC_HEADER;
29 | import static org.wssec.Utils.createError;
30 |
31 | public class WsSecurityHeader {
32 |
33 | private final WSSecHeader wsSecHeader;
34 | private final Document document;
35 |
36 | public WsSecurityHeader(BObject documentBuilder) {
37 | Document document = (Document) documentBuilder.getNativeData().get(NATIVE_DOCUMENT);
38 | this.wsSecHeader = new WSSecHeader(document);
39 | this.document = document;
40 | }
41 |
42 | protected Document getDocument() {
43 | return document;
44 | }
45 |
46 | protected WSSecHeader getWsSecHeader() {
47 | return wsSecHeader;
48 | }
49 |
50 | public static BError insertSecHeader(BObject secHeader) {
51 | BHandle handle = (BHandle) secHeader.get(StringUtils.fromString(NATIVE_SEC_HEADER));
52 | WsSecurityHeader wsSecurityHeader = (WsSecurityHeader) handle.getValue();
53 | try {
54 | wsSecurityHeader.getWsSecHeader().insertSecurityHeader();
55 | } catch (WSSecurityException e) {
56 | return createError(e.getMessage());
57 | }
58 | return null;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/native/src/main/java/io/ballerina/lib/soap/Soap.java:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | package io.ballerina.lib.soap;
18 |
19 | import io.ballerina.runtime.api.Environment;
20 | import io.ballerina.runtime.api.values.BError;
21 | import io.ballerina.runtime.api.values.BMap;
22 | import io.ballerina.runtime.api.values.BObject;
23 | import io.ballerina.runtime.api.values.BString;
24 | import io.ballerina.runtime.api.values.BTypedesc;
25 |
26 | public class Soap {
27 | private static final String REMOTE_FUNCTION = "generateResponse";
28 |
29 | public static Object sendReceive11(Environment env, BObject soap11, Object body, BString action,
30 | BMap headers, BString path, BTypedesc typeDesc) {
31 | return env.yieldAndRun(() -> {
32 | try {
33 | Object[] arguments = new Object[]{body, action, headers, path};
34 | Object result = env.getRuntime().callMethod(soap11, REMOTE_FUNCTION, null, arguments);
35 | if (result instanceof BError) {
36 | ((BError) result).printStackTrace();
37 | }
38 | return result;
39 | } catch (BError bError) {
40 | bError.printStackTrace();
41 | System.exit(1);
42 | }
43 | return null;
44 | });
45 | }
46 |
47 | public static Object sendReceive12(Environment env, BObject soap12, Object body, Object action,
48 | BMap headers, BString path, BTypedesc typeDesc) {
49 | return env.yieldAndRun(() -> {
50 | try {
51 | Object[] arguments = new Object[]{body, action, headers, path};
52 | return env.getRuntime().callMethod(soap12, REMOTE_FUNCTION, null, arguments);
53 | } catch (BError bError) {
54 | bError.printStackTrace();
55 | System.exit(1);
56 | }
57 | return null;
58 | });
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/native/src/main/java/org/wssec/Signature.java:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | package org.wssec;
18 |
19 | import io.ballerina.runtime.api.creators.ValueCreator;
20 | import io.ballerina.runtime.api.utils.StringUtils;
21 | import io.ballerina.runtime.api.values.BArray;
22 | import io.ballerina.runtime.api.values.BHandle;
23 | import io.ballerina.runtime.api.values.BObject;
24 | import io.ballerina.runtime.api.values.BString;
25 |
26 | import static org.wssec.Constants.NATIVE_SIGNATURE;
27 |
28 | public class Signature {
29 |
30 | private String signatureAlgorithm;
31 | private byte[] signatureValue;
32 |
33 | public static void setSignatureAlgorithm(BObject sign, BString signatureAlgorithm) {
34 | BHandle handle = (BHandle) sign.get(StringUtils.fromString(NATIVE_SIGNATURE));
35 | Signature signature = (Signature) handle.getValue();
36 | signature.setSignatureAlgorithm(signatureAlgorithm.getValue());
37 | }
38 |
39 | public static void setSignatureValue(BObject sign, BArray signatureValue) {
40 | BHandle handle = (BHandle) sign.get(StringUtils.fromString(NATIVE_SIGNATURE));
41 | Signature signature = (Signature) handle.getValue();
42 | signature.setSignatureValue(signatureValue.getByteArray());
43 | }
44 |
45 | public static BArray getSignatureValue(BObject sign) {
46 | BHandle handle = (BHandle) sign.get(StringUtils.fromString(NATIVE_SIGNATURE));
47 | Signature signature = (Signature) handle.getValue();
48 | return ValueCreator.createArrayValue(signature.getSignatureValue());
49 | }
50 |
51 | protected String getSignatureAlgorithm() {
52 | return signatureAlgorithm;
53 | }
54 |
55 | protected void setSignatureAlgorithm(String signatureAlgorithm) {
56 | this.signatureAlgorithm = signatureAlgorithm;
57 | }
58 |
59 | protected byte[] getSignatureValue() {
60 | return signatureValue;
61 | }
62 |
63 | protected void setSignatureValue(byte[] signatureValue) {
64 | this.signatureValue = signatureValue;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/pull_request_template.md:
--------------------------------------------------------------------------------
1 | ## Purpose
2 | > Describe the problems, issues, or needs driving this feature/fix and include links to related issues in the following format: Resolves issue1, issue2, etc.
3 |
4 | ## Goals
5 | > Describe the solutions that this feature/fix will introduce to resolve the problems described above
6 |
7 | ## Approach
8 | > Describe how you are implementing the solutions. Include an animated GIF or screenshot if the change affects the UI (email documentation@wso2.com to review all UI text). Include a link to a Markdown file or Google doc if the feature write-up is too long to paste here.
9 |
10 | ## User stories
11 | > Summary of user stories addressed by this change>
12 |
13 | ## Release note
14 | > Brief description of the new feature or bug fix as it will appear in the release notes
15 |
16 | ## Documentation
17 | > Link(s) to product documentation that addresses the changes of this PR. If no doc impact, enter “N/A” plus brief explanation of why there’s no doc impact
18 |
19 | ## Training
20 | > Link to the PR for changes to the training content in https://github.com/wso2/WSO2-Training, if applicable
21 |
22 | ## Certification
23 | > Type “Sent” when you have provided new/updated certification questions, plus four answers for each question (correct answer highlighted in bold), based on this change. Certification questions/answers should be sent to certification@wso2.com and NOT pasted in this PR. If there is no impact on certification exams, type “N/A” and explain why.
24 |
25 | ## Marketing
26 | > Link to drafts of marketing content that will describe and promote this feature, including product page changes, technical articles, blog posts, videos, etc., if applicable
27 |
28 | ## Automation tests
29 | - Unit tests
30 | > Code coverage information
31 | - Integration tests
32 | > Details about the test cases and coverage
33 |
34 | ## Security checks
35 | - Followed secure coding standards in http://wso2.com/technical-reports/wso2-secure-engineering-guidelines? yes/no
36 | - Ran FindSecurityBugs plugin and verified report? yes/no
37 | - Confirmed that this PR doesn't commit any keys, passwords, tokens, usernames, or other secrets? yes/no
38 |
39 | ## Samples
40 | > Provide high-level details about the samples related to this feature
41 |
42 | ## Related PRs
43 | > List any other related PRs
44 |
45 | ## Migrations (if applicable)
46 | > Describe migration steps and platforms on which migration has been tested
47 |
48 | ## Test environment
49 | > List all JDK versions, operating systems, databases, and browser/versions on which this feature/fix was tested
50 |
51 | ## Learning
52 | > Describe the research phase and any blog posts, patterns, libraries, or add-ons you used to solve the problem.
--------------------------------------------------------------------------------
/ballerina/types.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import soap.wssec;
18 |
19 | # Represents enums for all the supported password types.
20 | #
21 | public enum PasswordType {
22 | TEXT,
23 | DIGEST,
24 | DERIVED_KEY_TEXT,
25 | DERIVED_KEY_DIGEST
26 | }
27 |
28 | # Represents enums for all the supported signature algorithms.
29 | #
30 | public enum SignatureAlgorithm {
31 | RSA_SHA1 = "http://www.w3.org/2000/09/xmldsig#rsa-sha1",
32 | RSA_SHA256 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
33 | RSA_SHA384 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384",
34 | RSA_SHA512 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"
35 | }
36 |
37 | # Represents enums for all the supported encryption algorithms.
38 | #
39 | public enum EncryptionAlgorithm {
40 | TRIPLE_DES = "http://www.w3.org/2001/04/xmlenc#tripledes-cbc",
41 | AES_128 = "http://www.w3.org/2001/04/xmlenc#aes128-cbc",
42 | AES_256 = "http://www.w3.org/2001/04/xmlenc#aes256-cbc"
43 | }
44 |
45 | # Represents enums for all the supported canonicalization algorithms.
46 | #
47 | public enum CanonicalizationAlgorithm {
48 | C14N_OMIT_COMMENTS = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315",
49 | C14N_WITH_COMMENTS = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments",
50 | C14N_EXCL_OMIT_COMMENTS = "http://www.w3.org/2001/10/xml-exc-c14n#",
51 | C14N_EXCL_WITH_COMMENTS = "http://www.w3.org/2001/10/xml-exc-c14n#WithComments"
52 | }
53 |
54 | # Represents enums for all the supported digest algorithms.
55 | #
56 | public enum DigestAlgorithm {
57 | SHA1 = "http://www.w3.org/2000/09/xmldsig#sha1",
58 | SHA256 = "http://www.w3.org/2001/04/xmlenc#sha256",
59 | SHA384 = "http://www.w3.org/2001/04/xmldsig-more#sha384",
60 | SHA512 = "http://www.w3.org/2001/04/xmlenc#sha512"
61 | }
62 |
63 | # Represents the record for outbound security configurations to verify and decrypt SOAP envelopes.
64 | #
65 | # + decryptKeystore - The keystore to decrypt the SOAP envelope
66 | # + signatureKeystore - The keystore to verify the signature of the SOAP envelope
67 | public type InboundSecurityConfig wssec:InboundConfig;
68 |
69 | # Union type of all the outbound web service security configurations.
70 | public type OutboundSecurityConfig wssec:OutboundSecurityConfig;
71 |
72 |
--------------------------------------------------------------------------------
/native/src/main/java/org/wssec/DocumentBuilder.java:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | package org.wssec;
18 |
19 | import io.ballerina.runtime.api.creators.ValueCreator;
20 | import io.ballerina.runtime.api.values.BArray;
21 | import io.ballerina.runtime.api.values.BObject;
22 | import io.ballerina.runtime.api.values.BXml;
23 | import org.w3c.dom.Document;
24 | import org.xml.sax.InputSource;
25 |
26 | import java.io.StringReader;
27 |
28 | import javax.xml.parsers.DocumentBuilderFactory;
29 |
30 | import static org.wssec.Constants.NATIVE_DOCUMENT;
31 | import static org.wssec.Utils.createError;
32 | import static org.wssec.WsSecurityUtils.convertDocumentToString;
33 |
34 | public final class DocumentBuilder {
35 | private final Document document;
36 |
37 | public DocumentBuilder(BObject documentBuilder, BXml xmlPayload) throws Exception {
38 | DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
39 | factory.setNamespaceAware(true);
40 | this.document = factory.newDocumentBuilder().parse(new InputSource(
41 | new StringReader(xmlPayload.toString())));
42 | documentBuilder.addNativeData(NATIVE_DOCUMENT, this.document);
43 | }
44 |
45 | protected DocumentBuilder(Document document) {
46 | this.document = document;
47 | }
48 |
49 | public static Object getEnvelope(BObject document) {
50 | Document nativeDocument = (Document) document.getNativeData().get(NATIVE_DOCUMENT);
51 | try {
52 | return ValueCreator.createXmlValue(convertDocumentToString(nativeDocument).toString());
53 | } catch (Exception e) {
54 | return createError(e.getMessage());
55 | }
56 | }
57 |
58 | public static BArray getSignatureData(BObject document) {
59 | Document nativeDocument = (Document) document.getNativeData().get(NATIVE_DOCUMENT);
60 | return ValueCreator.createArrayValue(WsSecurityUtils.getSignatureValue(nativeDocument));
61 | }
62 |
63 | public static BArray getEncryptedData(BObject document) {
64 | Document nativeDocument = (Document) document.getNativeData().get(NATIVE_DOCUMENT);
65 | return ValueCreator.createArrayValue(WsSecurityUtils.getEncryptedData(nativeDocument));
66 | }
67 |
68 | protected Document getNativeDocument() {
69 | return this.document;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/ballerina/modules/wssec/ws_security.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import ballerina/jballerina.java;
18 |
19 | isolated class WsSecurity {
20 | isolated function applyUsernameTokenPolicy(WSSecurityHeader wsSecurityHeader, string username,
21 | string password, string pwType) returns string|Error = @java:Method {
22 | 'class: "org.wssec.WsSecurity"
23 | } external;
24 |
25 | isolated function applyTimestampPolicy(WSSecurityHeader wsSecurityHeader, int timeToLive)
26 | returns string|Error = @java:Method {
27 | 'class: "org.wssec.WsSecurity"
28 | } external;
29 |
30 | isolated function applySignatureOnlyPolicy(WSSecurityHeader wsSecurityPolicy, Signature signature,
31 | string? x509FilePath) returns string|Error = @java:Method {
32 | 'class: "org.wssec.WsSecurity"
33 | } external;
34 |
35 | isolated function applySignatureOnly(Document soapEnvelope, boolean soap12, SignatureConfig signatureConfig)
36 | returns string|Error = @java:Method {
37 | 'class: "org.wssec.WsSecurity"
38 | } external;
39 |
40 | isolated function applyEncryptionOnly(Document soapEnvelope, boolean soap12, EncryptionConfig encryptionConfig)
41 | returns string|Error = @java:Method {
42 | 'class: "org.wssec.WsSecurity"
43 | } external;
44 |
45 | isolated function applySignatureAndEncryption(Document soapEnvelope, boolean soap12,
46 | SignatureConfig signatureConfig, EncryptionConfig encryptionConfig)
47 | returns string|Error = @java:Method {
48 | 'class: "org.wssec.WsSecurity"
49 | } external;
50 |
51 | isolated function applyEncryptionOnlyPolicy(WSSecurityHeader wsSecurityPolicy, Encryption encryption)
52 | returns string|Error = @java:Method {
53 | 'class: "org.wssec.WsSecurity"
54 | } external;
55 |
56 | isolated function verifySignature(Document soapEnvelope, InboundConfig config)
57 | returns boolean|error = @java:Method {
58 | 'class: "org.wssec.WsSecurity"
59 | } external;
60 |
61 | isolated function decryptEnvelope(Document soapEnvelope, InboundConfig config)
62 | returns Document|error = @java:Method {
63 | 'class: "org.wssec.WsSecurity"
64 | } external;
65 | }
66 |
--------------------------------------------------------------------------------
/native/src/main/java/org/wssec/Encryption.java:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | package org.wssec;
18 |
19 | import io.ballerina.runtime.api.creators.ValueCreator;
20 | import io.ballerina.runtime.api.utils.StringUtils;
21 | import io.ballerina.runtime.api.values.BArray;
22 | import io.ballerina.runtime.api.values.BHandle;
23 | import io.ballerina.runtime.api.values.BObject;
24 | import io.ballerina.runtime.api.values.BString;
25 |
26 | import static org.wssec.Constants.NATIVE_ENCRYPTION;
27 | import static org.wssec.Utils.createError;
28 |
29 | public class Encryption {
30 |
31 | private String encryptionAlgorithm;
32 | private byte[] encryptedData;
33 |
34 | public static void setEncryptionAlgorithm(BObject encrypt, BString encryptionAlgorithm) {
35 | BHandle handle = (BHandle) encrypt.get(StringUtils.fromString(NATIVE_ENCRYPTION));
36 | Encryption encryption = (Encryption) handle.getValue();
37 | encryption.setEncryptionAlgorithm(encryptionAlgorithm.getValue());
38 | }
39 |
40 | public static void setEncryptedData(BObject encrypt, BArray encryptedData) {
41 | BHandle handle = (BHandle) encrypt.get(StringUtils.fromString(NATIVE_ENCRYPTION));
42 | Encryption encryption = (Encryption) handle.getValue();
43 | encryption.setEncryptedData(encryptedData.getByteArray());
44 | }
45 |
46 | public static BArray getEncryptedData(BObject encrypt) {
47 | BHandle handle = (BHandle) encrypt.get(StringUtils.fromString(NATIVE_ENCRYPTION));
48 | Encryption encryption = (Encryption) handle.getValue();
49 | return ValueCreator.createArrayValue(encryption.getEncryptedData());
50 | }
51 |
52 | public static Object getEncryptedKeyElements(BArray encryptedData) {
53 | try {
54 | return WsSecurityUtils.getEncryptedKeyElement(encryptedData.getByteArray());
55 | } catch (Exception e) {
56 | return createError(e.getMessage());
57 | }
58 | }
59 |
60 | protected String getEncryptionAlgorithm() {
61 | return encryptionAlgorithm;
62 | }
63 |
64 | protected byte[] getEncryptedData() {
65 | return encryptedData;
66 | }
67 |
68 | protected void setEncryptionAlgorithm(String encryptionAlgorithm) {
69 | this.encryptionAlgorithm = encryptionAlgorithm;
70 | }
71 |
72 | protected void setEncryptedData(byte[] encryptedData) {
73 | this.encryptedData = encryptedData;
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%"=="" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%"=="" set DIRNAME=.
29 | @rem This is normally unused
30 | set APP_BASE_NAME=%~n0
31 | set APP_HOME=%DIRNAME%
32 |
33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
35 |
36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
38 |
39 | @rem Find java.exe
40 | if defined JAVA_HOME goto findJavaFromJavaHome
41 |
42 | set JAVA_EXE=java.exe
43 | %JAVA_EXE% -version >NUL 2>&1
44 | if %ERRORLEVEL% equ 0 goto execute
45 |
46 | echo.
47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
48 | echo.
49 | echo Please set the JAVA_HOME variable in your environment to match the
50 | echo location of your Java installation.
51 |
52 | goto fail
53 |
54 | :findJavaFromJavaHome
55 | set JAVA_HOME=%JAVA_HOME:"=%
56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
57 |
58 | if exist "%JAVA_EXE%" goto execute
59 |
60 | echo.
61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
62 | echo.
63 | echo Please set the JAVA_HOME variable in your environment to match the
64 | echo location of your Java installation.
65 |
66 | goto fail
67 |
68 | :execute
69 | @rem Setup the command line
70 |
71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
72 |
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if %ERRORLEVEL% equ 0 goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | set EXIT_CODE=%ERRORLEVEL%
85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
87 | exit /b %EXIT_CODE%
88 |
89 | :mainEnd
90 | if "%OS%"=="Windows_NT" endlocal
91 |
92 | :omega
93 |
--------------------------------------------------------------------------------
/ballerina/modules/wssec/signature.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import ballerina/crypto;
18 | import ballerina/jballerina.java;
19 |
20 | isolated class Signature {
21 |
22 | private handle nativeSignature;
23 |
24 | isolated function init() returns Error? {
25 | self.nativeSignature = newSignature();
26 | }
27 |
28 | public isolated function signData(string dataString, SignatureAlgorithm signatureAlgorithm,
29 | crypto:PrivateKey privateKey) returns byte[]|Error {
30 | byte[] data = dataString.toBytes();
31 | do {
32 | match signatureAlgorithm {
33 | RSA_SHA1 => {
34 | return check crypto:signRsaSha1(data, privateKey);
35 | }
36 | RSA_SHA256 => {
37 | return check crypto:signRsaSha256(data, privateKey);
38 | }
39 | RSA_SHA384 => {
40 | return check crypto:signRsaSha384(data, privateKey);
41 | }
42 | _ => {
43 | return check crypto:signRsaSha512(data, privateKey);
44 | }
45 | }
46 | } on fail error signatureError {
47 | return error Error("Error occurred while signing the data", signatureError);
48 | }
49 | }
50 |
51 | public isolated function verifySignature(byte[] data, byte[] signature, crypto:PublicKey publicKey,
52 | SignatureAlgorithm signatureAlgorithm) returns boolean|Error {
53 | do {
54 | match signatureAlgorithm {
55 | RSA_SHA1 => {
56 | return check crypto:verifyRsaSha1Signature(data, signature, publicKey);
57 | }
58 | RSA_SHA256 => {
59 | return check crypto:verifyRsaSha256Signature(data, signature, publicKey);
60 | }
61 | RSA_SHA384 => {
62 | return check crypto:verifyRsaSha384Signature(data, signature, publicKey);
63 | }
64 | _ => {
65 | return check crypto:verifyRsaSha512Signature(data, signature, publicKey);
66 | }
67 | }
68 | } on fail error signatureError {
69 | return error Error("Error occurred while verifying the signature", signatureError);
70 | }
71 | }
72 |
73 | public isolated function setSignatureAlgorithm(string signatureAlgorithm) = @java:Method {
74 | 'class: "org.wssec.Signature"
75 | } external;
76 |
77 | public isolated function setSignatureValue(byte[] signatureValue) = @java:Method {
78 | 'class: "org.wssec.Signature"
79 | } external;
80 | }
81 |
82 | isolated function newSignature() returns handle = @java:Constructor {
83 | 'class: "org.wssec.Signature"
84 | } external;
85 |
--------------------------------------------------------------------------------
/native/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | plugins {
19 | id 'java'
20 | id 'checkstyle'
21 | id 'com.github.spotbugs'
22 | }
23 |
24 | description = 'Ballerina - SOAP Java Utils'
25 |
26 | dependencies {
27 | checkstyle project(':checkstyle')
28 | checkstyle "com.puppycrawl.tools:checkstyle:${checkstylePluginVersion}"
29 |
30 | implementation group: 'org.ballerinalang', name: 'ballerina-runtime', version: "${ballerinaLangVersion}"
31 | implementation group: 'com.google.guava', name: 'guava', version: "${guavaVersion}"
32 | implementation group: 'org.apache.wss4j', name: 'wss4j-ws-security-dom', version: "${wsSecurityDomVersion}"
33 | implementation group: 'org.apache.wss4j', name: 'wss4j-ws-security-common', version: "${wsSecurityCommonVersion}"
34 | implementation group: 'org.apache.santuario', name: 'xmlsec', version: "${xmlSecVersion}"
35 | compileOnly group: 'org.graalvm.nativeimage', name: 'svm', version: '22.2.0'
36 | }
37 |
38 | checkstyle {
39 | toolVersion "${project.checkstylePluginVersion}"
40 | configFile rootProject.file("build-config/checkstyle/build/checkstyle.xml")
41 | configProperties = ["suppressionFile" : file("${rootDir}/build-config/checkstyle/build/suppressions.xml")]
42 | }
43 |
44 | checkstyleMain.dependsOn(":checkstyle:downloadCheckstyleRuleFiles")
45 |
46 | spotbugsMain {
47 | def classLoader = plugins["com.github.spotbugs"].class.classLoader
48 | def SpotBugsConfidence = classLoader.findLoadedClass("com.github.spotbugs.snom.Confidence")
49 | def SpotBugsEffort = classLoader.findLoadedClass("com.github.spotbugs.snom.Effort")
50 | effort = SpotBugsEffort.MAX
51 | reportLevel = SpotBugsConfidence.LOW
52 | reportsDir = file("$project.buildDir/reports/spotbugs")
53 | reports {
54 | html.enabled true
55 | text.enabled = true
56 | }
57 | def excludeFile = file("${rootDir}/spotbugs-exclude.xml")
58 | if(excludeFile.exists()) {
59 | excludeFilter = excludeFile
60 | }
61 | }
62 |
63 | def excludePattern = '**/module-info.java'
64 | tasks.withType(Checkstyle) {
65 | exclude excludePattern
66 | }
67 |
68 | publishing {
69 | publications {
70 | mavenJava(MavenPublication) {
71 | groupId project.group
72 | artifactId "soap-native"
73 | version = project.version
74 | artifact jar
75 | }
76 | }
77 |
78 | repositories {
79 | maven {
80 | name = "GitHubPackages"
81 | url = uri("https://maven.pkg.github.com/ballerina-platform/module-ballerina-constraint")
82 | credentials {
83 | username = System.getenv("publishUser")
84 | password = System.getenv("publishPAT")
85 | }
86 | }
87 | }
88 | }
89 |
90 | compileJava {
91 | doFirst {
92 | options.compilerArgs = [
93 | '--module-path', classpath.asPath,
94 | ]
95 | classpath = files()
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/native/src/main/java/org/wssec/Constants.java:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | package org.wssec;
18 |
19 | public class Constants {
20 |
21 | private Constants() {
22 | }
23 |
24 | public static final int ITERATION = 1000;
25 | public static final String DIGEST = "DIGEST";
26 | public static final String DERIVED_KEY_TEXT = "DERIVED_KEY_TEXT";
27 | public static final String DERIVED_KEY_DIGEST = "DERIVED_KEY_DIGEST";
28 | public static final String PASSWORD = "password";
29 | public static final String NATIVE_SEC_HEADER = "nativeSecHeader";
30 | public static final String NATIVE_DOCUMENT = "nativeDocumentBuilder";
31 | public static final String NATIVE_SIGNATURE = "nativeSignature";
32 | public static final String NATIVE_ENCRYPTION = "nativeEncryption";
33 | public static final String SIGNATURE_VALUE_TAG = "ds:SignatureValue";
34 | public static final String SIGNATURE_METHOD_TAG = "ds:SignatureMethod";
35 | public static final String ALGORITHM = "Algorithm";
36 | public static final String KEY_INFO_TAG = "ds:KeyInfo";
37 | public static final String CIPHER_DATA_TAG = "xenc:CipherData";
38 | public static final String XML_ENC_NS = "xmlns:xenc";
39 | public static final String XML_DS_NS = "xmlns:ds";
40 | public static final String ENCRYPTED_KEY_TAG = "xenc:EncryptedKey";
41 | public static final String ENCRYPTION_METHOD_TAG = "xenc:EncryptionMethod";
42 | public static final String NAMESPACE_URI_ENC = "http://www.w3.org/2001/04/xmlenc#";
43 | public static final String CIPHER_VALUE_TAG = "CipherValue";
44 | public static final String X509 = "X.509";
45 | public static final String AES = "AES";
46 | public static final String EMPTY_XML_DOCUMENT_ERROR = "XML Document is empty";
47 | public static final String CRYPTO_PROVIDER_FIELD = "org.apache.ws.security.crypto.provider";
48 | public static final String CRYPTO_PROVIDER_VALUE = "org.apache.wss4j.common.crypto.Merlin";
49 | public static final String KEYSTORE = "keystore";
50 | public static final String DECRYPT_KEYSTORE = "decryptKeystore";
51 | public static final String SIGNATURE_KEYSTORE = "signatureKeystore";
52 | public static final String PATH = "path";
53 | public static final String DIGEST_ALGORITHM = "digestAlgorithm";
54 | public static final String CANONICALIZATION_ALGORITHM = "canonicalizationAlgorithm";
55 | public static final String SIGNATURE_ALGORITHM = "signatureAlgorithm";
56 | public static final String PRIVATE_KEY_PASSWORD = "privateKeyPassword";
57 | public static final String PRIVATE_KEY_ALIAS = "privateKeyAlias";
58 | public static final String PUBLIC_KEY_ALIAS = "publicKeyAlias";
59 | public static final String ENCRYPTION_ALGORITHM = "encryptionAlgorithm";
60 | public static final String KEYSTORE_PATH_FIELD = "org.apache.ws.security.crypto.merlin.keystore.file";
61 | public static final String KEYSTORE_PASSWORD_FIELD = "org.apache.ws.security.crypto.merlin.keystore.password";
62 | }
63 |
--------------------------------------------------------------------------------
/ballerina/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 | import org.apache.tools.ant.taskdefs.condition.Os
18 |
19 | plugins {
20 | id 'io.ballerina.plugin'
21 | }
22 |
23 | description = 'Ballerina - SOAP Module'
24 |
25 | def packageName = "soap"
26 | def packageOrg = "ballerina"
27 | def tomlVersion = stripBallerinaExtensionVersion("${project.version}")
28 | def ballerinaTomlFilePlaceHolder = new File("${project.rootDir}/build-config/resources/Ballerina.toml")
29 | def ballerinaTomlFile = new File("$project.projectDir/Ballerina.toml")
30 |
31 | def stripBallerinaExtensionVersion(String extVersion) {
32 | if (extVersion.matches(project.ext.timestampedVersionRegex)) {
33 | def splitVersion = extVersion.split('-')
34 | if (splitVersion.length > 3) {
35 | def strippedValues = splitVersion[0..-4]
36 | return strippedValues.join('-')
37 | } else {
38 | return extVersion
39 | }
40 | } else {
41 | return extVersion.replace("${project.ext.snapshotVersion}", "")
42 | }
43 | }
44 |
45 | ballerina {
46 | packageOrganization = packageOrg
47 | module = packageName
48 | langVersion = ballerinaLangVersion
49 | testCoverageParam = "--code-coverage --coverage-format=xml --includes=io.ballerina.stdlib.soap.*:ballerina.soap*"
50 | }
51 |
52 | task updateTomlFiles {
53 | doLast {
54 | def wsSecurityDomVersion = project.wsSecurityDomVersion
55 | def wsSecurityCommonVersion = project.wsSecurityCommonVersion
56 | def xmlSecVersion = project.xmlSecVersion
57 | def newConfig = ballerinaTomlFilePlaceHolder.text.replace("@project.version@", project.version)
58 | newConfig = newConfig.replace("@wssecuritydom.version@", wsSecurityDomVersion)
59 | newConfig = newConfig.replace("@wssecuritycommon.version@", wsSecurityCommonVersion)
60 | newConfig = newConfig.replace("@xmlsec.version@", xmlSecVersion)
61 | newConfig = newConfig.replace("@toml.version@", tomlVersion)
62 | ballerinaTomlFile.text = newConfig
63 | }
64 | }
65 |
66 | task commitTomlFiles {
67 | doLast {
68 | project.exec {
69 | ignoreExitValue true
70 | if (Os.isFamily(Os.FAMILY_WINDOWS)) {
71 | commandLine 'cmd', '/c', "git commit -m \"[Automated] Update the native jar versions\" Ballerina.toml Dependencies.toml"
72 | } else {
73 | commandLine 'sh', '-c', "git commit -m '[Automated] Update the native jar versions' Ballerina.toml Dependencies.toml"
74 | }
75 | }
76 | }
77 | }
78 |
79 | publishing {
80 | publications {
81 | maven(MavenPublication) {
82 | artifact source: createArtifactZip, extension: 'zip'
83 | }
84 | }
85 |
86 | repositories {
87 | maven {
88 | name = "GitHubPackages"
89 | url = uri("https://maven.pkg.github.com/ballerina-platform/module-${packageOrg}-${packageName}")
90 | credentials {
91 | username = System.getenv("publishUser")
92 | password = System.getenv("publishPAT")
93 | }
94 | }
95 | }
96 | }
97 |
98 | updateTomlFiles.dependsOn copyStdlibs
99 |
100 | test.dependsOn ":${packageName}-native:build"
101 | build.dependsOn "generatePomFileForMavenPublication"
102 | build.dependsOn ":${packageName}-native:build"
103 | publishToMavenLocal.dependsOn build
104 | publish.dependsOn build
105 |
--------------------------------------------------------------------------------
/ballerina/modules/soap11/tests/http_soap_service.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 | import ballerina/crypto;
17 | import ballerina/http;
18 | import ballerina/mime;
19 | import ballerina/soap;
20 |
21 | const crypto:KeyStore serverKeyStore = {
22 | path: X509_KEY_STORE_PATH,
23 | password: KEY_PASSWORD
24 | };
25 | crypto:PrivateKey serverPrivateKey = check crypto:decodeRsaPrivateKeyFromKeyStore(serverKeyStore, KEY_ALIAS,
26 | KEY_PASSWORD);
27 | crypto:PublicKey serverPublicKey = check crypto:decodeRsaPublicKeyFromTrustStore(serverKeyStore, KEY_ALIAS);
28 |
29 | service / on new http:Listener(9090) {
30 |
31 | resource function post .(http:Request request) returns xml|error {
32 | string action = check request.getHeader("SOAPAction");
33 | if action == "http://tempuri.org/Add" {
34 | return xml `5`;
35 | } else {
36 | return xml `soap:ClientSystem.Web.Services.Protocols.SoapException: Server did not recognize the value of HTTP Header SOAPAction: http://tempuri.org/invalid_action.
37 | at System.Web.Services.Protocols.Soap11ServerProtocolHelper.RouteRequest()
38 | at System.Web.Services.Protocols.SoapServerProtocol.RouteRequest(SoapServerMessage message)
39 | at System.Web.Services.Protocols.SoapServerProtocol.Initialize()
40 | at System.Web.Services.Protocols.ServerProtocol.SetContext(Type type, HttpContext context, HttpRequest request, HttpResponse response)
41 | at System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type, HttpContext context, HttpRequest request, HttpResponse response, Boolean& abortProcessing)`;
42 | }
43 | }
44 |
45 | resource function post getPayload(http:Request request) returns xml|error {
46 | return check (check request.getBodyParts())[0].getXml();
47 | }
48 |
49 | resource function post getMimePayload(http:Request request) returns http:Response|error {
50 | http:Response response = new;
51 | mime:Entity[] mtomMessage = [];
52 | mime:Entity envelope = new;
53 | check envelope.setContentType("application/xop+xml");
54 | envelope.setContentId("");
55 | envelope.setBody(check (check request.getBodyParts())[0].getXml());
56 | mtomMessage.push(envelope);
57 | response.setBodyParts(mtomMessage);
58 | response.setPayload(mtomMessage);
59 | return response;
60 | }
61 |
62 | resource function post getSamePayload(http:Request request) returns xml|error {
63 | return check request.getXmlPayload();
64 | }
65 |
66 | resource function post getSecuredMimePayload(http:Request request) returns http:Response|error {
67 | xml payload = check (check request.getBodyParts())[0].getXml();
68 | http:Response response = new;
69 | mime:Entity[] mtomMessage = [];
70 | mime:Entity envelope = new;
71 | check envelope.setContentType("application/xop+xml");
72 | envelope.setContentId("");
73 | envelope.setBody(payload);
74 | mtomMessage.push(envelope);
75 | response.setBodyParts(mtomMessage);
76 | response.setPayload(mtomMessage);
77 | return response;
78 | }
79 |
80 | resource function post getSecuredPayload(http:Request request) returns xml|error {
81 | xml payload = check request.getXmlPayload();
82 | xml applyInboundConfig = check soap:applyInboundConfig(
83 | {
84 | decryptKeystore: {
85 | path: KEY_STORE_PATH_2,
86 | password: PASSWORD
87 | },
88 | signatureKeystore: {
89 | path: KEY_STORE_PATH_2,
90 | password: PASSWORD
91 | }
92 | },
93 | payload,
94 | false
95 | );
96 | return applyInboundConfig;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/ballerina/modules/wssec/records.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import ballerina/crypto;
18 |
19 | # Union type of all the inbound web service security configurations.
20 | public type OutboundSecurityConfig NoPolicy|UsernameTokenConfig|TimestampTokenConfig|SymmetricBindingConfig
21 | |TransportBindingConfig|AsymmetricBindingConfig;
22 |
23 | # Represents the record for outbound security configurations to verify and decrypt SOAP envelopes.
24 | #
25 | # + verificationKey - The public key to verify the signature of the SOAP envelope
26 | # + decryptionKey - The private key to decrypt the SOAP envelope
27 | # + signatureAlgorithm - The algorithm to verify the SOAP envelope
28 | # + decryptionAlgorithm - The algorithm to decrypt the SOAP body
29 | public type InboundSecurityConfig record {|
30 | crypto:PublicKey verificationKey?;
31 | crypto:PrivateKey|crypto:PublicKey decryptionKey?;
32 | SignatureAlgorithm signatureAlgorithm?;
33 | EncryptionAlgorithm decryptionAlgorithm?;
34 | |};
35 |
36 | # Represents the record for Username Token policy.
37 | #
38 | # + username - The name of the user
39 | # + password - The password of the user
40 | # + passwordType - The password type of the username token
41 | public type UsernameTokenConfig record {|
42 | string username;
43 | string password;
44 | PasswordType passwordType;
45 | |};
46 |
47 | # Represents the record for Timestamp Token policy.
48 | #
49 | # + timeToLive - The time to get expired
50 | public type TimestampTokenConfig record {|
51 | int timeToLive = 300;
52 | |};
53 |
54 | # Represents the record for Symmetric Binding policy.
55 | #
56 | # + symmetricKey - The key to sign and encrypt the SOAP envelope
57 | # + servicePublicKey - The key to encrypt the symmetric key
58 | # + signatureAlgorithm - The algorithm to sign the SOAP envelope
59 | # + encryptionAlgorithm - The algorithm to encrypt the SOAP envelope
60 | # + x509Token - The path or token of the X509 certificate
61 | public type SymmetricBindingConfig record {|
62 | crypto:PrivateKey symmetricKey;
63 | crypto:PublicKey servicePublicKey;
64 | SignatureAlgorithm signatureAlgorithm?;
65 | EncryptionAlgorithm encryptionAlgorithm?;
66 | string x509Token?;
67 | |};
68 |
69 | # Represents the record for Asymmetric Binding policy.
70 | #
71 | # + signatureConfig - Configuration for applying digital signatures
72 | # + encryptionConfig - Configuration for applying encryption
73 | # + x509Token - The path or token of the X509 certificate
74 | public type AsymmetricBindingConfig record {|
75 | SignatureConfig signatureConfig?;
76 | EncryptionConfig encryptionConfig?;
77 | string x509Token?;
78 | |};
79 |
80 | # Represents the record for signature configurations.
81 | #
82 | # + keystore - The keystore to store the private key
83 | # + privateKeyAlias - The alias of the private key
84 | # + privateKeyPassword - The password of the private key
85 | # + signatureAlgorithm - The algorithm to sign the SOAP envelope
86 | # + canonicalizationAlgorithm - The algorithm to canonicalize the SOAP envelope
87 | # + digestAlgorithm - The algorithm to digest the SOAP envelope
88 | public type SignatureConfig record {|
89 | crypto:KeyStore keystore;
90 | string privateKeyAlias;
91 | string privateKeyPassword;
92 | SignatureAlgorithm signatureAlgorithm?;
93 | CanonicalizationAlgorithm canonicalizationAlgorithm = C14N_EXCL_OMIT_COMMENTS;
94 | DigestAlgorithm digestAlgorithm = SHA1;
95 | |};
96 |
97 | # Represents the record for encryption configurations.
98 | #
99 | # + keystore - The keystore to store the public key
100 | # + publicKeyAlias - The alias of the public key
101 | # + encryptionAlgorithm - The algorithm to encrypt the SOAP envelope
102 | public type EncryptionConfig record {|
103 | crypto:KeyStore keystore;
104 | string publicKeyAlias;
105 | EncryptionAlgorithm encryptionAlgorithm?;
106 | |};
107 |
108 | # Represents the record for Transport Binding policy.
109 | # + protocol - Protocol of the endpoint
110 | public type TransportBindingConfig "TransportBinding";
111 |
112 | # Represents the record to send SOAP envelopes with no security policy.
113 | public type NoPolicy "NoPolicy";
114 |
115 | # Represents the record for outbound security configurations to verify and decrypt SOAP envelopes.
116 | #
117 | # + decryptKeystore - The keystore to decrypt the SOAP envelope
118 | # + signatureKeystore - The keystore to verify the signature of the SOAP envelope
119 | public type InboundConfig record {|
120 | crypto:KeyStore decryptKeystore?;
121 | crypto:KeyStore signatureKeystore?;
122 | |};
123 |
--------------------------------------------------------------------------------
/ballerina/modules/soap12/tests/http_soap_service.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import ballerina/crypto;
18 | import ballerina/http;
19 | import ballerina/mime;
20 | import ballerina/soap;
21 |
22 | const crypto:KeyStore serverKeyStore = {
23 | path: X509_KEY_STORE_PATH,
24 | password: KEY_PASSWORD
25 | };
26 | crypto:PrivateKey serverPrivateKey = check crypto:decodeRsaPrivateKeyFromKeyStore(serverKeyStore, KEY_ALIAS,
27 | KEY_PASSWORD);
28 | crypto:PublicKey serverPublicKey = check crypto:decodeRsaPublicKeyFromTrustStore(serverKeyStore, KEY_ALIAS);
29 |
30 | service / on new http:Listener(9090) {
31 |
32 | resource function post .() returns xml|error {
33 | return xml `5`;
34 | }
35 |
36 | resource function post getPayload(http:Request request) returns xml|error {
37 | return check (check request.getBodyParts())[0].getXml();
38 | }
39 |
40 | resource function post getMimePayload(http:Request request) returns http:Response|error {
41 | http:Response response = new;
42 | mime:Entity[] mtomMessage = [];
43 | mime:Entity envelope = new;
44 | check envelope.setContentType("application/xop+xml");
45 | envelope.setContentId("");
46 | envelope.setBody(check (check request.getBodyParts())[0].getXml());
47 | mtomMessage.push(envelope);
48 | response.setBodyParts(mtomMessage);
49 | response.setPayload(mtomMessage);
50 | return response;
51 | }
52 |
53 | resource function post getActionPayload(http:Request request) returns xml|error {
54 | string[] headers = check request.getHeaders(mime:CONTENT_TYPE);
55 | mime:MediaType mediaHeader = check mime:getMediaType(headers[0]);
56 | map actionMap = mediaHeader.parameters;
57 | string action = actionMap.get("action");
58 | if action == "http://tempuri.org/Add" {
59 | return check request.getXmlPayload();
60 | }
61 | return xml `soap:ClientSystem.Web.Services.Protocols.SoapException: Server did not recognize the value of HTTP Header SOAPAction: http://tempuri.org/invalid_action.
62 | at System.Web.Services.Protocols.Soap11ServerProtocolHelper.RouteRequest()
63 | at System.Web.Services.Protocols.SoapServerProtocol.RouteRequest(SoapServerMessage message)
64 | at System.Web.Services.Protocols.SoapServerProtocol.Initialize()
65 | at System.Web.Services.Protocols.ServerProtocol.SetContext(Type type, HttpContext context, HttpRequest request, HttpResponse response)
66 | at System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type, HttpContext context, HttpRequest request, HttpResponse response, Boolean& abortProcessing)`;
67 | }
68 |
69 | resource function post getErrorPayload(http:Request request) returns xml|http:InternalServerError {
70 | return {
71 | body: "Error occurred in the server"
72 | };
73 | }
74 |
75 | resource function post getSamePayload(http:Request request) returns xml|error {
76 | return check request.getXmlPayload();
77 | }
78 |
79 | resource function post getSecuredPayload(http:Request request) returns xml|error {
80 | xml payload = check request.getXmlPayload();
81 | xml applyInboundConfig = check soap:applyInboundConfig(
82 | {
83 | decryptKeystore: {
84 | path: KEY_STORE_PATH_2,
85 | password: PASSWORD
86 | },
87 | signatureKeystore: {
88 | path: KEY_STORE_PATH_2,
89 | password: PASSWORD
90 | }
91 | },
92 | payload
93 | );
94 | return applyInboundConfig;
95 | }
96 |
97 | resource function post getSecuredMimePayload(http:Request request) returns http:Response|error {
98 | xml payload = check (check request.getBodyParts())[0].getXml();
99 | xml applyInboundConfig = check soap:applyInboundConfig(
100 | {
101 | decryptKeystore: {
102 | path: KEY_STORE_PATH_2,
103 | password: PASSWORD
104 | },
105 | signatureKeystore: {
106 | path: KEY_STORE_PATH_2,
107 | password: PASSWORD
108 | }
109 | },
110 | payload
111 | );
112 | http:Response response = new;
113 | mime:Entity[] mtomMessage = [];
114 | mime:Entity envelope = new;
115 | check envelope.setContentType("application/xop+xml");
116 | envelope.setContentId("");
117 | envelope.setBody(applyInboundConfig);
118 | mtomMessage.push(envelope);
119 | response.setBodyParts(mtomMessage);
120 | response.setPayload(mtomMessage);
121 | return response;
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/ballerina/modules/soap12/soap12.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import soap;
18 |
19 | import ballerina/http;
20 | import ballerina/mime;
21 | import ballerina/jballerina.java;
22 | import soap.wssec;
23 |
24 | # Object for the basic SOAP 1.2 client endpoint.
25 | public isolated client class Client {
26 | private final http:Client soapClient;
27 | private final readonly & soap:OutboundSecurityConfig|soap:OutboundSecurityConfig[] outboundSecurity;
28 | private final readonly & soap:InboundSecurityConfig inboundSecurity;
29 |
30 | # Gets invoked during object initialization.
31 | #
32 | # + url - URL endpoint
33 | # + config - Configurations for SOAP client
34 | # + return - `error` in case of errors or `()` otherwise
35 | public isolated function init(string url, *soap:ClientConfig config) returns Error? {
36 | do {
37 | check soap:validateTransportBindingPolicy(config);
38 | self.soapClient = check new (url, config.httpConfig);
39 | readonly & soap:ClientConfig readonlyConfig = soap:getReadOnlyClientConfig(config);
40 | self.outboundSecurity = readonlyConfig.outboundSecurity;
41 | self.inboundSecurity = readonlyConfig.inboundSecurity;
42 | } on fail var err {
43 | return error Error(SOAP_CLIENT_ERROR, err);
44 | }
45 | }
46 |
47 | # Sends SOAP request and expects a response.
48 | # ```ballerina
49 | # xml response = check soapClient->sendReceive(body);
50 | # -- OR --
51 | # mime:Entity[] response = check soapClient->sendReceive(body);
52 | # ```
53 | #
54 | # + body - SOAP request body as an `XML` or `mime:Entity[]` to work with SOAP attachments
55 | # + action - SOAP action as a `string`
56 | # + headers - SOAP headers as a `map`
57 | # + path - The resource path
58 | # + T - Default parameter use to infer the user specified type (`xml` or `mime:Entity[]`)
59 | # + return - If successful, returns the response. Else, returns an error
60 | remote isolated function sendReceive(xml|mime:Entity[] body, string? action = (), map headers = {},
61 | string path = "", typedesc T = <>)
62 | returns T|Error = @java:Method {
63 | 'class: "io.ballerina.lib.soap.Soap",
64 | name: "sendReceive12"
65 | } external;
66 |
67 | isolated function generateResponse(xml|mime:Entity[] body, string? action = (),
68 | map headers = {}, string path = "")
69 | returns xml|mime:Entity[]|Error {
70 | do {
71 | xml securedBody;
72 | xml mimeEntity = body is xml ? body : check body[0].getXml();
73 | lock {
74 | xml envelope = body is xml ? body.clone() : mimeEntity.clone();
75 | securedBody = check soap:applySecurityPolicies(self.outboundSecurity.clone(), envelope.clone());
76 | }
77 | xml|mime:Entity[] response;
78 | if body is mime:Entity[] {
79 | body[0].setXml(securedBody);
80 | response = check soap:sendReceive(body, self.soapClient, action, headers, path);
81 | } else {
82 | response = check soap:sendReceive(securedBody, self.soapClient, action, headers, path);
83 | }
84 | lock {
85 | wssec:InboundConfig? inboundSecurity = self.inboundSecurity.clone();
86 | do {
87 | if inboundSecurity is wssec:InboundConfig && inboundSecurity != {} {
88 | if response is xml {
89 | return check soap:applyInboundConfig(inboundSecurity.clone(), response.clone());
90 | } else {
91 | return check soap:applyInboundConfig(inboundSecurity.clone(),
92 | check response[0].getXml().clone());
93 | }
94 | }
95 | } on fail error soapError {
96 | return error Error(INVALID_OUTBOUND_SECURITY_ERROR, soapError);
97 | }
98 | return response;
99 | }
100 | } on fail error soapError {
101 | return error Error(SOAP_ERROR, soapError);
102 | }
103 | }
104 |
105 | # Fires and forgets requests. Sends the request without the possibility of any response from the
106 | # service (even an error).
107 | # ```ballerina
108 | # check soapClient->sendOnly(body);
109 | # ```
110 | #
111 | # + body - SOAP request body as an `XML` or `mime:Entity[]` to work with SOAP attachments
112 | # + action - SOAP action as a `string`
113 | # + headers - SOAP headers as a `map`
114 | # + path - The resource path
115 | # + return - If successful, returns `nil`. Else, returns an error
116 | remote isolated function sendOnly(xml|mime:Entity[] body, string? action = (),
117 | map headers = {}, string path = "") returns Error? {
118 | do {
119 | xml securedBody;
120 | xml mimeEntity = body is xml ? body : check body[0].getXml();
121 | lock {
122 | xml envelope = body is xml ? body.clone() : mimeEntity.clone();
123 | securedBody = check soap:applySecurityPolicies(self.outboundSecurity.clone(), envelope.clone());
124 | }
125 | return check soap:sendOnly(securedBody, self.soapClient, action, headers, path);
126 | } on fail error soapError {
127 | return error Error(SOAP_ERROR, soapError);
128 | }
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/ballerina/modules/soap11/soap11.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import soap;
18 |
19 | import ballerina/http;
20 | import ballerina/mime;
21 | import ballerina/jballerina.java;
22 | import soap.wssec;
23 |
24 | # Object for the basic SOAP 1.1 client endpoint.
25 | public isolated client class Client {
26 | private final http:Client soapClient;
27 | private final readonly & soap:OutboundSecurityConfig|soap:OutboundSecurityConfig[] outboundSecurity;
28 | private final readonly & soap:InboundSecurityConfig inboundSecurity;
29 |
30 | # Gets invoked during object initialization.
31 | #
32 | # + url - URL endpoint
33 | # + config - Configurations for SOAP client
34 | # + return - `error` in case of errors or `()` otherwise
35 | public isolated function init(string url, *soap:ClientConfig config) returns Error? {
36 | do {
37 | check soap:validateTransportBindingPolicy(config);
38 | self.soapClient = check new (url, config.httpConfig);
39 | readonly & soap:ClientConfig readonlyConfig = soap:getReadOnlyClientConfig(config);
40 | self.inboundSecurity = readonlyConfig.inboundSecurity;
41 | self.outboundSecurity = readonlyConfig.outboundSecurity;
42 | } on fail var err {
43 | return error Error(SOAP_CLIENT_ERROR, err);
44 | }
45 | }
46 |
47 | # Sends SOAP request and expects a response.
48 | # ```ballerina
49 | # xml response = check soapClient->sendReceive(body, action);
50 | # -- OR --
51 | # mime:Entity[] response = check soapClient->sendReceive(body, action);
52 | # ```
53 | #
54 | # + body - SOAP request body as an `XML` or `mime:Entity[]` to work with SOAP attachments
55 | # + action - SOAP action as a `string`
56 | # + headers - SOAP headers as a `map`
57 | # + path - The resource path
58 | # + T - Default parameter use to infer the user specified type (`xml` or `mime:Entity[]`)
59 | # + return - If successful, returns the response. Else, returns an error
60 | remote isolated function sendReceive(xml|mime:Entity[] body, string action, map headers = {},
61 | string path = "", typedesc T = <>)
62 | returns T|Error = @java:Method {
63 | 'class: "io.ballerina.lib.soap.Soap",
64 | name: "sendReceive11"
65 | } external;
66 |
67 | isolated function generateResponse(xml|mime:Entity[] body, string action,
68 | map headers = {}, string path = "")
69 | returns xml|mime:Entity[]|Error {
70 | do {
71 | xml securedBody;
72 | xml mimeEntity = body is xml ? body : check body[0].getXml();
73 | lock {
74 | xml envelope = body is xml ? body.clone() : mimeEntity.clone();
75 | securedBody = check soap:applySecurityPolicies(self.outboundSecurity.clone(), envelope.clone(), false);
76 | }
77 | xml|mime:Entity[] response;
78 | if body is mime:Entity[] {
79 | body[0].setXml(securedBody);
80 | response = check soap:sendReceive(body, self.soapClient, action, headers, path, false);
81 | } else {
82 | response = check soap:sendReceive(securedBody, self.soapClient, action, headers, path, false);
83 | }
84 | lock {
85 | wssec:InboundConfig? inboundSecurity = self.inboundSecurity.clone();
86 | do {
87 | if inboundSecurity is wssec:InboundConfig && inboundSecurity != {} {
88 | if response is xml {
89 | return check soap:applyInboundConfig(inboundSecurity.clone(), response.clone(), false);
90 | } else {
91 | return check soap:applyInboundConfig(inboundSecurity.clone(),
92 | check response[0].getXml().clone(), false);
93 | }
94 | }
95 | } on fail error soapError {
96 | return error Error(INVALID_OUTBOUND_SECURITY_ERROR, soapError);
97 | }
98 | return response;
99 | }
100 | } on fail error soapError {
101 | return error Error(SOAP_ERROR, soapError);
102 | }
103 | }
104 |
105 | # Fires and forgets requests. Sends the request without the possibility of any response from the
106 | # service (even an error).
107 | # ```ballerina
108 | # check soapClient->sendOnly(body, action);
109 | # ```
110 | #
111 | # + body - SOAP request body as an `XML` or `mime:Entity[]` to work with SOAP attachments
112 | # + action - SOAP action as a `string`
113 | # + headers - SOAP headers as a `map`
114 | # + path - The resource path
115 | # + return - If successful, returns `nil`. Else, returns an error
116 | remote isolated function sendOnly(xml|mime:Entity[] body, string action,
117 | map headers = {}, string path = "") returns Error? {
118 | do {
119 | xml securedBody;
120 | xml mimeEntity = body is xml ? body : check body[0].getXml();
121 | lock {
122 | xml envelope = body is xml ? body.clone() : mimeEntity.clone();
123 | securedBody = check soap:applySecurityPolicies(self.outboundSecurity.clone(), envelope.clone(), false);
124 | }
125 | return check soap:sendOnly(securedBody, self.soapClient, action, headers, path, false);
126 | } on fail error soapError {
127 | return error Error(SOAP_ERROR, soapError);
128 | }
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/native/src/main/java/org/wssec/WsSecurityUtils.java:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | package org.wssec;
18 |
19 | import io.ballerina.runtime.api.creators.ErrorCreator;
20 | import io.ballerina.runtime.api.utils.StringUtils;
21 | import org.apache.wss4j.common.WSEncryptionPart;
22 | import org.apache.wss4j.dom.handler.RequestData;
23 | import org.apache.wss4j.dom.message.WSSecSignature;
24 | import org.apache.wss4j.dom.message.WSSecUsernameToken;
25 | import org.apache.wss4j.dom.util.WSSecurityUtil;
26 | import org.w3c.dom.Document;
27 | import org.w3c.dom.Element;
28 | import org.w3c.dom.NodeList;
29 |
30 | import java.io.StringWriter;
31 | import java.util.ArrayList;
32 | import java.util.Base64;
33 | import java.util.List;
34 |
35 | import javax.xml.crypto.dsig.Reference;
36 | import javax.xml.parsers.DocumentBuilderFactory;
37 | import javax.xml.transform.Transformer;
38 | import javax.xml.transform.TransformerFactory;
39 | import javax.xml.transform.dom.DOMSource;
40 | import javax.xml.transform.stream.StreamResult;
41 |
42 | import static org.apache.wss4j.common.WSS4JConstants.ENC_NS;
43 | import static org.apache.wss4j.common.WSS4JConstants.KEYTRANSPORT_RSA15;
44 | import static org.apache.wss4j.common.WSS4JConstants.PASSWORD_DIGEST;
45 | import static org.apache.wss4j.common.WSS4JConstants.PASSWORD_TEXT;
46 | import static org.apache.wss4j.common.WSS4JConstants.SIG_NS;
47 | import static org.wssec.Constants.ALGORITHM;
48 | import static org.wssec.Constants.CIPHER_DATA_TAG;
49 | import static org.wssec.Constants.CIPHER_VALUE_TAG;
50 | import static org.wssec.Constants.DERIVED_KEY_DIGEST;
51 | import static org.wssec.Constants.DIGEST;
52 | import static org.wssec.Constants.EMPTY_XML_DOCUMENT_ERROR;
53 | import static org.wssec.Constants.ENCRYPTED_KEY_TAG;
54 | import static org.wssec.Constants.ENCRYPTION_METHOD_TAG;
55 | import static org.wssec.Constants.KEY_INFO_TAG;
56 | import static org.wssec.Constants.NAMESPACE_URI_ENC;
57 | import static org.wssec.Constants.SIGNATURE_METHOD_TAG;
58 | import static org.wssec.Constants.SIGNATURE_VALUE_TAG;
59 | import static org.wssec.Constants.XML_DS_NS;
60 | import static org.wssec.Constants.XML_ENC_NS;
61 |
62 | public final class WsSecurityUtils {
63 |
64 | private WsSecurityUtils() {}
65 |
66 | public static void buildSignature(RequestData reqData, WSSecSignature sign) throws Exception {
67 | List parts = new ArrayList<>(1);
68 | Document doc = reqData.getSecHeader().getSecurityHeaderElement().getOwnerDocument();
69 | parts.add(WSSecurityUtil.getDefaultEncryptionPart(doc));
70 | List referenceList = sign.addReferencesToSign(parts);
71 | sign.computeSignature(referenceList);
72 | reqData.getSignatureValues().add(sign.getSignatureValue());
73 | }
74 |
75 | public static void setSignatureValue(Document doc, byte[] signature, String algorithm) {
76 | doc.getElementsByTagName(SIGNATURE_METHOD_TAG)
77 | .item(0).getAttributes().item(0).setNodeValue(algorithm);
78 | NodeList digestValueList = doc.getElementsByTagName(SIGNATURE_VALUE_TAG);
79 | digestValueList.item(0).getFirstChild().setNodeValue(Base64.getEncoder().encodeToString(signature));
80 | }
81 |
82 | public static byte[] getSignatureValue(Document doc) {
83 | String signature = doc.getElementsByTagName(SIGNATURE_VALUE_TAG).item(0).getFirstChild().getNodeValue();
84 | return Base64.getDecoder().decode(signature);
85 | }
86 |
87 | public static void setEncryptedData(Document doc, byte[] encryptedData, String algorithm) {
88 | Element cipherDataElement = (Element) doc
89 | .getElementsByTagNameNS(NAMESPACE_URI_ENC, CIPHER_VALUE_TAG).item(0);
90 | cipherDataElement.getFirstChild().setNodeValue(Base64.getEncoder().encodeToString(encryptedData));
91 | doc.getElementsByTagName(ENCRYPTION_METHOD_TAG).item(0).getAttributes().item(0)
92 | .setNodeValue(algorithm);
93 | }
94 |
95 | public static byte[] getEncryptedData(Document document) {
96 | String encryptedText = document
97 | .getElementsByTagNameNS(NAMESPACE_URI_ENC, CIPHER_VALUE_TAG).item(0)
98 | .getFirstChild().getNodeValue();
99 | return Base64.getDecoder().decode(encryptedText);
100 | }
101 |
102 | public static Object getEncryptedKeyElement(byte[] encryptKey) throws Exception {
103 | Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
104 | Element encryptedKey = document.createElement(ENCRYPTED_KEY_TAG);
105 | encryptedKey.setAttribute(XML_ENC_NS, ENC_NS);
106 | Element encryptionMethod = document.createElement(ENCRYPTION_METHOD_TAG);
107 | encryptionMethod.setAttribute(ALGORITHM, KEYTRANSPORT_RSA15);
108 | encryptedKey.appendChild(encryptionMethod);
109 | Element keyInfo = document.createElement(KEY_INFO_TAG);
110 | keyInfo.setAttribute(XML_DS_NS, SIG_NS);
111 | encryptedKey.appendChild(keyInfo);
112 | Element cipherData = document.createElement(CIPHER_DATA_TAG);
113 | cipherData.appendChild(document.createTextNode(Base64.getEncoder().encodeToString(encryptKey)));
114 | encryptedKey.appendChild(cipherData);
115 | document.appendChild(encryptedKey);
116 | return convertDocumentToString(document);
117 | }
118 |
119 | public static void setUTChildElements(WSSecUsernameToken usernameToken, String passwordType,
120 | String username, String password) {
121 | if (DIGEST.equals(passwordType) || DERIVED_KEY_DIGEST.equals(passwordType)) {
122 | usernameToken.setPasswordType(PASSWORD_DIGEST);
123 | usernameToken.setUserInfo(username, password);
124 | usernameToken.addCreated();
125 | usernameToken.addNonce();
126 | } else {
127 | usernameToken.setPasswordType(PASSWORD_TEXT);
128 | usernameToken.setUserInfo(username, password);
129 | }
130 | }
131 |
132 | public static Object convertDocumentToString(Document document) throws Exception {
133 | if (document == null) {
134 | return ErrorCreator.createError(StringUtils.fromString(EMPTY_XML_DOCUMENT_ERROR));
135 | }
136 | Transformer transformer = TransformerFactory.newInstance().newTransformer();
137 | StringWriter writer = new StringWriter();
138 | transformer.transform(new DOMSource(document), new StreamResult(writer));
139 | return StringUtils.fromString(writer.toString());
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/ballerina/modules/soap12/README.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | This module offers a set of APIs that facilitate the transmission of XML requests to a SOAP 1.2 backend. It excels in managing security policies within SOAP requests, ensuring the transmission of secured SOAP envelopes. Moreover, it possesses the capability to efficiently extract data from security-applied SOAP responses.
4 |
5 | SOAP module abstracts out the details of the creation of a SOAP envelope, headers, and the body in a SOAP message.
6 |
7 | ## Client
8 |
9 | The `Client` is used to connect to and interact with `SOAP` 1.2 endpoints.
10 |
11 | ### SOAP 1.2 Client
12 |
13 | ```ballerina
14 | import ballerina/soap.soap12;
15 |
16 | soap12:Client soapClient = check new ("http://www.dneonline.com/calculator.asmx?WSDL");
17 | ```
18 |
19 | ## APIs associated with SOAP
20 |
21 | - **Send & Receive**: Sends SOAP request and receives a response.
22 | - **Send Only**: Fires and forgets requests. Sends the request without the possibility of any response from the service.
23 |
24 | The SOAP 1.1 specification requires the inclusion of the `action` parameter as a mandatory component within its APIs. In contrast, SOAP 1.2 relaxes this requirement, making the action parameter optional.
25 |
26 | ### Example: Send & Receive
27 |
28 | ```ballerina
29 | import ballerina/soap.soap12;
30 |
31 | public function main() returns error? {
32 | soap12:Client soapClient = check new ("http://www.dneonline.com/calculator.asmx?WSDL");
33 |
34 | xml envelope = xml `
35 |
36 |
37 | 2
38 | 3
39 |
40 |
41 | `;
42 | xml response = check soapClient->sendReceive(envelope, "http://tempuri.org/Add");
43 | }
44 | ```
45 |
46 | ### Example: Send Only
47 |
48 | ```ballerina
49 | import ballerina/soap.soap12;
50 |
51 | public function main() returns error? {
52 | soap12:Client soapClient = check new ("http://www.dneonline.com/calculator.asmx?WSDL");
53 |
54 | xml envelope = xml `
55 |
56 |
57 | 2
58 | 3
59 |
60 |
61 | `;
62 | check soapClient->sendOnly(envelope, "http://tempuri.org/Add");
63 | }
64 | ```
65 |
66 | ## Security
67 |
68 | The SOAP client module introduces a robust framework for configuring security measures in SOAP communication. Security is a critical concern when exchanging data via web services, and this module offers comprehensive options to fortify SOAP requests and responses.
69 |
70 | There are two primary security configurations available for SOAP clients:
71 |
72 | - `outboundSecurity`: This configuration applies WS-Security policies to outgoing SOAP messages. It supports multiple security options, such as Username Token, Timestamp Token, X.509 Token, Symmetric Binding, Asymmetric Binding, and Transport Binding. These can be used individually or in combination to secure the message.
73 |
74 | - `inboundSecurity`: This configuration handles the security of incoming SOAP messages. It decrypts encrypted data and verifies the digital signature to confirm the authenticity of the message.
75 |
76 |
77 | ### Policies
78 |
79 | This library currently supports the following WS Security policies:
80 |
81 | - **Username Token**: Provides authentication through username and password credentials.
82 | - **Timestamp Token**: Enhances message integrity by incorporating timestamp information.
83 | - **X509 Token**: Allows the use of X.509 certificates for secure communication.
84 | - **Symmetric Binding**: Enables symmetric key-based security mechanisms.
85 | - **Asymmetric Binding**: Facilitates the use of asymmetric cryptography for enhanced security.
86 |
87 | These policies empower SOAP clients to enhance the security of their web service communications by selecting and implementing the appropriate security mechanisms to safeguard their SOAP envelopes.
88 |
89 | ### Security Policy Configuration Types
90 |
91 | #### Outbound Security Configurations
92 |
93 | - `TimestampTokenConfig`: Represents the record for Timestamp Token policy.
94 | - Fields:
95 | - `int` timeToLive : The time to get expired
96 |
97 | - `UsernameTokenConfig`: Represents the record for Username Token policy.
98 | - Fields:
99 | - `string` username : The name of the user
100 | - `string` password : The password of the user
101 | - `PasswordType` passwordType : The password type of the username token
102 |
103 | - `SymmetricBindingConfig`: Represents the record for Symmetric Binding policy.
104 | - Fields:
105 | - `crypto:PrivateKey` symmetricKey : The key to sign and encrypt the SOAP envelope
106 | - `crypto:PublicKey` servicePublicKey : The key to encrypt the symmetric key
107 | - `SignatureAlgorithm` signatureAlgorithm : The algorithm to sign the SOAP envelope
108 | - `EncryptionAlgorithm` encryptionAlgorithm : The algorithm to encrypt the SOAP envelope
109 | - `string` x509Token : The path or token of the X509 certificate
110 |
111 | - `AsymmetricBindingConfig`: Represents the record for Asymmetric Binding policy.
112 | - Fields:
113 | - `SignatureConfig` signatureConfig : Configuration for applying digital signatures
114 | - `EncryptionConfig` encryptionConfig : Configuration for applying encryption
115 | - `string` x509Token : The path or token of the X509 certificate
116 |
117 | #### Inbound Security Configurations
118 |
119 | - `InboundSecurityConfig`: Represents the record for outbound security configurations to verify and decrypt SOAP envelopes.
120 | - Fields:
121 | - `crypto:KeyStore` decryptKeystore - The keystore to decrypt the SOAP envelope
122 | - `crypto:KeyStore` signatureKeystore - The keystore to verify the signature of the SOAP envelope
123 |
124 | ### Apply Security Policies
125 |
126 | #### SOAP 1.2 Client with Asymmetric Binding and Outbound Security Configuration
127 |
128 | ```ballerina
129 | import ballerina/crypto;
130 | import ballerina/mime;
131 | import ballerina/soap;
132 | import ballerina/soap.soap12;
133 |
134 | public function main() returns error? {
135 | soap12:Client soapClient = check new ("http://www.secured-soap-endpoint.com",
136 | {
137 | outboundSecurity: {
138 | signatureConfig: {
139 | keystore: {
140 | path: KEY_STORE_PATH_2,
141 | password: PASSWORD
142 | },
143 | privateKeyAlias: ALIAS,
144 | privateKeyPassword: PASSWORD,
145 | signatureAlgorithm: wssec:RSA_SHA1
146 | },
147 | encryptionConfig: {
148 | keystore: {
149 | path: KEY_STORE_PATH_2,
150 | password: PASSWORD
151 | },
152 | publicKeyAlias: ALIAS,
153 | encryptionAlgorithm: wssec:AES_128
154 | }
155 | },
156 | inboundSecurity: {
157 | decryptKeystore: {
158 | path: KEY_STORE_PATH_2,
159 | password: PASSWORD
160 | },
161 | signatureKeystore: {
162 | path: KEY_STORE_PATH_2,
163 | password: PASSWORD
164 | }
165 | }
166 | });
167 | }
168 | ```
169 |
--------------------------------------------------------------------------------
/ballerina/modules/wssec/tests/test_utils.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import ballerina/test;
18 | import ballerina/crypto;
19 |
20 | const USERNAME = "username";
21 | const PASSWORD = "password";
22 |
23 | const KEY_ALIAS = "wss40";
24 | const KEY_PASSWORD = "security";
25 |
26 | const SOAP_ENVELOPE_PATH = "modules/wssec/tests/resources/xml/soap_envelope.xml";
27 | const PUBLIC_KEY_PATH = "modules/wssec/tests/resources/public_key.cer";
28 | const PRIVATE_KEY_PATH = "modules/wssec/tests/resources/private_key.pem";
29 | const KEY_STORE_PATH = "modules/wssec/tests/resources/wss40.p12";
30 | const X509_PUBLIC_CERT_PATH = "modules/wssec/tests/resources/x509_certificate.crt";
31 | const X509_PUBLIC_CERT_PATH_2 = "modules/wssec/tests/resources/x509_certificate_2.crt";
32 | const X509_KEY_STORE_PATH = "modules/wssec/tests/resources/x509_certificate.p12";
33 | const X509_KEY_STORE_PATH_2 = "modules/wssec/tests/resources/x509_certificate_2.p12";
34 |
35 | const KEY_STORE_PATH_2 = "modules/wssec/tests/resources/keystore.jks";
36 | const ALIAS = "mykey";
37 |
38 | const crypto:KeyStore clientKeyStore = {
39 | path: X509_KEY_STORE_PATH_2,
40 | password: KEY_PASSWORD
41 | };
42 | crypto:PrivateKey clientPrivateKey = check crypto:decodeRsaPrivateKeyFromKeyStore(clientKeyStore, KEY_ALIAS,
43 | KEY_PASSWORD);
44 | crypto:PublicKey clientPublicKey = check crypto:decodeRsaPublicKeyFromTrustStore(clientKeyStore, KEY_ALIAS);
45 |
46 | const crypto:KeyStore serverKeyStore = {
47 | path: X509_KEY_STORE_PATH,
48 | password: KEY_PASSWORD
49 | };
50 | crypto:PrivateKey serverPrivateKey = check crypto:decodeRsaPrivateKeyFromKeyStore(serverKeyStore, KEY_ALIAS,
51 | KEY_PASSWORD);
52 | crypto:PublicKey serverPublicKey = check crypto:decodeRsaPublicKeyFromTrustStore(serverKeyStore, KEY_ALIAS);
53 |
54 | crypto:KeyStore keyStore = {
55 | path: KEY_STORE_PATH,
56 | password: KEY_PASSWORD
57 | };
58 | crypto:PrivateKey symmetricKey = check crypto:decodeRsaPrivateKeyFromKeyStore(keyStore, KEY_ALIAS, KEY_PASSWORD);
59 | crypto:PublicKey publicKey = check crypto:decodeRsaPublicKeyFromTrustStore(keyStore, KEY_ALIAS);
60 |
61 | function assertTimestampToken(string envelopeString) {
62 | string:RegExp ts_token = re ``;
63 | string:RegExp created = re `.*`;
64 | string:RegExp expires = re `.*`;
65 | test:assertTrue(envelopeString.includesMatch(ts_token));
66 | test:assertTrue(envelopeString.includesMatch(created));
67 | test:assertTrue(envelopeString.includesMatch(expires));
68 | }
69 |
70 | function assertUsernameToken(string envelopeString, PasswordType passwordType) {
71 | string:RegExp usernameTokenTag = re `.*`;
72 | string:RegExp usernameTag = re `${USERNAME}`;
73 | test:assertTrue(envelopeString.includesMatch(usernameTokenTag));
74 | test:assertTrue(envelopeString.includesMatch(usernameTag));
75 | match passwordType {
76 | TEXT => {
77 | string:RegExp passwordTag = re `${PASSWORD}`;
78 | test:assertTrue(envelopeString.includesMatch(passwordTag));
79 | }
80 | DIGEST => {
81 | string:RegExp passwordTag = re `.*`;
82 | string:RegExp nonce = re `.*`;
83 | string:RegExp created = re `.*`;
84 | test:assertTrue(envelopeString.includesMatch(passwordTag));
85 | test:assertTrue(envelopeString.includesMatch(nonce));
86 | test:assertTrue(envelopeString.includesMatch(created));
87 | }
88 | _ => {
89 | string:RegExp salt = re `.*`;
90 | string:RegExp iteration = re `.*`;
91 | test:assertTrue(envelopeString.includesMatch(salt));
92 | test:assertTrue(envelopeString.includesMatch(iteration));
93 | }
94 | }
95 | }
96 |
97 | function assertSignatureWithX509(string securedEnvelope) {
98 | string:RegExp keyIdentifier = re `.*`;
99 | test:assertTrue(securedEnvelope.includesMatch(keyIdentifier));
100 | assertSignatureWithoutX509(securedEnvelope);
101 | }
102 |
103 | function assertSignatureWithoutX509(string securedEnvelope) {
104 | string:RegExp signature = re ``;
105 | string:RegExp signatureInfo = re ``;
106 | string:RegExp canonicalizationMethod = re ``;
107 | string:RegExp signatureMethod = re ``;
108 | string:RegExp transformMethod = re ``;
109 | string:RegExp digestMethod = re ``;
110 | string:RegExp digestValue = re `ds:DigestValue>`;
111 | string:RegExp signatureValue = re ``;
112 |
113 | test:assertTrue(securedEnvelope.includesMatch(signature));
114 | test:assertTrue(securedEnvelope.includesMatch(signatureInfo));
115 | test:assertTrue(securedEnvelope.includesMatch(canonicalizationMethod));
116 | test:assertTrue(securedEnvelope.includesMatch(signatureMethod));
117 | test:assertTrue(securedEnvelope.includesMatch(transformMethod));
118 | test:assertTrue(securedEnvelope.includesMatch(digestMethod));
119 | test:assertTrue(securedEnvelope.includesMatch(digestValue));
120 | test:assertTrue(securedEnvelope.includesMatch(signatureValue));
121 | }
122 |
123 | function assertEncryptedSymmetricKey(string securedEnvelope) {
124 | string:RegExp encryptedKey = re ``;
125 | string:RegExp encryptionMethod = re ``;
126 | string:RegExp cipherData = re ``;
127 |
128 | test:assertTrue(securedEnvelope.includesMatch(encryptedKey));
129 | test:assertTrue(securedEnvelope.includesMatch(encryptionMethod));
130 | test:assertTrue(securedEnvelope.includesMatch(cipherData));
131 | }
132 |
133 | function assertEncryptedPart(string securedEnvelope) {
134 | string:RegExp encryptedData = re ``;
136 | string:RegExp cipherData = re ``;
137 | string:RegExp cipherValue = re ``;
138 |
139 | test:assertTrue(securedEnvelope.includesMatch(encryptedData));
140 | test:assertTrue(securedEnvelope.includesMatch(encMethod));
141 | test:assertTrue(securedEnvelope.includesMatch(cipherData));
142 | test:assertTrue(securedEnvelope.includesMatch(cipherValue));
143 | }
144 |
--------------------------------------------------------------------------------
/ballerina/modules/soap11/README.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | This module offers a set of APIs that facilitate the transmission of XML requests to a SOAP 1.1 backend. It excels in managing security policies within SOAP requests, ensuring the transmission of secured SOAP envelopes. Moreover, it possesses the capability to efficiently extract data from security-applied SOAP responses.
4 |
5 | SOAP module abstracts out the details of the creation of a SOAP envelope, headers, and the body in a SOAP message.
6 |
7 | ## Client
8 |
9 | The `Client` is used to connect to and interact with `SOAP` 1.1 endpoints.
10 |
11 | ### SOAP 1.1 Client
12 |
13 | ```ballerina
14 | import ballerina/soap.soap11;
15 |
16 | soap11:Client soapClient = check new ("http://www.dneonline.com/calculator.asmx?WSDL");
17 | ```
18 |
19 | ## APIs associated with SOAP
20 |
21 | - **Send & Receive**: Sends SOAP request and receives a response.
22 | - **Send Only**: Fires and forgets requests. Sends the request without the possibility of any response from the service.
23 |
24 | The SOAP 1.1 specification requires the inclusion of the `action` parameter as a mandatory component within its APIs. In contrast, SOAP 1.2 relaxes this requirement, making the action parameter optional.
25 |
26 | ### Example: Send & Receive
27 |
28 | ```ballerina
29 | import ballerina/soap.soap11;
30 |
31 | public function main() returns error? {
32 | soap11:Client soapClient = check new ("http://www.dneonline.com/calculator.asmx?WSDL");
33 |
34 | xml envelope = xml `
35 |
36 |
37 | 2
38 | 3
39 |
40 |
41 | `;
42 | xml response = check soapClient->sendReceive(envelope, "http://tempuri.org/Add");
43 | }
44 | ```
45 |
46 | ### Example: Send Only
47 |
48 | ```ballerina
49 | import ballerina/soap.soap11;
50 |
51 | public function main() returns error? {
52 | soap11:Client soapClient = check new ("http://www.dneonline.com/calculator.asmx?WSDL");
53 |
54 | xml envelope = xml `
55 |
56 |
57 | 2
58 | 3
59 |
60 |
61 | `;
62 | check soapClient->sendOnly(envelope, "http://tempuri.org/Add");
63 | }
64 | ```
65 |
66 | ## Security
67 |
68 | The SOAP client module introduces a robust framework for configuring security measures in SOAP communication. Security is a critical concern when exchanging data via web services, and this module offers comprehensive options to fortify SOAP requests and responses.
69 |
70 | There are two primary security configurations available for SOAP clients:
71 |
72 | - `outboundSecurity`: This configuration applies WS-Security policies to outgoing SOAP messages. It supports multiple security options, such as Username Token, Timestamp Token, X.509 Token, Symmetric Binding, Asymmetric Binding, and Transport Binding. These can be used individually or in combination to secure the message.
73 |
74 | - `inboundSecurity`: This configuration handles the security of incoming SOAP messages. It decrypts encrypted data and verifies the digital signature to confirm the authenticity of the message.
75 |
76 | ### Policies
77 |
78 | This library currently supports the following WS Security policies:
79 |
80 | - **Username Token**: Provides authentication through username and password credentials.
81 | - **Timestamp Token**: Enhances message integrity by incorporating timestamp information.
82 | - **X509 Token**: Allows the use of X.509 certificates for secure communication.
83 | - **Symmetric Binding**: Enables symmetric key-based security mechanisms.
84 | - **Asymmetric Binding**: Facilitates the use of asymmetric cryptography for enhanced security.
85 |
86 | These policies empower SOAP clients to enhance the security of their web service communications by selecting and implementing the appropriate security mechanisms to safeguard their SOAP envelopes.
87 |
88 | ### Security Policy Configuration Types
89 |
90 | #### Outbound Security Configurations
91 |
92 | - `TimestampTokenConfig`: Represents the record for Timestamp Token policy.
93 | - Fields:
94 | - `int` timeToLive : The time to get expired
95 |
96 | - `UsernameTokenConfig`: Represents the record for Username Token policy.
97 | - Fields:
98 | - `string` username : The name of the user
99 | - `string` password : The password of the user
100 | - `PasswordType` passwordType : The password type of the username token
101 |
102 | - `SymmetricBindingConfig`: Represents the record for Symmetric Binding policy.
103 | - Fields:
104 | - `crypto:PrivateKey` symmetricKey : The key to sign and encrypt the SOAP envelope
105 | - `crypto:PublicKey` servicePublicKey : The key to encrypt the symmetric key
106 | - `SignatureAlgorithm` signatureAlgorithm : The algorithm to sign the SOAP envelope
107 | - `EncryptionAlgorithm` encryptionAlgorithm : The algorithm to encrypt the SOAP envelope
108 | - `string` x509Token : The path or token of the X509 certificate
109 |
110 | - `AsymmetricBindingConfig`: Represents the record for Asymmetric Binding policy.
111 | - Fields:
112 | - `SignatureConfig` signatureConfig : Configuration for applying digital signatures
113 | - `EncryptionConfig` encryptionConfig : Configuration for applying encryption
114 | - `string` x509Token : The path or token of the X509 certificate
115 |
116 | #### Inbound Security Configurations
117 |
118 | - `InboundSecurityConfig`: Represents the record for outbound security configurations to verify and decrypt SOAP envelopes.
119 | - Fields:
120 | - `crypto:KeyStore` decryptKeystore - The keystore to decrypt the SOAP envelope
121 | - `crypto:KeyStore` signatureKeystore - The keystore to verify the signature of the SOAP envelope
122 |
123 | ### Apply Security Policies
124 |
125 | #### SOAP 1.1 Client with Asymmetric Binding and Outbound Security Configuration
126 |
127 | ```ballerina
128 | import ballerina/crypto;
129 | import ballerina/mime;
130 | import ballerina/soap;
131 | import ballerina/soap.soap11;
132 |
133 | public function main() returns error? {
134 | crypto:PrivateKey clientPrivateKey = ...//
135 | crypto:PublicKey clientPublicKey = ...//
136 | crypto:PublicKey serverPublicKey = ...//
137 |
138 | soap11:Client soapClient = check new ("http://www.secured-soap-endpoint.com",
139 | {
140 | outboundSecurity: {
141 | signatureConfig: {
142 | keystore: {
143 | path: KEY_STORE_PATH_2,
144 | password: PASSWORD
145 | },
146 | privateKeyAlias: ALIAS,
147 | privateKeyPassword: PASSWORD,
148 | signatureAlgorithm: wssec:RSA_SHA1
149 | },
150 | encryptionConfig: {
151 | keystore: {
152 | path: KEY_STORE_PATH_2,
153 | password: PASSWORD
154 | },
155 | publicKeyAlias: ALIAS,
156 | encryptionAlgorithm: wssec:AES_128
157 | }
158 | },
159 | inboundSecurity: {
160 | decryptKeystore: {
161 | path: KEY_STORE_PATH_2,
162 | password: PASSWORD
163 | },
164 | signatureKeystore: {
165 | path: KEY_STORE_PATH_2,
166 | password: PASSWORD
167 | }
168 | }
169 | });
170 | }
171 | ```
172 |
--------------------------------------------------------------------------------
/ballerina/Dependencies.toml:
--------------------------------------------------------------------------------
1 | # AUTO-GENERATED FILE. DO NOT MODIFY.
2 |
3 | # This file is auto-generated by Ballerina for managing dependency versions.
4 | # It should not be modified by hand.
5 |
6 | [ballerina]
7 | dependencies-toml-version = "2"
8 | distribution-version = "2201.12.0"
9 |
10 | [[package]]
11 | org = "ballerina"
12 | name = "auth"
13 | version = "2.14.0"
14 | dependencies = [
15 | {org = "ballerina", name = "crypto"},
16 | {org = "ballerina", name = "jballerina.java"},
17 | {org = "ballerina", name = "lang.array"},
18 | {org = "ballerina", name = "lang.string"},
19 | {org = "ballerina", name = "log"}
20 | ]
21 |
22 | [[package]]
23 | org = "ballerina"
24 | name = "cache"
25 | version = "3.10.0"
26 | dependencies = [
27 | {org = "ballerina", name = "constraint"},
28 | {org = "ballerina", name = "jballerina.java"},
29 | {org = "ballerina", name = "task"},
30 | {org = "ballerina", name = "time"}
31 | ]
32 |
33 | [[package]]
34 | org = "ballerina"
35 | name = "constraint"
36 | version = "1.7.0"
37 | dependencies = [
38 | {org = "ballerina", name = "jballerina.java"}
39 | ]
40 |
41 | [[package]]
42 | org = "ballerina"
43 | name = "crypto"
44 | version = "2.9.0"
45 | dependencies = [
46 | {org = "ballerina", name = "jballerina.java"},
47 | {org = "ballerina", name = "time"}
48 | ]
49 | modules = [
50 | {org = "ballerina", packageName = "crypto", moduleName = "crypto"}
51 | ]
52 |
53 | [[package]]
54 | org = "ballerina"
55 | name = "data.jsondata"
56 | version = "1.1.0"
57 | dependencies = [
58 | {org = "ballerina", name = "jballerina.java"},
59 | {org = "ballerina", name = "lang.object"}
60 | ]
61 |
62 | [[package]]
63 | org = "ballerina"
64 | name = "file"
65 | version = "1.12.0"
66 | dependencies = [
67 | {org = "ballerina", name = "io"},
68 | {org = "ballerina", name = "jballerina.java"},
69 | {org = "ballerina", name = "os"},
70 | {org = "ballerina", name = "time"}
71 | ]
72 |
73 | [[package]]
74 | org = "ballerina"
75 | name = "http"
76 | version = "2.14.0"
77 | dependencies = [
78 | {org = "ballerina", name = "auth"},
79 | {org = "ballerina", name = "cache"},
80 | {org = "ballerina", name = "constraint"},
81 | {org = "ballerina", name = "crypto"},
82 | {org = "ballerina", name = "data.jsondata"},
83 | {org = "ballerina", name = "file"},
84 | {org = "ballerina", name = "io"},
85 | {org = "ballerina", name = "jballerina.java"},
86 | {org = "ballerina", name = "jwt"},
87 | {org = "ballerina", name = "lang.array"},
88 | {org = "ballerina", name = "lang.decimal"},
89 | {org = "ballerina", name = "lang.int"},
90 | {org = "ballerina", name = "lang.regexp"},
91 | {org = "ballerina", name = "lang.runtime"},
92 | {org = "ballerina", name = "lang.string"},
93 | {org = "ballerina", name = "lang.value"},
94 | {org = "ballerina", name = "log"},
95 | {org = "ballerina", name = "mime"},
96 | {org = "ballerina", name = "oauth2"},
97 | {org = "ballerina", name = "observe"},
98 | {org = "ballerina", name = "time"},
99 | {org = "ballerina", name = "url"}
100 | ]
101 | modules = [
102 | {org = "ballerina", packageName = "http", moduleName = "http"},
103 | {org = "ballerina", packageName = "http", moduleName = "http.httpscerr"}
104 | ]
105 |
106 | [[package]]
107 | org = "ballerina"
108 | name = "io"
109 | version = "1.8.0"
110 | dependencies = [
111 | {org = "ballerina", name = "jballerina.java"},
112 | {org = "ballerina", name = "lang.value"}
113 | ]
114 | modules = [
115 | {org = "ballerina", packageName = "io", moduleName = "io"}
116 | ]
117 |
118 | [[package]]
119 | org = "ballerina"
120 | name = "jballerina.java"
121 | version = "0.0.0"
122 | modules = [
123 | {org = "ballerina", packageName = "jballerina.java", moduleName = "jballerina.java"}
124 | ]
125 |
126 | [[package]]
127 | org = "ballerina"
128 | name = "jwt"
129 | version = "2.15.0"
130 | dependencies = [
131 | {org = "ballerina", name = "cache"},
132 | {org = "ballerina", name = "crypto"},
133 | {org = "ballerina", name = "io"},
134 | {org = "ballerina", name = "jballerina.java"},
135 | {org = "ballerina", name = "lang.int"},
136 | {org = "ballerina", name = "lang.string"},
137 | {org = "ballerina", name = "log"},
138 | {org = "ballerina", name = "time"}
139 | ]
140 |
141 | [[package]]
142 | org = "ballerina"
143 | name = "lang.__internal"
144 | version = "0.0.0"
145 | dependencies = [
146 | {org = "ballerina", name = "jballerina.java"},
147 | {org = "ballerina", name = "lang.object"}
148 | ]
149 |
150 | [[package]]
151 | org = "ballerina"
152 | name = "lang.array"
153 | version = "0.0.0"
154 | dependencies = [
155 | {org = "ballerina", name = "jballerina.java"},
156 | {org = "ballerina", name = "lang.__internal"}
157 | ]
158 |
159 | [[package]]
160 | org = "ballerina"
161 | name = "lang.decimal"
162 | version = "0.0.0"
163 | dependencies = [
164 | {org = "ballerina", name = "jballerina.java"}
165 | ]
166 |
167 | [[package]]
168 | org = "ballerina"
169 | name = "lang.error"
170 | version = "0.0.0"
171 | dependencies = [
172 | {org = "ballerina", name = "jballerina.java"}
173 | ]
174 |
175 | [[package]]
176 | org = "ballerina"
177 | name = "lang.int"
178 | version = "0.0.0"
179 | dependencies = [
180 | {org = "ballerina", name = "jballerina.java"},
181 | {org = "ballerina", name = "lang.__internal"},
182 | {org = "ballerina", name = "lang.object"}
183 | ]
184 |
185 | [[package]]
186 | org = "ballerina"
187 | name = "lang.object"
188 | version = "0.0.0"
189 |
190 | [[package]]
191 | org = "ballerina"
192 | name = "lang.regexp"
193 | version = "0.0.0"
194 | dependencies = [
195 | {org = "ballerina", name = "jballerina.java"}
196 | ]
197 | modules = [
198 | {org = "ballerina", packageName = "lang.regexp", moduleName = "lang.regexp"}
199 | ]
200 |
201 | [[package]]
202 | org = "ballerina"
203 | name = "lang.runtime"
204 | version = "0.0.0"
205 | dependencies = [
206 | {org = "ballerina", name = "jballerina.java"}
207 | ]
208 |
209 | [[package]]
210 | org = "ballerina"
211 | name = "lang.string"
212 | version = "0.0.0"
213 | dependencies = [
214 | {org = "ballerina", name = "jballerina.java"},
215 | {org = "ballerina", name = "lang.regexp"}
216 | ]
217 |
218 | [[package]]
219 | org = "ballerina"
220 | name = "lang.value"
221 | version = "0.0.0"
222 | dependencies = [
223 | {org = "ballerina", name = "jballerina.java"}
224 | ]
225 |
226 | [[package]]
227 | org = "ballerina"
228 | name = "log"
229 | version = "2.12.0"
230 | dependencies = [
231 | {org = "ballerina", name = "io"},
232 | {org = "ballerina", name = "jballerina.java"},
233 | {org = "ballerina", name = "lang.value"},
234 | {org = "ballerina", name = "observe"}
235 | ]
236 |
237 | [[package]]
238 | org = "ballerina"
239 | name = "mime"
240 | version = "2.12.0"
241 | dependencies = [
242 | {org = "ballerina", name = "io"},
243 | {org = "ballerina", name = "jballerina.java"},
244 | {org = "ballerina", name = "lang.int"},
245 | {org = "ballerina", name = "log"}
246 | ]
247 | modules = [
248 | {org = "ballerina", packageName = "mime", moduleName = "mime"}
249 | ]
250 |
251 | [[package]]
252 | org = "ballerina"
253 | name = "oauth2"
254 | version = "2.14.0"
255 | dependencies = [
256 | {org = "ballerina", name = "cache"},
257 | {org = "ballerina", name = "crypto"},
258 | {org = "ballerina", name = "jballerina.java"},
259 | {org = "ballerina", name = "log"},
260 | {org = "ballerina", name = "time"},
261 | {org = "ballerina", name = "url"}
262 | ]
263 |
264 | [[package]]
265 | org = "ballerina"
266 | name = "observe"
267 | version = "1.5.0"
268 | dependencies = [
269 | {org = "ballerina", name = "jballerina.java"}
270 | ]
271 |
272 | [[package]]
273 | org = "ballerina"
274 | name = "os"
275 | version = "1.10.0"
276 | dependencies = [
277 | {org = "ballerina", name = "io"},
278 | {org = "ballerina", name = "jballerina.java"}
279 | ]
280 |
281 | [[package]]
282 | org = "ballerina"
283 | name = "soap"
284 | version = "2.3.0"
285 | dependencies = [
286 | {org = "ballerina", name = "crypto"},
287 | {org = "ballerina", name = "http"},
288 | {org = "ballerina", name = "io"},
289 | {org = "ballerina", name = "jballerina.java"},
290 | {org = "ballerina", name = "lang.regexp"},
291 | {org = "ballerina", name = "mime"},
292 | {org = "ballerina", name = "test"},
293 | {org = "ballerinai", name = "observe"}
294 | ]
295 | modules = [
296 | {org = "ballerina", packageName = "soap", moduleName = "soap"},
297 | {org = "ballerina", packageName = "soap", moduleName = "soap.soap11"},
298 | {org = "ballerina", packageName = "soap", moduleName = "soap.soap12"},
299 | {org = "ballerina", packageName = "soap", moduleName = "soap.wssec"}
300 | ]
301 |
302 | [[package]]
303 | org = "ballerina"
304 | name = "task"
305 | version = "2.7.0"
306 | dependencies = [
307 | {org = "ballerina", name = "jballerina.java"},
308 | {org = "ballerina", name = "time"}
309 | ]
310 |
311 | [[package]]
312 | org = "ballerina"
313 | name = "test"
314 | version = "0.0.0"
315 | dependencies = [
316 | {org = "ballerina", name = "jballerina.java"},
317 | {org = "ballerina", name = "lang.array"},
318 | {org = "ballerina", name = "lang.error"}
319 | ]
320 | modules = [
321 | {org = "ballerina", packageName = "test", moduleName = "test"}
322 | ]
323 |
324 | [[package]]
325 | org = "ballerina"
326 | name = "time"
327 | version = "2.7.0"
328 | dependencies = [
329 | {org = "ballerina", name = "jballerina.java"}
330 | ]
331 |
332 | [[package]]
333 | org = "ballerina"
334 | name = "url"
335 | version = "2.6.0"
336 | dependencies = [
337 | {org = "ballerina", name = "jballerina.java"}
338 | ]
339 |
340 | [[package]]
341 | org = "ballerinai"
342 | name = "observe"
343 | version = "0.0.0"
344 | dependencies = [
345 | {org = "ballerina", name = "jballerina.java"},
346 | {org = "ballerina", name = "observe"}
347 | ]
348 | modules = [
349 | {org = "ballerinai", packageName = "observe", moduleName = "observe"}
350 | ]
351 |
352 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | #
21 | # Gradle start up script for POSIX generated by Gradle.
22 | #
23 | # Important for running:
24 | #
25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
26 | # noncompliant, but you have some other compliant shell such as ksh or
27 | # bash, then to run this script, type that shell name before the whole
28 | # command line, like:
29 | #
30 | # ksh Gradle
31 | #
32 | # Busybox and similar reduced shells will NOT work, because this script
33 | # requires all of these POSIX shell features:
34 | # * functions;
35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
37 | # * compound commands having a testable exit status, especially «case»;
38 | # * various built-in commands including «command», «set», and «ulimit».
39 | #
40 | # Important for patching:
41 | #
42 | # (2) This script targets any POSIX shell, so it avoids extensions provided
43 | # by Bash, Ksh, etc; in particular arrays are avoided.
44 | #
45 | # The "traditional" practice of packing multiple parameters into a
46 | # space-separated string is a well documented source of bugs and security
47 | # problems, so this is (mostly) avoided, by progressively accumulating
48 | # options in "$@", and eventually passing that to Java.
49 | #
50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
52 | # see the in-line comments for details.
53 | #
54 | # There are tweaks for specific operating systems such as AIX, CygWin,
55 | # Darwin, MinGW, and NonStop.
56 | #
57 | # (3) This script is generated from the Groovy template
58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
59 | # within the Gradle project.
60 | #
61 | # You can find Gradle at https://github.com/gradle/gradle/.
62 | #
63 | ##############################################################################
64 |
65 | # Attempt to set APP_HOME
66 |
67 | # Resolve links: $0 may be a link
68 | app_path=$0
69 |
70 | # Need this for daisy-chained symlinks.
71 | while
72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
73 | [ -h "$app_path" ]
74 | do
75 | ls=$( ls -ld "$app_path" )
76 | link=${ls#*' -> '}
77 | case $link in #(
78 | /*) app_path=$link ;; #(
79 | *) app_path=$APP_HOME$link ;;
80 | esac
81 | done
82 |
83 | # This is normally unused
84 | # shellcheck disable=SC2034
85 | APP_BASE_NAME=${0##*/}
86 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
87 | APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
88 |
89 | # Use the maximum available, or set MAX_FD != -1 to use that value.
90 | MAX_FD=maximum
91 |
92 | warn () {
93 | echo "$*"
94 | } >&2
95 |
96 | die () {
97 | echo
98 | echo "$*"
99 | echo
100 | exit 1
101 | } >&2
102 |
103 | # OS specific support (must be 'true' or 'false').
104 | cygwin=false
105 | msys=false
106 | darwin=false
107 | nonstop=false
108 | case "$( uname )" in #(
109 | CYGWIN* ) cygwin=true ;; #(
110 | Darwin* ) darwin=true ;; #(
111 | MSYS* | MINGW* ) msys=true ;; #(
112 | NONSTOP* ) nonstop=true ;;
113 | esac
114 |
115 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
116 |
117 |
118 | # Determine the Java command to use to start the JVM.
119 | if [ -n "$JAVA_HOME" ] ; then
120 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
121 | # IBM's JDK on AIX uses strange locations for the executables
122 | JAVACMD=$JAVA_HOME/jre/sh/java
123 | else
124 | JAVACMD=$JAVA_HOME/bin/java
125 | fi
126 | if [ ! -x "$JAVACMD" ] ; then
127 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
128 |
129 | Please set the JAVA_HOME variable in your environment to match the
130 | location of your Java installation."
131 | fi
132 | else
133 | JAVACMD=java
134 | if ! command -v java >/dev/null 2>&1
135 | then
136 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
137 |
138 | Please set the JAVA_HOME variable in your environment to match the
139 | location of your Java installation."
140 | fi
141 | fi
142 |
143 | # Increase the maximum file descriptors if we can.
144 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
145 | case $MAX_FD in #(
146 | max*)
147 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
148 | # shellcheck disable=SC3045
149 | MAX_FD=$( ulimit -H -n ) ||
150 | warn "Could not query maximum file descriptor limit"
151 | esac
152 | case $MAX_FD in #(
153 | '' | soft) :;; #(
154 | *)
155 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
156 | # shellcheck disable=SC3045
157 | ulimit -n "$MAX_FD" ||
158 | warn "Could not set maximum file descriptor limit to $MAX_FD"
159 | esac
160 | fi
161 |
162 | # Collect all arguments for the java command, stacking in reverse order:
163 | # * args from the command line
164 | # * the main class name
165 | # * -classpath
166 | # * -D...appname settings
167 | # * --module-path (only if needed)
168 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
169 |
170 | # For Cygwin or MSYS, switch paths to Windows format before running java
171 | if "$cygwin" || "$msys" ; then
172 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
173 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
174 |
175 | JAVACMD=$( cygpath --unix "$JAVACMD" )
176 |
177 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
178 | for arg do
179 | if
180 | case $arg in #(
181 | -*) false ;; # don't mess with options #(
182 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
183 | [ -e "$t" ] ;; #(
184 | *) false ;;
185 | esac
186 | then
187 | arg=$( cygpath --path --ignore --mixed "$arg" )
188 | fi
189 | # Roll the args list around exactly as many times as the number of
190 | # args, so each arg winds up back in the position where it started, but
191 | # possibly modified.
192 | #
193 | # NB: a `for` loop captures its iteration list before it begins, so
194 | # changing the positional parameters here affects neither the number of
195 | # iterations, nor the values presented in `arg`.
196 | shift # remove old arg
197 | set -- "$@" "$arg" # push replacement arg
198 | done
199 | fi
200 |
201 |
202 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
203 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
204 |
205 | # Collect all arguments for the java command;
206 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
207 | # shell script including quotes and variable substitutions, so put them in
208 | # double quotes to make sure that they get re-expanded; and
209 | # * put everything else in single quotes, so that it's not re-expanded.
210 |
211 | set -- \
212 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
213 | -classpath "$CLASSPATH" \
214 | org.gradle.wrapper.GradleWrapperMain \
215 | "$@"
216 |
217 | # Stop when "xargs" is not available.
218 | if ! command -v xargs >/dev/null 2>&1
219 | then
220 | die "xargs is not available"
221 | fi
222 |
223 | # Use "xargs" to parse quoted args.
224 | #
225 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
226 | #
227 | # In Bash we could simply go:
228 | #
229 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
230 | # set -- "${ARGS[@]}" "$@"
231 | #
232 | # but POSIX shell has neither arrays nor command substitution, so instead we
233 | # post-process each arg (as a line of input to sed) to backslash-escape any
234 | # character that might be a shell metacharacter, then use eval to reverse
235 | # that process (while maintaining the separation between arguments), and wrap
236 | # the whole thing up as a single "set" statement.
237 | #
238 | # This will of course break if any of these variables contains a newline or
239 | # an unmatched quote.
240 | #
241 |
242 | eval "set -- $(
243 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
244 | xargs -n1 |
245 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
246 | tr '\n' ' '
247 | )" '"$@"'
248 |
249 | exec "$JAVACMD" "$@"
250 |
--------------------------------------------------------------------------------
/ballerina/README.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | This module offers a set of APIs that facilitate the transmission of XML requests to a SOAP backend. It excels in managing security policies within SOAP requests, ensuring the transmission of secured SOAP envelopes. Moreover, it possesses the capability to efficiently extract data from security-applied SOAP responses.
4 |
5 | SOAP module abstracts out the details of the creation of a SOAP envelope, headers, and the body in a SOAP message.
6 |
7 | ## Client
8 |
9 | The `Client` is used to connect to and interact with `SOAP` endpoints.
10 |
11 | ### SOAP 1.1 Client
12 |
13 | ```ballerina
14 | import ballerina/soap.soap11;
15 |
16 | soap11:Client soapClient = check new ("http://www.dneonline.com/calculator.asmx?WSDL");
17 | ```
18 |
19 | ### SOAP 1.2 Client
20 |
21 | ```ballerina
22 | import ballerina/soap.soap12;
23 |
24 | soap12:Client soapClient = check new ("http://www.dneonline.com/calculator.asmx?WSDL");
25 | ```
26 |
27 | ## APIs associated with SOAP
28 |
29 | - **Send & Receive**: Sends SOAP request and receives a response.
30 | - **Send Only**: Fires and forgets requests. Sends the request without the possibility of any response from the service.
31 |
32 | The SOAP 1.1 specification requires the inclusion of the `action` parameter as a mandatory component within its APIs. In contrast, SOAP 1.2 relaxes this requirement, making the action parameter optional.
33 |
34 | ### Example: Send & Receive
35 |
36 | ```ballerina
37 | import ballerina/soap.soap11;
38 |
39 | public function main() returns error? {
40 | soap11:Client soapClient = check new ("http://www.dneonline.com/calculator.asmx?WSDL");
41 |
42 | xml envelope = xml `
43 |
44 |
45 | 2
46 | 3
47 |
48 |
49 | `;
50 | xml response = check soapClient->sendReceive(envelope, "http://tempuri.org/Add");
51 | }
52 | ```
53 |
54 | ### Example: Send Only
55 |
56 | ```ballerina
57 | import ballerina/soap.soap11;
58 |
59 | public function main() returns error? {
60 | soap11:Client soapClient = check new ("http://www.dneonline.com/calculator.asmx?WSDL");
61 |
62 | xml envelope = xml `
63 |
64 |
65 | 2
66 | 3
67 |
68 |
69 | `;
70 | check soapClient->sendOnly(envelope, "http://tempuri.org/Add");
71 | }
72 | ```
73 |
74 | ## Security
75 |
76 | The SOAP client module introduces a robust framework for configuring security measures in SOAP communication. Security is a critical concern when exchanging data via web services, and this module offers comprehensive options to fortify SOAP requests and responses.
77 |
78 | There are two primary security configurations available for SOAP clients:
79 |
80 | - `outboundSecurity`: This configuration applies WS-Security policies to outgoing SOAP messages. It supports multiple security options, such as Username Token, Timestamp Token, X.509 Token, Symmetric Binding, Asymmetric Binding, and Transport Binding. These can be used individually or in combination to secure the message.
81 |
82 | - `inboundSecurity`: This configuration handles the security of incoming SOAP messages. It decrypts encrypted data and verifies the digital signature to confirm the authenticity of the message.
83 |
84 | ### Policies
85 |
86 | This library currently supports the following WS Security policies:
87 |
88 | - **Username Token**: Provides authentication through username and password credentials.
89 | - **Timestamp Token**: Enhances message integrity by incorporating timestamp information.
90 | - **X509 Token**: Allows the use of X.509 certificates for secure communication.
91 | - **Symmetric Binding**: Enables symmetric key-based security mechanisms.
92 | - **Asymmetric Binding**: Facilitates the use of asymmetric cryptography for enhanced security.
93 |
94 | These policies empower SOAP clients to enhance the security of their web service communications by selecting and implementing the appropriate security mechanisms to safeguard their SOAP envelopes.
95 |
96 | ### Security Policy Configuration Types
97 |
98 | #### Outbound Security Configurations
99 |
100 | - `TimestampTokenConfig`: Represents the record for Timestamp Token policy.
101 | - Fields:
102 | - `int` timeToLive : The time to get expired
103 |
104 | - `UsernameTokenConfig`: Represents the record for Username Token policy.
105 | - Fields:
106 | - `string` username : The name of the user
107 | - `string` password : The password of the user
108 | - `PasswordType` passwordType : The password type of the username token
109 |
110 | - `SymmetricBindingConfig`: Represents the record for Symmetric Binding policy.
111 | - Fields:
112 | - `crypto:PrivateKey` symmetricKey : The key to sign and encrypt the SOAP envelope
113 | - `crypto:PublicKey` servicePublicKey : The key to encrypt the symmetric key
114 | - `SignatureAlgorithm` signatureAlgorithm : The algorithm to sign the SOAP envelope
115 | - `EncryptionAlgorithm` encryptionAlgorithm : The algorithm to encrypt the SOAP envelope
116 | - `string` x509Token : The path or token of the X509 certificate
117 |
118 | - `AsymmetricBindingConfig`: Represents the record for Asymmetric Binding policy.
119 | - Fields:
120 | - `SignatureConfig` signatureConfig : Configuration for applying digital signatures
121 | - `EncryptionConfig` encryptionConfig : Configuration for applying encryption
122 | - `string` x509Token : The path or token of the X509 certificate
123 |
124 | #### Inbound Security Configurations
125 |
126 | - `InboundSecurityConfig`: Represents the record for outbound security configurations to verify and decrypt SOAP envelopes.
127 | - Fields:
128 | - `crypto:KeyStore` decryptKeystore - The keystore to decrypt the SOAP envelope
129 | - `crypto:KeyStore` signatureKeystore - The keystore to verify the signature of the SOAP envelope
130 |
131 | ### Apply Security Policies
132 |
133 | #### SOAP 1.1 Client: UsernameToken and TranportBinding Policy
134 |
135 | ```ballerina
136 | import ballerina/crypto;
137 | import ballerina/mime;
138 | import ballerina/soap;
139 | import ballerina/soap.soap11;
140 |
141 | public function main() returns error? {
142 | soap11:Client soapClient = check new ("https://www.secured-soap-endpoint.com",
143 | {
144 | outboundSecurity: [
145 | {
146 | username: "username",
147 | password: "password",
148 | passwordType: soap:TEXT
149 | },
150 | TRANSPORT_BINDING
151 | ]
152 | });
153 |
154 | xml envelope = xml `
155 |
156 |
157 | 2
158 | 3
159 |
160 |
161 | `;
162 | xml response = check soapClient->sendReceive(envelope, "http://tempuri.org/Add");
163 | }
164 | ```
165 |
166 | #### SOAP 1.2 Client with Asymmetric Binding and Outbound Security Configuration
167 |
168 | ```ballerina
169 | import ballerina/crypto;
170 | import ballerina/mime;
171 | import ballerina/soap;
172 | import ballerina/soap.soap12;
173 |
174 | public function main() returns error? {
175 | configurable crypto:PrivateKey clientPrivateKey = ?;
176 | configurable crypto:PublicKey clientPublicKey = ?;
177 | configurable crypto:PublicKey serverPublicKey = ?;
178 |
179 | soap12:Client soapClient = check new ("https://www.secured-soap-endpoint.com",
180 | {
181 | outboundSecurity: {
182 | signatureConfig: {
183 | keystore: {
184 | path: KEY_STORE_PATH,
185 | password: PASSWORD
186 | },
187 | privateKeyAlias: ALIAS,
188 | privateKeyPassword: PASSWORD,
189 | canonicalizationAlgorithm: wssec:C14N_EXCL_OMIT_COMMENTS,
190 | digestAlgorithm: wssec:SHA1
191 | },
192 | encryptionConfig: {
193 | keystore: {
194 | path: KEY_STORE_PATH_2,
195 | password: PASSWORD
196 | },
197 | publicKeyAlias: ALIAS,
198 | encryptionAlgorithm: wssec:AES_128
199 | }
200 | },
201 | inboundSecurity: {
202 | decryptKeystore: {
203 | path: KEY_STORE_PATH_2,
204 | password: PASSWORD
205 | },
206 | signatureKeystore: {
207 | path: KEY_STORE_PATH,
208 | password: PASSWORD
209 | }
210 | }
211 | });
212 | xml envelope = xml `
213 |
214 |
215 | 2
216 | 3
217 |
218 |
219 | `;
220 | xml response = check soapClient->sendReceive(envelope, "http://tempuri.org/Add");
221 | }
222 | ```
223 |
--------------------------------------------------------------------------------
/ballerina/soap_utils.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import soap.wssec;
18 |
19 | import ballerina/crypto;
20 | import ballerina/http;
21 | import ballerina/jballerina.java;
22 | import ballerina/lang.regexp;
23 | import ballerina/mime;
24 | import ballerina/test;
25 |
26 | public isolated function validateTransportBindingPolicy(ClientConfig config) returns Error? {
27 | if config.httpConfig.secureSocket is () {
28 | wssec:OutboundSecurityConfig|wssec:OutboundSecurityConfig[] securityPolicy = config.outboundSecurity;
29 | if securityPolicy is wssec:TransportBindingConfig {
30 | return error Error(INVALID_PROTOCOL_ERROR);
31 | } else if securityPolicy is wssec:OutboundSecurityConfig[] {
32 | foreach wssec:OutboundSecurityConfig policy in securityPolicy {
33 | if policy is wssec:TransportBindingConfig {
34 | return error Error(INVALID_PROTOCOL_ERROR);
35 | }
36 | }
37 | }
38 | }
39 | }
40 |
41 | public isolated function getReadOnlyClientConfig(ClientConfig original) returns readonly & ClientConfig = @java:Method {
42 | 'class: "org.wssec.WsSecurity"
43 | } external;
44 |
45 | public isolated function applySecurityPolicies(wssec:OutboundSecurityConfig|wssec:OutboundSecurityConfig[] security,
46 | xml envelope, boolean soap12 = true)
47 | returns xml|crypto:Error|wssec:Error {
48 | if security is wssec:TimestampTokenConfig {
49 | return wssec:applyTimestampToken(envelope, security);
50 | } else if security is wssec:UsernameTokenConfig {
51 | return wssec:applyUsernameToken(envelope, security);
52 | } else if security is wssec:SymmetricBindingConfig {
53 | return wssec:applySymmetricBinding(envelope, soap12, security);
54 | } else if security is wssec:AsymmetricBindingConfig {
55 | return wssec:applyAsymmetricConfigurations(envelope, soap12, security);
56 | } else if security is wssec:OutboundSecurityConfig {
57 | return envelope;
58 | } else {
59 | xml securedEnvelope = envelope.clone();
60 | foreach wssec:OutboundSecurityConfig policy in security {
61 | securedEnvelope = check applySecurityPolicies(policy, securedEnvelope, soap12);
62 | }
63 | return securedEnvelope;
64 | }
65 | }
66 |
67 | public isolated function applyInboundConfig(wssec:InboundConfig inboundSecurity, xml envelope,
68 | boolean soap12 = true) returns xml|Error {
69 | xmlns "http://schemas.xmlsoap.org/soap/envelope/" as soap11;
70 | xmlns "http://www.w3.org/2003/05/soap-envelope" as soap12;
71 | xml soapEnvelope = envelope;
72 | do {
73 | crypto:KeyStore? encryptionAlgorithm = inboundSecurity.decryptKeystore;
74 | if encryptionAlgorithm is crypto:KeyStore {
75 | wssec:Document doc = check wssec:decryptEnvelope(envelope, inboundSecurity);
76 | soapEnvelope = check doc.getEnvelope();
77 | }
78 | crypto:KeyStore? signatureAlgorithm = inboundSecurity.signatureKeystore;
79 | if signatureAlgorithm is crypto:KeyStore {
80 | boolean validity = check wssec:verifySignature(soapEnvelope, inboundSecurity);
81 | if !validity {
82 | return error Error("Signature verification failed");
83 | }
84 | }
85 | return soapEnvelope;
86 | } on fail error soapError {
87 | return error Error("Outbound security configurations do not match with the SOAP response", soapError);
88 | }
89 | }
90 |
91 | public isolated function sendReceive(xml|mime:Entity[] body, http:Client httpClient, string? soapAction = (),
92 | map headers = {}, string path = "", boolean soap12 = true)
93 | returns xml|mime:Entity[]|Error {
94 | http:Request req = soap12 ? createSoap12HttpRequest(body, soapAction, headers)
95 | : createSoap11HttpRequest(body, soapAction, headers);
96 | do {
97 | http:Response response = check httpClient->post(path, req);
98 | return check createSoapResponse(response);
99 | } on fail var soapError {
100 | return error Error(SOAP_RESPONSE_ERROR, soapError);
101 | }
102 | }
103 |
104 | public isolated function sendOnly(xml|mime:Entity[] body, http:Client httpClient, string? soapAction = (),
105 | map headers = {}, string path = "", boolean soap12 = true)
106 | returns Error? {
107 | http:Request req = soap12 ? createSoap12HttpRequest(body, soapAction, headers)
108 | : createSoap11HttpRequest(body, soapAction, headers);
109 | http:Response|http:ClientError response = httpClient->post(path, req);
110 | if response is http:ClientError {
111 | return error Error(response.message());
112 | }
113 | }
114 |
115 | isolated function createSoap11HttpRequest(xml|mime:Entity[] body, string soapAction,
116 | map headers = {}) returns http:Request {
117 | http:Request req = new;
118 | if body is xml {
119 | req.setXmlPayload(body);
120 | req.setHeader(mime:CONTENT_TYPE, mime:TEXT_XML);
121 | } else {
122 | req.setBodyParts(body);
123 | req.setHeader(mime:CONTENT_TYPE, mime:MULTIPART_MIXED);
124 | }
125 | req.addHeader(SOAP_ACTION, soapAction);
126 | foreach string key in headers.keys() {
127 | req.addHeader(key, headers[key].toBalString());
128 | }
129 | return req;
130 | }
131 |
132 | isolated function createSoap12HttpRequest(xml|mime:Entity[] body, string? soapAction,
133 | map headers = {}) returns http:Request {
134 | http:Request req = new;
135 | if body is xml {
136 | req.setXmlPayload(body);
137 | } else {
138 | req.setBodyParts(body);
139 | }
140 | if soapAction is string {
141 | mime:MediaType|mime:InvalidContentTypeError mediaType;
142 | if body is xml {
143 | mediaType = mime:getMediaType(mime:APPLICATION_SOAP_XML);
144 | } else {
145 | mediaType = mime:getMediaType(mime:MULTIPART_MIXED);
146 | }
147 | if mediaType is mime:MediaType {
148 | mediaType.parameters = {"action": string `"${soapAction}"`};
149 | req.setHeader(mime:CONTENT_TYPE, mediaType.toString());
150 | }
151 | } else if body is xml {
152 | req.setHeader(mime:CONTENT_TYPE, mime:TEXT_XML);
153 | } else {
154 | req.setHeader(mime:CONTENT_TYPE, mime:MULTIPART_MIXED);
155 | }
156 | foreach string key in headers.keys() {
157 | req.addHeader(key, headers[key].toBalString());
158 | }
159 | return req;
160 | }
161 |
162 | isolated function createSoapResponse(http:Response response) returns xml|mime:Entity[]|error {
163 | mime:Entity[]|http:ClientError payload = response.getBodyParts();
164 | if payload !is mime:Entity[] {
165 | xml|error responsePayload = response.getXmlPayload();
166 | if responsePayload is xml {
167 | return responsePayload;
168 | }
169 | return error(response.reasonPhrase);
170 | }
171 | return payload;
172 | }
173 |
174 | public function assertUsernameToken(string envelopeString, string username, string password,
175 | wssec:PasswordType passwordType, string body) returns error? {
176 | string:RegExp bodyData = check regexp:fromString(body);
177 | test:assertTrue(envelopeString.includesMatch(bodyData));
178 | string:RegExp usernameTokenTag = re `.*`;
179 | string:RegExp usernameTag = re `${username}`;
180 | test:assertTrue(envelopeString.includesMatch(usernameTokenTag));
181 | test:assertTrue(envelopeString.includesMatch(usernameTag));
182 | string:RegExp passwordTag = re `${password}`;
183 | test:assertTrue(envelopeString.includesMatch(passwordTag));
184 | }
185 |
186 | public function assertSymmetricBinding(string envelopeString, string body) returns error? {
187 | string:RegExp bodyData = check regexp:fromString(body);
188 | test:assertTrue(envelopeString.includesMatch(bodyData));
189 | assertSignatureWithoutX509(envelopeString);
190 | }
191 |
192 | public function assertSignatureWithoutX509(string securedEnvelope) {
193 | string:RegExp signature = re `.*`;
194 | string:RegExp signatureInfo = re `.*`;
195 | string:RegExp canonicalizationMethod = re ``;
196 | string:RegExp signatureMethod = re ``;
197 | string:RegExp transformMethod = re ``;
198 | string:RegExp digestMethod = re ``;
199 | string:RegExp signatureValue = re `.*`;
200 |
201 | test:assertTrue(securedEnvelope.includesMatch(signature));
202 | test:assertTrue(securedEnvelope.includesMatch(signatureInfo));
203 | test:assertTrue(securedEnvelope.includesMatch(canonicalizationMethod));
204 | test:assertTrue(securedEnvelope.includesMatch(signatureMethod));
205 | test:assertTrue(securedEnvelope.includesMatch(transformMethod));
206 | test:assertTrue(securedEnvelope.includesMatch(digestMethod));
207 | test:assertTrue(securedEnvelope.includesMatch(signatureValue));
208 | }
209 |
--------------------------------------------------------------------------------
/ballerina/modules/wssec/ws_security_methods.bal:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
2 | //
3 | // WSO2 LLC. licenses this file to you under the Apache License,
4 | // Version 2.0 (the "License"); you may not use this file except
5 | // in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing,
11 | // software distributed under the License is distributed on an
12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 | // KIND, either express or implied. See the License for the
14 | // specific language governing permissions and limitations
15 | // under the License.
16 |
17 | import ballerina/crypto;
18 | import ballerina/lang.regexp;
19 |
20 | xmlns "http://schemas.xmlsoap.org/soap/envelope/" as soap11;
21 | xmlns "http://www.w3.org/2003/05/soap-envelope" as soap12;
22 | xmlns "http://www.w3.org/2000/09/xmldsig#" as ds;
23 |
24 |
25 | public isolated function verifySignature(xml|Document soapEnvelope, InboundConfig config) returns boolean|error {
26 | WsSecurity wsSecurity = new;
27 | Document document;
28 | if soapEnvelope is xml {
29 | document = check new (soapEnvelope);
30 | } else {
31 | document = soapEnvelope;
32 | }
33 | return check wsSecurity.verifySignature(document, config);
34 | }
35 |
36 | public isolated function decryptEnvelope(xml soapEnvelope, InboundConfig config) returns Document|error {
37 | WsSecurity wsSecurity = new;
38 | Document document = check new (soapEnvelope);
39 | return check wsSecurity.decryptEnvelope(document, config);
40 | }
41 |
42 | isolated function addSecurityHeader(Document document) returns WSSecurityHeader|Error {
43 | WSSecurityHeader wsSecHeader = check new (document);
44 | Error? insertHeader = wsSecHeader.insertSecHeader();
45 | return insertHeader ?: wsSecHeader;
46 | }
47 |
48 | public isolated function verifyData(byte[] data, byte[] signature, crypto:PublicKey publicKey,
49 | SignatureAlgorithm signatureAlgorithm) returns Error? {
50 | Signature sign = check new ();
51 | boolean verifySignature = check sign.verifySignature(data, signature, publicKey, signatureAlgorithm);
52 | if !verifySignature {
53 | return error Error("Signature verification of the SOAP envelope has been failed");
54 | }
55 | }
56 |
57 | isolated function addSignature(Signature sign, string signatureAlgorithm, byte[] signature) returns Signature|Error {
58 | sign.setSignatureAlgorithm(signatureAlgorithm);
59 | sign.setSignatureValue(signature);
60 | return sign;
61 | }
62 |
63 | isolated function addEncryption(Encryption encrypt, string encryptionAlgorithm, byte[] encryption) returns Encryption|Error {
64 | encrypt.setEncryptionAlgorithm(encryptionAlgorithm);
65 | encrypt.setEncryptedData(encryption);
66 | return encrypt;
67 | }
68 |
69 | isolated function applyEncryptedKey(string envelopeString, crypto:PrivateKey symmetricKey, crypto:PublicKey encryptKey)
70 | returns string|Error {
71 | string securedEnvelope = envelopeString;
72 | do {
73 | Encryption encryption = check new ();
74 | byte[] encryptedKey = check crypto:encryptRsaEcb(symmetricKey.toBalString().toBytes(), encryptKey);
75 | string encryptedKeyElements = check encryption.getEncryptedKeyElements(encryptedKey);
76 | string replace = regexp:replace(re `.*?><`, encryptedKeyElements, "<");
77 | string:RegExp securityToken =
78 | re ``;
79 | if securedEnvelope.includesMatch(securityToken) {
80 | securedEnvelope = regexp:replace(securityToken, securedEnvelope, replace);
81 | }
82 | else if securedEnvelope.includesMatch(re ``) {
83 | securedEnvelope = regexp:replace(re ``, securedEnvelope, replace);
84 | }
85 | return securedEnvelope;
86 | } on fail error encryptionError {
87 | return error Error("Error occurred while applying the encrypted key to the envelope", encryptionError);
88 | }
89 | }
90 |
91 | isolated function convertStringToXml(string envelope) returns xml|Error {
92 | xml|error xmlEnvelope = xml:fromString(regexp:replace(re `.*?><`, envelope, "<"));
93 | if xmlEnvelope is error {
94 | return error Error(xmlEnvelope.message());
95 | }
96 | return xmlEnvelope;
97 | }
98 |
99 | # Returns the encrypted data of the SOAP envelope.
100 | #
101 | # + envelope - The SOAP envelope
102 | # + return - A `byte[]` if the encrypted data is successfully decoded or else `wssec:Error`
103 | public isolated function getEncryptedData(xml envelope) returns byte[]|Error {
104 | Document document = check new (envelope);
105 | return document.getEncryptedData();
106 | }
107 |
108 | # Returns the signed data of the SOAP envelope.
109 | #
110 | # + envelope - The SOAP envelope
111 | # + return - A `byte[]` if the signed data is successfully decoded or else `wssec:Error`
112 | public isolated function getSignatureData(xml envelope) returns byte[]|Error {
113 | Document document = check new (envelope);
114 | return document.getSignatureData();
115 | }
116 |
117 | # Apply timestamp token security policy to the SOAP envelope.
118 | #
119 | # + envelope - The SOAP envelope
120 | # + timestampToken - The `TSRecord` record with the required parameters
121 | # + return - A `xml` type of SOAP envelope if the security binding is successfully added or else `wssec:Error`
122 | public isolated function applyTimestampToken(xml envelope, *TimestampTokenConfig timestampToken) returns xml|Error {
123 | if timestampToken.timeToLive <= 0 {
124 | return error Error("Invalid value for `timeToLive`");
125 | }
126 | Document document = check new (envelope);
127 | WSSecurityHeader wsSecurityHeader = check addSecurityHeader(document);
128 | WsSecurity wsSecurity = new;
129 | string securedEnvelope = check wsSecurity.applyTimestampPolicy(wsSecurityHeader, timestampToken.timeToLive);
130 | return convertStringToXml(securedEnvelope);
131 | }
132 |
133 | # Apply username token security policy to the SOAP envelope.
134 | #
135 | # + envelope - The SOAP envelope
136 | # + usernameToken - The `UsernameTokenConfig` record with the required parameters
137 | # + return - A `xml` type of SOAP envelope if the security binding is successfully added or else `wssec:Error`
138 | public isolated function applyUsernameToken(xml envelope, *UsernameTokenConfig usernameToken) returns xml|Error {
139 | Document document = check new (envelope);
140 | WSSecurityHeader wsSecurityHeader = check addSecurityHeader(document);
141 | WsSecurity wsSecurity = new;
142 | string securedEnvelope = check wsSecurity
143 | .applyUsernameTokenPolicy(wsSecurityHeader, usernameToken.username, usernameToken.password,
144 | usernameToken.passwordType);
145 | return convertStringToXml(securedEnvelope);
146 | }
147 |
148 | # Apply symmetric binding security policy with username token to the SOAP envelope.
149 | #
150 | # + envelope - The SOAP envelope
151 | # + soap12 - A boolean flag. Set to `true` for SOAP 1.2, or `false` for SOAP 1.1.
152 | # + symmetricBinding - The `SymmetricBindingConfig` record with the required parameters
153 | # + return - A `xml` type of SOAP envelope if the security binding is successfully added or else `wssec:Error`
154 | public isolated function applySymmetricBinding(xml envelope, boolean soap12, *SymmetricBindingConfig symmetricBinding)
155 | returns xml|crypto:Error|Error {
156 | Document document = check new (envelope);
157 | WSSecurityHeader wsSecurityHeader = check addSecurityHeader(document);
158 | string securedEnvelope = envelope.toBalString();
159 | SignatureAlgorithm? signatureAlgorithm = symmetricBinding.signatureAlgorithm;
160 | EncryptionAlgorithm? encryptionAlgorithm = symmetricBinding.encryptionAlgorithm;
161 | if signatureAlgorithm is SignatureAlgorithm {
162 | Signature signature = check new ();
163 | byte[] signedData;
164 | if soap12 {
165 | signedData = check signature.signData((envelope//*).toString(), signatureAlgorithm,
166 | symmetricBinding.symmetricKey);
167 | } else {
168 | signedData = check signature.signData((envelope//*).toString(), signatureAlgorithm,
169 | symmetricBinding.symmetricKey);
170 | }
171 |
172 | Signature signatureResult = check addSignature(signature, signatureAlgorithm, signedData);
173 | WsSecurity wsSecurity = new;
174 | securedEnvelope = check wsSecurity.applySignatureOnlyPolicy(wsSecurityHeader, signatureResult,
175 | symmetricBinding.x509Token);
176 | }
177 | if encryptionAlgorithm is EncryptionAlgorithm {
178 | Encryption encryption = check new ();
179 | byte[] encryptData;
180 | if soap12 {
181 | encryptData = check crypto:encryptRsaEcb((envelope//*).toString().toBytes(),
182 | symmetricBinding.symmetricKey);
183 | } else {
184 | encryptData = check crypto:encryptRsaEcb((envelope//*).toString().toBytes(),
185 | symmetricBinding.symmetricKey);
186 | }
187 | Encryption encryptionResult = check addEncryption(encryption, encryptionAlgorithm, encryptData);
188 | WsSecurity wsSecurity = new;
189 | securedEnvelope = check wsSecurity.applyEncryptionOnlyPolicy(wsSecurityHeader, encryptionResult);
190 | }
191 | securedEnvelope = check applyEncryptedKey(securedEnvelope, symmetricBinding.symmetricKey,
192 | symmetricBinding.servicePublicKey);
193 | return convertStringToXml(securedEnvelope);
194 | }
195 |
196 | # Apply asymmetric binding security policy with X509 token to the SOAP envelope.
197 | #
198 | # + envelope - The SOAP envelope
199 | # + soap12 - A boolean flag. Set to `true` for SOAP 1.2, or `false` for SOAP 1.1.
200 | # + asymmetricBinding - The `AsymmetricBindingConfig` record with the required parameters
201 | # + return - A `xml` type of SOAP envelope if the security binding is successfully added or else `wssec:Error`
202 | public isolated function applyAsymmetricConfigurations(xml envelope, boolean soap12,
203 | *AsymmetricBindingConfig asymmetricBinding)
204 | returns xml|Error {
205 | Document document = check new (envelope);
206 | WsSecurity wsSecurity = new;
207 | _ = check addSecurityHeader(document);
208 | SignatureConfig? signatureConfig = asymmetricBinding.signatureConfig;
209 | EncryptionConfig? encryptionConfig = asymmetricBinding.encryptionConfig;
210 | string securedEnvelope = envelope.toString();
211 | if signatureConfig !is () && encryptionConfig !is () {
212 | securedEnvelope = check wsSecurity
213 | .applySignatureAndEncryption(document, soap12, signatureConfig, encryptionConfig);
214 | } else if signatureConfig !is () {
215 | securedEnvelope = check wsSecurity.applySignatureOnly(document, soap12, signatureConfig);
216 | } else if encryptionConfig !is () {
217 | securedEnvelope = check wsSecurity.applyEncryptionOnly(document, soap12, encryptionConfig);
218 | }
219 | return convertStringToXml(securedEnvelope);
220 | }
221 |
222 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Ballerina SOAP Library
2 |
3 | [](https://github.com/ballerina-platform/module-ballerina-soap/actions/workflows/build-timestamped-master.yml)
4 | [](https://codecov.io/gh/ballerina-platform/module-ballerina-soap)
5 | [](https://github.com/ballerina-platform/module-ballerina-soap/actions/workflows/trivy-scan.yml)
6 | [](https://github.com/ballerina-platform/module-ballerina-soap/actions/workflows/build-with-bal-test-graalvm.yml)
7 | [](https://github.com/ballerina-platform/module-ballerina-soap/commits/master)
8 | [](https://github.com/ballerina-platform/ballerina-standard-library/labels/module%2Fsoap)
9 | [](https://codecov.io/gh/ballerina-platform/module-ballerina-soap)
10 |
11 | This module offers a set of APIs that facilitate the transmission of XML requests to a SOAP backend. It excels in managing security policies within SOAP requests, ensuring the transmission of secured SOAP envelopes. Moreover, it possesses the capability to efficiently extract data from security-applied SOAP responses.
12 |
13 | SOAP module abstracts out the details of the creation of a SOAP envelope, headers, and the body in a SOAP message.
14 |
15 | ## Client
16 |
17 | The `Client` is used to connect to and interact with `SOAP` endpoints.
18 |
19 | ### SOAP 1.1 Client
20 |
21 | ```ballerina
22 | import ballerina/soap.soap11;
23 |
24 | soap11:Client soapClient = check new ("http://www.dneonline.com/calculator.asmx?WSDL");
25 | ```
26 |
27 | ### SOAP 1.2 Client
28 |
29 | ```ballerina
30 | import ballerina/soap.soap12;
31 |
32 | soap12:Client soapClient = check new ("http://www.dneonline.com/calculator.asmx?WSDL");
33 | ```
34 |
35 | ## APIs associated with SOAP
36 |
37 | - **Send & Receive**: Sends SOAP request and receives a response.
38 | - **Send Only**: Fires and forgets requests. Sends the request without the possibility of any response from the service.
39 |
40 | The SOAP 1.1 specification requires the inclusion of the `action` parameter as a mandatory component within its APIs. In contrast, SOAP 1.2 relaxes this requirement, making the action parameter optional.
41 |
42 | ### Example: Send & Receive
43 |
44 | ```ballerina
45 | import ballerina/soap.soap11;
46 |
47 | public function main() returns error? {
48 | soap11:Client soapClient = check new ("http://www.dneonline.com/calculator.asmx?WSDL");
49 |
50 | xml envelope = xml `
51 |
52 |
53 | 2
54 | 3
55 |
56 |
57 | `;
58 | xml response = check soapClient->sendReceive(envelope, "http://tempuri.org/Add");
59 | }
60 | ```
61 |
62 | ### Example: Send Only
63 |
64 | ```ballerina
65 | import ballerina/soap.soap11;
66 |
67 | public function main() returns error? {
68 | soap11:Client soapClient = check new ("http://www.dneonline.com/calculator.asmx?WSDL");
69 |
70 | xml envelope = xml `
71 |
72 |
73 | 2
74 | 3
75 |
76 |
77 | `;
78 | check soapClient->sendOnly(envelope, "http://tempuri.org/Add");
79 | }
80 | ```
81 |
82 | ## Security
83 |
84 | The SOAP client module introduces a robust framework for configuring security measures in SOAP communication. Security is a critical concern when exchanging data via web services, and this module offers comprehensive options to fortify SOAP requests and responses.
85 |
86 | There are two primary security configurations available for SOAP clients:
87 |
88 | - `outboundSecurity`: This configuration applies ws-security policies to outgoing SOAP messages. It supports multiple security options, such as Username Token, Timestamp Token, X.509 Token, Symmetric Binding, Asymmetric Binding, and Transport Binding. These can be used individually or in combination to secure the message.
89 |
90 | - `inboundSecurity`: This configuration handles the security of incoming SOAP messages. It decrypts encrypted data and verifies the digital signature to confirm the authenticity of the message.
91 |
92 | ### Policies
93 |
94 | This library currently supports the following WS Security policies:
95 |
96 | - **Username Token**: Provides authentication through username and password credentials.
97 | - **Timestamp Token**: Enhances message integrity by incorporating timestamp information.
98 | - **X509 Token**: Allows the use of X.509 certificates for secure communication.
99 | - **Symmetric Binding**: Enables symmetric key-based security mechanisms.
100 | - **Asymmetric Binding**: Facilitates the use of asymmetric cryptography for enhanced security.
101 |
102 | These policies empower SOAP clients to enhance the security of their web service communications by selecting and implementing the appropriate security mechanisms to safeguard their SOAP envelopes.
103 |
104 | ### Security Policy Configuration Types
105 |
106 | #### Outbound Security Configurations
107 |
108 | - `TimestampTokenConfig`: Represents the record for Timestamp Token policy.
109 | - Fields:
110 | - `int` timeToLive : The time to get expired
111 |
112 | - `UsernameTokenConfig`: Represents the record for Username Token policy.
113 | - Fields:
114 | - `string` username : The name of the user
115 | - `string` password : The password of the user
116 | - `PasswordType` passwordType : The password type of the username token
117 |
118 | - `SymmetricBindingConfig`: Represents the record for Symmetric Binding policy.
119 | - Fields:
120 | - `crypto:PrivateKey` symmetricKey : The key to sign and encrypt the SOAP envelope
121 | - `crypto:PublicKey` servicePublicKey : The key to encrypt the symmetric key
122 | - `SignatureAlgorithm` signatureAlgorithm : The algorithm to sign the SOAP envelope
123 | - `EncryptionAlgorithm` encryptionAlgorithm : The algorithm to encrypt the SOAP envelope
124 | - `string` x509Token : The path or token of the X509 certificate
125 |
126 | - `AsymmetricBindingConfig`: Represents the record for Asymmetric Binding policy.
127 | - Fields:
128 | - `SignatureConfig` signatureConfig : Configuration for applying digital signatures
129 | - `EncryptionConfig` encryptionConfig : Configuration for applying encryption
130 | - `string` x509Token : The path or token of the X509 certificate
131 |
132 | #### Inbound Security Configurations
133 |
134 | - `InboundSecurityConfig`: Represents the record for outbound security configurations to verify and decrypt SOAP envelopes.
135 | - Fields:
136 | - `crypto:KeyStore` decryptKeystore - The keystore to decrypt the SOAP envelope
137 | - `crypto:KeyStore` signatureKeystore - The keystore to verify the signature of the SOAP envelope
138 |
139 | ### Apply Security Policies
140 |
141 | #### SOAP 1.1 Client: UsernameToken and TranportBinding Policy
142 |
143 | ```ballerina
144 | import ballerina/crypto;
145 | import ballerina/mime;
146 | import ballerina/soap;
147 | import ballerina/soap.soap11;
148 |
149 | public function main() returns error? {
150 | soap11:Client soapClient = check new ("https://www.secured-soap-endpoint.com",
151 | {
152 | outboundSecurity: [
153 | {
154 | username: "username",
155 | password: "password",
156 | passwordType: soap:TEXT
157 | },
158 | TRANSPORT_BINDING
159 | ]
160 | });
161 |
162 | xml envelope = xml `
163 |
164 |
165 | 2
166 | 3
167 |
168 |
169 | `;
170 | xml response = check soapClient->sendReceive(envelope, "http://tempuri.org/Add");
171 | }
172 | ```
173 |
174 | #### SOAP 1.2 Client with Asymmetric Binding and Outbound Security Configuration
175 |
176 | ```ballerina
177 | import ballerina/crypto;
178 | import ballerina/mime;
179 | import ballerina/soap;
180 | import ballerina/soap.soap12;
181 |
182 | public function main() returns error? {
183 |
184 | soap12:Client soapClient = check new ("http://www.secured-soap-endpoint.com",
185 | {
186 | outboundSecurity: {
187 | signatureConfig: {
188 | keystore: {
189 | path: KEY_STORE_PATH,
190 | password: PASSWORD
191 | },
192 | privateKeyAlias: ALIAS,
193 | privateKeyPassword: PASSWORD,
194 | signatureAlgorithm: wssec:RSA_SHA1
195 | },
196 | encryptionConfig: {
197 | keystore: {
198 | path: KEY_STORE_PATH_2,
199 | password: PASSWORD
200 | },
201 | publicKeyAlias: ALIAS,
202 | encryptionAlgorithm: wssec:AES_128
203 | }
204 | },
205 | inboundSecurity: {
206 | decryptKeystore: {
207 | path: KEY_STORE_PATH_2,
208 | password: PASSWORD
209 | },
210 | signatureKeystore: {
211 | path: KEY_STORE_PATH_2,
212 | password: PASSWORD
213 | }
214 | }
215 | });
216 |
217 | xml envelope = xml `
218 |
219 |
220 | 2
221 | 3
222 |
223 |
224 | `;
225 | xml response = check soapClient->sendReceive(envelope, "http://tempuri.org/Add");
226 | }
227 | ```
228 |
229 | ## Issues and projects
230 |
231 | The **Issues** and **Projects** tabs are disabled for this repository as this is part of the Ballerina Standard Library. To report bugs, request new features, start new discussions, view project boards, etc., go to the Ballerina Standard Library [parent repository](https://github.com/ballerina-platform/ballerina-standard-library).
232 |
233 | This repository contains only the source code of the package.
234 |
235 | ## Build from the source
236 |
237 | ### Set up the prerequisites
238 |
239 | 1. Download and install Java SE Development Kit (JDK) version 21 (from one of the following locations).
240 | - [Oracle](https://www.oracle.com/java/technologies/downloads/)
241 |
242 | - [OpenJDK](https://adoptium.net/)
243 |
244 | > **Note:** Set the JAVA_HOME environment variable to the path name of the directory into which you installed JDK.
245 |
246 | 2. Export your Github Personal access token with the read package permissions as follows.
247 |
248 | ```bash
249 | export packageUser=
250 | export packagePAT=
251 | ```
252 |
253 | ### Build the source
254 |
255 | Execute the commands below to build from source.
256 |
257 | 1. To build the library:
258 |
259 | ```bash
260 | ./gradlew clean build
261 | ```
262 |
263 | 2. To run the integration tests:
264 |
265 | ```bash
266 | ./gradlew clean test
267 | ```
268 |
269 | 3. To build the module without the tests:
270 |
271 | ```bash
272 | ./gradlew clean build -x test
273 | ```
274 |
275 | 4. To debug module implementation:
276 |
277 | ```bash
278 | ./gradlew clean build -Pdebug=
279 | ./gradlew clean test -Pdebug=
280 | ```
281 |
282 | 5. To debug the module with Ballerina language:
283 |
284 | ```bash
285 | ./gradlew clean build -PbalJavaDebug=
286 | ./gradlew clean test -PbalJavaDebug=
287 | ```
288 |
289 | 6. Publish ZIP artifact to the local `.m2` repository:
290 |
291 | ```bash
292 | ./gradlew clean build publishToMavenLocal
293 | ```
294 |
295 | 7. Publish the generated artifacts to the local Ballerina central repository:
296 |
297 | ```bash
298 | ./gradlew clean build -PpublishToLocalCentral=true
299 | ```
300 |
301 | 8. Publish the generated artifacts to the Ballerina central repository:
302 |
303 | ```bash
304 | ./gradlew clean build -PpublishToCentral=true
305 | ```
306 |
307 | ## Contribute to Ballerina
308 |
309 | As an open source project, Ballerina welcomes contributions from the community.
310 |
311 | For more information, go to the [contribution guidelines](https://github.com/ballerina-platform/ballerina-lang/blob/master/CONTRIBUTING.md).
312 |
313 | ## Code of conduct
314 |
315 | All contributors are encouraged to read the [Ballerina Code of Conduct](https://ballerina.io/code-of-conduct).
316 |
317 | ## Useful links
318 |
319 | - Chat live with us via our [Discord server](https://discord.gg/ballerinalang).
320 | - Post all technical questions on Stack Overflow with the [#ballerina](https://stackoverflow.com/questions/tagged/ballerina) tag.
321 | - For more information go to the [`soap` library](https://lib.ballerina.io/ballerina/soap/latest).
322 | - For example demonstrations of the usage, go to [Ballerina By Examples](https://ballerina.io/swan-lake/learn/by-example/).
323 |
--------------------------------------------------------------------------------