diff --git a/README.md b/README.md
index 17424dd..7cd54ae 100644
--- a/README.md
+++ b/README.md
@@ -85,9 +85,9 @@ The SOAP client module introduces a robust framework for configuring security me
There are two primary security configurations available for SOAP clients:
-- `inboundSecurity`: This configuration is applied to the SOAP envelope when a request is made. It includes various ws security policies such as Username Token, Timestamp Token, X509 Token, Symmetric Binding, Asymmetric Binding, and Transport Binding, either individually or in combination with each other.
+- `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.
-- `outboundSecurity`: This configuration is applied to the SOAP envelope when a response is received. Its purpose is to decrypt the data within the envelope and verify the digital signature for security validation.
+- `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.
### Policies
@@ -103,7 +103,7 @@ These policies empower SOAP clients to enhance the security of their web service
### Security Policy Configuration Types
-#### Inbound Security Configurations
+#### Outbound Security Configurations
- `TimestampTokenConfig`: Represents the record for Timestamp Token policy.
- Fields:
@@ -123,22 +123,18 @@ These policies empower SOAP clients to enhance the security of their web service
- `EncryptionAlgorithm` encryptionAlgorithm : The algorithm to encrypt the SOAP envelope
- `string` x509Token : The path or token of the X509 certificate
-- `AsymmetricBindingConfig`: Represents the record for Username Token with Asymmetric Binding policy.
+- `AsymmetricBindingConfig`: Represents the record for Asymmetric Binding policy.
- Fields:
- - `crypto:PrivateKey` signatureKey : The private key to sign the SOAP envelope
- - `crypto:PublicKey` encryptionKey : The public key to encrypt the SOAP body
- - `SignatureAlgorithm` signatureAlgorithm : The algorithm to sign the SOAP envelope
- - `EncryptionAlgorithm` encryptionAlgorithm : The algorithm to encrypt the SOAP body
- - `string` x509Token : field description
+ - `SignatureConfig` signatureConfig : Configuration for applying digital signatures
+ - `EncryptionConfig` encryptionConfig : Configuration for applying encryption
+ - `string` x509Token : The path or token of the X509 certificate
-#### Outbound Security Configurations
+#### Inbound Security Configurations
-- `OutboundSecurityConfig`: Represents the record for outbound security configurations to verify and decrypt SOAP envelopes.
+- `InboundSecurityConfig`: Represents the record for outbound security configurations to verify and decrypt SOAP envelopes.
- Fields:
- - `crypto:PublicKey` verificationKey : The public key to verify the signature of the SOAP envelope
- - `crypto:PrivateKey`|`crypto:PublicKey` decryptionKey : The private key to decrypt the SOAP envelope
- - `SignatureAlgorithm` signatureAlgorithm : The algorithm to verify the SOAP envelope
- - `EncryptionAlgorithm` decryptionAlgorithm : The algorithm to decrypt the SOAP body
+ - `crypto:KeyStore` decryptKeystore - The keystore to decrypt the SOAP envelope
+ - `crypto:KeyStore` signatureKeystore - The keystore to verify the signature of the SOAP envelope
### Apply Security Policies
@@ -153,7 +149,7 @@ import ballerina/soap.soap11;
public function main() returns error? {
soap11:Client soapClient = check new ("https://www.secured-soap-endpoint.com",
{
- inboundSecurity: [
+ outboundSecurity: [
{
username: "username",
password: "password",
@@ -184,27 +180,41 @@ import ballerina/soap;
import ballerina/soap.soap12;
public function main() returns error? {
- configurable crypto:PrivateKey clientPrivateKey = ?;
- configurable crypto:PublicKey clientPublicKey = ?;
- configurable crypto:PublicKey serverPublicKey = ?;
- soap12:Client soapClient = check new ("https://www.secured-soap-endpoint.com",
+ soap12:Client soapClient = check new ("http://www.secured-soap-endpoint.com",
{
- inboundSecurity: {
- signatureAlgorithm: soap:RSA_SHA256,
- encryptionAlgorithm: soap:RSA_ECB,
- signatureKey: clientPrivateKey,
- encryptionKey: serverPublicKey,
- },
outboundSecurity: {
- verificationKey: serverPublicKey,
- signatureAlgorithm: soap:RSA_SHA256,
- decryptionKey: clientPrivateKey,
- decryptionAlgorithm: soap:RSA_ECB
+ signatureConfig: {
+ keystore: {
+ path: KEY_STORE_PATH,
+ password: PASSWORD
+ },
+ privateKeyAlias: ALIAS,
+ privateKeyPassword: PASSWORD,
+ signatureAlgorithm: wssec:RSA_SHA1
+ },
+ encryptionConfig: {
+ keystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ publicKeyAlias: ALIAS,
+ encryptionAlgorithm: wssec:AES_128
+ }
+ },
+ inboundSecurity: {
+ decryptKeystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ signatureKeystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ }
}
});
- xml envelope = xml `
+ xml envelope = xml `
2
diff --git a/ballerina/Ballerina.toml b/ballerina/Ballerina.toml
index a1a4977..357f155 100644
--- a/ballerina/Ballerina.toml
+++ b/ballerina/Ballerina.toml
@@ -1,7 +1,7 @@
[package]
org = "ballerina"
name = "soap"
-version = "1.1.0"
+version = "2.0.0"
authors = ["Ballerina"]
export=["soap", "soap.soap11", "soap.soap12"]
keywords = ["soap"]
@@ -19,8 +19,8 @@ graalvmCompatible = true
[[platform.java17.dependency]]
groupId = "io.ballerina.stdlib"
artifactId = "soap-native"
-version = "1.1.0"
-path = "../native/build/libs/soap-native-1.1.0.jar"
+version = "2.0.0"
+path = "../native/build/libs/soap-native-2.0.0-SNAPSHOT.jar"
[[platform.java17.dependency]]
groupId = "org.apache.wss4j"
diff --git a/ballerina/Dependencies.toml b/ballerina/Dependencies.toml
index 8c68d62..5745e59 100644
--- a/ballerina/Dependencies.toml
+++ b/ballerina/Dependencies.toml
@@ -64,7 +64,7 @@ dependencies = [
[[package]]
org = "ballerina"
name = "http"
-version = "2.12.0"
+version = "2.12.1"
dependencies = [
{org = "ballerina", name = "auth"},
{org = "ballerina", name = "cache"},
@@ -227,7 +227,7 @@ dependencies = [
[[package]]
org = "ballerina"
name = "mime"
-version = "2.10.0"
+version = "2.10.1"
dependencies = [
{org = "ballerina", name = "io"},
{org = "ballerina", name = "jballerina.java"},
@@ -271,7 +271,7 @@ dependencies = [
[[package]]
org = "ballerina"
name = "soap"
-version = "1.1.0"
+version = "2.0.0"
dependencies = [
{org = "ballerina", name = "crypto"},
{org = "ballerina", name = "http"},
@@ -314,7 +314,7 @@ modules = [
[[package]]
org = "ballerina"
name = "time"
-version = "2.4.0"
+version = "2.5.0"
dependencies = [
{org = "ballerina", name = "jballerina.java"}
]
diff --git a/ballerina/Module.md b/ballerina/Module.md
index f7aa647..397ebbd 100644
--- a/ballerina/Module.md
+++ b/ballerina/Module.md
@@ -77,9 +77,9 @@ The SOAP client module introduces a robust framework for configuring security me
There are two primary security configurations available for SOAP clients:
-- `inboundSecurity`: This configuration is applied to the SOAP envelope when a request is made. It includes various ws security policies such as Username Token, Timestamp Token, X509 Token, Symmetric Binding, Asymmetric Binding, and Transport Binding, either individually or in combination with each other.
+- `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.
-- `outboundSecurity`: This configuration is applied to the SOAP envelope when a response is received. Its purpose is to decrypt the data within the envelope and verify the digital signature for security validation.
+- `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.
### Policies
@@ -95,7 +95,7 @@ These policies empower SOAP clients to enhance the security of their web service
### Security Policy Configuration Types
-#### Inbound Security Configurations
+#### Outbound Security Configurations
- `TimestampTokenConfig`: Represents the record for Timestamp Token policy.
- Fields:
@@ -115,22 +115,18 @@ These policies empower SOAP clients to enhance the security of their web service
- `EncryptionAlgorithm` encryptionAlgorithm : The algorithm to encrypt the SOAP envelope
- `string` x509Token : The path or token of the X509 certificate
-- `AsymmetricBindingConfig`: Represents the record for Username Token with Asymmetric Binding policy.
+- `AsymmetricBindingConfig`: Represents the record for Asymmetric Binding policy.
- Fields:
- - `crypto:PrivateKey` signatureKey : The private key to sign the SOAP envelope
- - `crypto:PublicKey` encryptionKey : The public key to encrypt the SOAP body
- - `SignatureAlgorithm` signatureAlgorithm : The algorithm to sign the SOAP envelope
- - `EncryptionAlgorithm` encryptionAlgorithm : The algorithm to encrypt the SOAP body
- - `string` x509Token : field description
+ - `SignatureConfig` signatureConfig : Configuration for applying digital signatures
+ - `EncryptionConfig` encryptionConfig : Configuration for applying encryption
+ - `string` x509Token : The path or token of the X509 certificate
-#### Outbound Security Configurations
+#### Inbound Security Configurations
-- `OutboundSecurityConfig`: Represents the record for outbound security configurations to verify and decrypt SOAP envelopes.
+- `InboundSecurityConfig`: Represents the record for outbound security configurations to verify and decrypt SOAP envelopes.
- Fields:
- - `crypto:PublicKey` verificationKey : The public key to verify the signature of the SOAP envelope
- - `crypto:PrivateKey`|`crypto:PublicKey` decryptionKey : The private key to decrypt the SOAP envelope
- - `SignatureAlgorithm` signatureAlgorithm : The algorithm to verify the SOAP envelope
- - `EncryptionAlgorithm` decryptionAlgorithm : The algorithm to decrypt the SOAP body
+ - `crypto:KeyStore` decryptKeystore - The keystore to decrypt the SOAP envelope
+ - `crypto:KeyStore` signatureKeystore - The keystore to verify the signature of the SOAP envelope
### Apply Security Policies
@@ -145,7 +141,7 @@ import ballerina/soap.soap11;
public function main() returns error? {
soap11:Client soapClient = check new ("https://www.secured-soap-endpoint.com",
{
- inboundSecurity: [
+ outboundSecurity: [
{
username: "username",
password: "password",
@@ -182,17 +178,35 @@ public function main() returns error? {
soap12:Client soapClient = check new ("https://www.secured-soap-endpoint.com",
{
- inboundSecurity: {
- signatureAlgorithm: soap:RSA_SHA256,
- encryptionAlgorithm: soap:RSA_ECB,
- signatureKey: clientPrivateKey,
- encryptionKey: serverPublicKey,
- },
outboundSecurity: {
- verificationKey: serverPublicKey,
- signatureAlgorithm: soap:RSA_SHA256,
- decryptionKey: clientPrivateKey,
- decryptionAlgorithm: soap:RSA_ECB
+ signatureConfig: {
+ keystore: {
+ path: KEY_STORE_PATH,
+ password: PASSWORD
+ },
+ privateKeyAlias: ALIAS,
+ privateKeyPassword: PASSWORD,
+ canonicalizationAlgorithm: wssec:C14N_EXCL_OMIT_COMMENTS,
+ digestAlgorithm: wssec:SHA1
+ },
+ encryptionConfig: {
+ keystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ publicKeyAlias: ALIAS,
+ encryptionAlgorithm: wssec:AES_128
+ }
+ },
+ inboundSecurity: {
+ decryptKeystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ signatureKeystore: {
+ path: KEY_STORE_PATH,
+ password: PASSWORD
+ }
}
});
xml envelope = xml `
diff --git a/ballerina/Package.md b/ballerina/Package.md
index 9b4ce35..4e44074 100644
--- a/ballerina/Package.md
+++ b/ballerina/Package.md
@@ -77,9 +77,9 @@ The SOAP client module introduces a robust framework for configuring security me
There are two primary security configurations available for SOAP clients:
-- `inboundSecurity`: This configuration is applied to the SOAP envelope when a request is made. It includes various ws security policies such as Username Token, Timestamp Token, X509 Token, Symmetric Binding, Asymmetric Binding, and Transport Binding, either individually or in combination with each other.
+- `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.
-- `outboundSecurity`: This configuration is applied to the SOAP envelope when a response is received. Its purpose is to decrypt the data within the envelope and verify the digital signature for security validation.
+- `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.
### Policies
@@ -95,7 +95,7 @@ These policies empower SOAP clients to enhance the security of their web service
### Security Policy Configuration Types
-#### Inbound Security Configurations
+#### Outbound Security Configurations
- `TimestampTokenConfig`: Represents the record for Timestamp Token policy.
- Fields:
@@ -103,9 +103,9 @@ These policies empower SOAP clients to enhance the security of their web service
- `UsernameTokenConfig`: Represents the record for Username Token policy.
- Fields:
- - `string` username : The name of the user
- - `string` password : The password of the user
- - `PasswordType` passwordType : The password type of the username token
+ - `string` username : The name of the user
+ - `string` password : The password of the user
+ - `PasswordType` passwordType : The password type of the username token
- `SymmetricBindingConfig`: Represents the record for Symmetric Binding policy.
- Fields:
@@ -115,22 +115,18 @@ These policies empower SOAP clients to enhance the security of their web service
- `EncryptionAlgorithm` encryptionAlgorithm : The algorithm to encrypt the SOAP envelope
- `string` x509Token : The path or token of the X509 certificate
-- `AsymmetricBindingConfig`: Represents the record for Username Token with Asymmetric Binding policy.
+- `AsymmetricBindingConfig`: Represents the record for Asymmetric Binding policy.
- Fields:
- - `crypto:PrivateKey` signatureKey : The private key to sign the SOAP envelope
- - `crypto:PublicKey` encryptionKey : The public key to encrypt the SOAP body
- - `SignatureAlgorithm` signatureAlgorithm : The algorithm to sign the SOAP envelope
- - `EncryptionAlgorithm` encryptionAlgorithm : The algorithm to encrypt the SOAP body
- - `string` x509Token : field description
+ - `SignatureConfig` signatureConfig : Configuration for applying digital signatures
+ - `EncryptionConfig` encryptionConfig : Configuration for applying encryption
+ - `string` x509Token : The path or token of the X509 certificate
-#### Outbound Security Configurations
+#### Inbound Security Configurations
-- `OutboundSecurityConfig`: Represents the record for outbound security configurations to verify and decrypt SOAP envelopes.
+- `InboundSecurityConfig`: Represents the record for outbound security configurations to verify and decrypt SOAP envelopes.
- Fields:
- - `crypto:PublicKey` verificationKey : The public key to verify the signature of the SOAP envelope
- - `crypto:PrivateKey`|`crypto:PublicKey` decryptionKey : The private key to decrypt the SOAP envelope
- - `SignatureAlgorithm` signatureAlgorithm : The algorithm to verify the SOAP envelope
- - `EncryptionAlgorithm` decryptionAlgorithm : The algorithm to decrypt the SOAP body
+ - `crypto:KeyStore` decryptKeystore - The keystore to decrypt the SOAP envelope
+ - `crypto:KeyStore` signatureKeystore - The keystore to verify the signature of the SOAP envelope
### Apply Security Policies
@@ -145,7 +141,7 @@ import ballerina/soap.soap11;
public function main() returns error? {
soap11:Client soapClient = check new ("https://www.secured-soap-endpoint.com",
{
- inboundSecurity: [
+ outboundSecurity: [
{
username: "username",
password: "password",
@@ -182,18 +178,45 @@ public function main() returns error? {
soap12:Client soapClient = check new ("https://www.secured-soap-endpoint.com",
{
- inboundSecurity: {
- signatureAlgorithm: soap:RSA_SHA256,
- encryptionAlgorithm: soap:RSA_ECB,
- signatureKey: clientPrivateKey,
- encryptionKey: serverPublicKey,
- },
outboundSecurity: {
- verificationKey: serverPublicKey,
- signatureAlgorithm: soap:RSA_SHA256,
- decryptionKey: clientPrivateKey,
- decryptionAlgorithm: soap:RSA_ECB
+ signatureConfig: {
+ keystore: {
+ path: KEY_STORE_PATH,
+ password: PASSWORD
+ },
+ privateKeyAlias: ALIAS,
+ privateKeyPassword: PASSWORD,
+ canonicalizationAlgorithm: wssec:C14N_EXCL_OMIT_COMMENTS,
+ digestAlgorithm: wssec:SHA1
+ },
+ encryptionConfig: {
+ keystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ publicKeyAlias: ALIAS,
+ encryptionAlgorithm: wssec:AES_128
+ }
+ },
+ inboundSecurity: {
+ decryptKeystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ signatureKeystore: {
+ path: KEY_STORE_PATH,
+ password: PASSWORD
+ }
}
});
+ xml envelope = xml `
+
+
+ 2
+ 3
+
+
+ `;
+ xml response = check soapClient->sendReceive(envelope, "http://tempuri.org/Add");
}
```
diff --git a/ballerina/configs.bal b/ballerina/configs.bal
index 85d067e..8242714 100644
--- a/ballerina/configs.bal
+++ b/ballerina/configs.bal
@@ -19,10 +19,10 @@ import ballerina/http;
# SOAP client configurations.
#
# + httpConfig - HTTP Configuration
-# + inboundSecurity - Web service security configurations for SOAP requests
-# + outboundSecurity - Web service security configurations to decrypt and verify SOAP responses
+# + outboundSecurity - Web service security configurations for SOAP requests
+# + inboundSecurity - Web service security configurations to decrypt and verify SOAP responses
public type ClientConfig record {|
http:ClientConfiguration httpConfig = {};
- InboundSecurityConfig|InboundSecurityConfig[] inboundSecurity = NO_POLICY;
- OutboundSecurityConfig outboundSecurity = {};
+ OutboundSecurityConfig|OutboundSecurityConfig[] outboundSecurity = NO_POLICY;
+ InboundSecurityConfig inboundSecurity = {};
|};
diff --git a/ballerina/modules/soap11/Module.md b/ballerina/modules/soap11/Module.md
index 6d34c9f..de8f8a9 100644
--- a/ballerina/modules/soap11/Module.md
+++ b/ballerina/modules/soap11/Module.md
@@ -69,9 +69,9 @@ The SOAP client module introduces a robust framework for configuring security me
There are two primary security configurations available for SOAP clients:
-- `inboundSecurity`: This configuration is applied to the SOAP envelope when a request is made. It includes various ws security policies such as Username Token, Timestamp Token, X509 Token, Symmetric Binding, Asymmetric Binding, and Transport Binding, either individually or in combination with each other.
+- `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.
-- `outboundSecurity`: This configuration is applied to the SOAP envelope when a response is received. Its purpose is to decrypt the data within the envelope and verify the digital signature for security validation.
+- `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.
### Policies
@@ -87,7 +87,7 @@ These policies empower SOAP clients to enhance the security of their web service
### Security Policy Configuration Types
-#### Inbound Security Configurations
+#### Outbound Security Configurations
- `TimestampTokenConfig`: Represents the record for Timestamp Token policy.
- Fields:
@@ -107,22 +107,18 @@ These policies empower SOAP clients to enhance the security of their web service
- `EncryptionAlgorithm` encryptionAlgorithm : The algorithm to encrypt the SOAP envelope
- `string` x509Token : The path or token of the X509 certificate
-- `AsymmetricBindingConfig`: Represents the record for Username Token with Asymmetric Binding policy.
+- `AsymmetricBindingConfig`: Represents the record for Asymmetric Binding policy.
- Fields:
- - `crypto:PrivateKey` signatureKey : The private key to sign the SOAP envelope
- - `crypto:PublicKey` encryptionKey : The public key to encrypt the SOAP body
- - `SignatureAlgorithm` signatureAlgorithm : The algorithm to sign the SOAP envelope
- - `EncryptionAlgorithm` encryptionAlgorithm : The algorithm to encrypt the SOAP body
- - `string` x509Token : field description
+ - `SignatureConfig` signatureConfig : Configuration for applying digital signatures
+ - `EncryptionConfig` encryptionConfig : Configuration for applying encryption
+ - `string` x509Token : The path or token of the X509 certificate
-#### Outbound Security Configurations
+#### Inbound Security Configurations
-- `OutboundSecurityConfig`: Represents the record for outbound security configurations to verify and decrypt SOAP envelopes.
+- `InboundSecurityConfig`: Represents the record for outbound security configurations to verify and decrypt SOAP envelopes.
- Fields:
- - `crypto:PublicKey` verificationKey : The public key to verify the signature of the SOAP envelope
- - `crypto:PrivateKey`|`crypto:PublicKey` decryptionKey : The private key to decrypt the SOAP envelope
- - `SignatureAlgorithm` signatureAlgorithm : The algorithm to verify the SOAP envelope
- - `EncryptionAlgorithm` decryptionAlgorithm : The algorithm to decrypt the SOAP body
+ - `crypto:KeyStore` decryptKeystore - The keystore to decrypt the SOAP envelope
+ - `crypto:KeyStore` signatureKeystore - The keystore to verify the signature of the SOAP envelope
### Apply Security Policies
@@ -141,17 +137,34 @@ public function main() returns error? {
soap11:Client soapClient = check new ("http://www.secured-soap-endpoint.com",
{
- inboundSecurity: {
- signatureAlgorithm: soap:RSA_SHA256,
- encryptionAlgorithm: soap:RSA_ECB,
- signatureKey: clientPrivateKey,
- encryptionKey: serverPublicKey,
- },
outboundSecurity: {
- verificationKey: serverPublicKey,
- signatureAlgorithm: soap:RSA_SHA256,
- decryptionKey: clientPrivateKey,
- decryptionAlgorithm: soap:RSA_ECB
+ signatureConfig: {
+ keystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ privateKeyAlias: ALIAS,
+ privateKeyPassword: PASSWORD,
+ signatureAlgorithm: wssec:RSA_SHA1
+ },
+ encryptionConfig: {
+ keystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ publicKeyAlias: ALIAS,
+ encryptionAlgorithm: wssec:AES_128
+ }
+ },
+ inboundSecurity: {
+ decryptKeystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ signatureKeystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ }
}
});
}
diff --git a/ballerina/modules/soap11/soap11.bal b/ballerina/modules/soap11/soap11.bal
index f6f5979..905bbcb 100644
--- a/ballerina/modules/soap11/soap11.bal
+++ b/ballerina/modules/soap11/soap11.bal
@@ -19,12 +19,13 @@ import soap;
import ballerina/http;
import ballerina/mime;
import ballerina/jballerina.java;
+import soap.wssec;
# Object for the basic SOAP 1.1 client endpoint.
public isolated client class Client {
private final http:Client soapClient;
- private final readonly & soap:InboundSecurityConfig|soap:InboundSecurityConfig[] inboundSecurity;
- private final readonly & soap:OutboundSecurityConfig outboundSecurity;
+ private final readonly & soap:OutboundSecurityConfig|soap:OutboundSecurityConfig[] outboundSecurity;
+ private final readonly & soap:InboundSecurityConfig inboundSecurity;
# Gets invoked during object initialization.
#
@@ -71,7 +72,7 @@ public isolated client class Client {
xml mimeEntity = body is xml ? body : check body[0].getXml();
lock {
xml envelope = body is xml ? body.clone() : mimeEntity.clone();
- securedBody = check soap:applySecurityPolicies(self.inboundSecurity.clone(), envelope.clone(), false);
+ securedBody = check soap:applySecurityPolicies(self.outboundSecurity.clone(), envelope.clone(), false);
}
xml|mime:Entity[] response;
if body is mime:Entity[] {
@@ -81,13 +82,13 @@ public isolated client class Client {
response = check soap:sendReceive(securedBody, self.soapClient, action, headers, path, false);
}
lock {
- soap:OutboundSecurityConfig? outboundSecurity = self.outboundSecurity.clone();
+ wssec:InboundConfig? inboundSecurity = self.inboundSecurity.clone();
do {
- if outboundSecurity is soap:OutboundSecurityConfig && outboundSecurity != {} {
+ if inboundSecurity is wssec:InboundConfig && inboundSecurity != {} {
if response is xml {
- return check soap:applyOutboundConfig(outboundSecurity.clone(), response.clone(), false);
+ return check soap:applyInboundConfig(inboundSecurity.clone(), response.clone(), false);
} else {
- return check soap:applyOutboundConfig(outboundSecurity.clone(),
+ return check soap:applyInboundConfig(inboundSecurity.clone(),
check response[0].getXml().clone(), false);
}
}
@@ -119,7 +120,7 @@ public isolated client class Client {
xml mimeEntity = body is xml ? body : check body[0].getXml();
lock {
xml envelope = body is xml ? body.clone() : mimeEntity.clone();
- securedBody = check soap:applySecurityPolicies(self.inboundSecurity.clone(), envelope.clone(), false);
+ securedBody = check soap:applySecurityPolicies(self.outboundSecurity.clone(), envelope.clone(), false);
}
return check soap:sendOnly(securedBody, self.soapClient, action, headers, path, false);
} on fail error soapError {
diff --git a/ballerina/modules/soap11/tests/http_secured_service.bal b/ballerina/modules/soap11/tests/http_secured_service.bal
index 4b04cb7..1b0696f 100644
--- a/ballerina/modules/soap11/tests/http_secured_service.bal
+++ b/ballerina/modules/soap11/tests/http_secured_service.bal
@@ -18,11 +18,7 @@ import ballerina/http;
service / on new http:Listener(9091) {
- resource function post .() returns xml|error {
- return xml `soap:MustUnderstandSystem.Web.Services.Protocols.SoapHeaderException: SOAP header Security was not understood.
- at System.Web.Services.Protocols.SoapHeaderHandling.SetHeaderMembers(SoapHeaderCollection headers, Object target, SoapHeaderMapping[] mappings, SoapHeaderDirection direction, Boolean client)
- at System.Web.Services.Protocols.SoapServerProtocol.CreateServerInstance()
- at System.Web.Services.Protocols.WebServiceHandler.Invoke()
- at System.Web.Services.Protocols.WebServiceHandler.CoreProcessRequest()`;
+ resource function post .(http:Request request) returns xml|error {
+ return check request.getXmlPayload();
}
}
diff --git a/ballerina/modules/soap11/tests/http_soap_service.bal b/ballerina/modules/soap11/tests/http_soap_service.bal
index bda5b79..54efeec 100644
--- a/ballerina/modules/soap11/tests/http_soap_service.bal
+++ b/ballerina/modules/soap11/tests/http_soap_service.bal
@@ -65,32 +65,12 @@ service / on new http:Listener(9090) {
resource function post getSecuredMimePayload(http:Request request) returns http:Response|error {
xml payload = check (check request.getBodyParts())[0].getXml();
- xml applyOutboundConfig = check soap:applyOutboundConfig(
- {
- verificationKey: clientPublicKey,
- signatureAlgorithm: soap:RSA_SHA256,
- decryptionAlgorithm: soap:RSA_ECB,
- decryptionKey: serverPrivateKey
- },
- payload,
- false
- );
- xml securedEnv = check soap:applySecurityPolicies(
- {
- signatureAlgorithm: soap:RSA_SHA256,
- encryptionAlgorithm: soap:RSA_ECB,
- signatureKey: serverPrivateKey,
- encryptionKey: clientPublicKey
- },
- applyOutboundConfig,
- false
- );
http:Response response = new;
mime:Entity[] mtomMessage = [];
mime:Entity envelope = new;
check envelope.setContentType("application/xop+xml");
envelope.setContentId("");
- envelope.setBody(securedEnv);
+ envelope.setBody(payload);
mtomMessage.push(envelope);
response.setBodyParts(mtomMessage);
response.setPayload(mtomMessage);
@@ -99,25 +79,20 @@ service / on new http:Listener(9090) {
resource function post getSecuredPayload(http:Request request) returns xml|error {
xml payload = check request.getXmlPayload();
- xml applyOutboundConfig = check soap:applyOutboundConfig(
+ xml applyInboundConfig = check soap:applyInboundConfig(
{
- verificationKey: clientPublicKey,
- signatureAlgorithm: soap:RSA_SHA256,
- decryptionAlgorithm: soap:RSA_ECB,
- decryptionKey: serverPrivateKey
+ decryptKeystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ signatureKeystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ }
},
payload,
false
);
- return check soap:applySecurityPolicies(
- {
- signatureAlgorithm: soap:RSA_SHA256,
- encryptionAlgorithm: soap:RSA_ECB,
- signatureKey: serverPrivateKey,
- encryptionKey: clientPublicKey
- },
- applyOutboundConfig,
- false
- );
+ return applyInboundConfig;
}
}
diff --git a/ballerina/modules/soap11/tests/soap11_client_test.bal b/ballerina/modules/soap11/tests/soap11_client_test.bal
index 2bbe88d..21d5271 100644
--- a/ballerina/modules/soap11/tests/soap11_client_test.bal
+++ b/ballerina/modules/soap11/tests/soap11_client_test.bal
@@ -32,6 +32,10 @@ const string X509_KEY_STORE_PATH_2 = "modules/wssec/tests/resources/x509_certifi
const wssec:TransportBindingConfig TRANSPORT_BINDING = "TransportBinding";
const wssec:NoPolicy NO_POLICY = "NoPolicy";
+const KEY_STORE_PATH_2 = "modules/wssec/tests/resources/keystore.jks";
+const ALIAS = "mykey";
+const PASSWORD = "password";
+
const crypto:KeyStore clientKeyStore = {
path: X509_KEY_STORE_PATH_2,
password: KEY_PASSWORD
@@ -209,8 +213,8 @@ function testSendOnlyError() returns error? {
function testSendReceive() returns error? {
Client soapClient = check new ("http://localhost:9090",
{
- inboundSecurity: NO_POLICY,
- outboundSecurity: {}
+ outboundSecurity: NO_POLICY,
+ inboundSecurity: {}
}
);
@@ -235,8 +239,8 @@ function testSendReceive() returns error? {
function testSendReceiveWithInvalidAction() returns error? {
Client soapClient = check new ("http://localhost:9090",
{
- inboundSecurity: NO_POLICY,
- outboundSecurity: {}
+ outboundSecurity: NO_POLICY,
+ inboundSecurity: {}
}
);
@@ -287,7 +291,7 @@ function testSendReceiveWithHeaders() returns error? {
}
function testTransportBindingError() returns error? {
Client|Error soapClient = new ("http://localhost:9090",
- inboundSecurity = TRANSPORT_BINDING
+ outboundSecurity = TRANSPORT_BINDING
);
test:assertTrue(soapClient is Error);
test:assertEquals((soapClient).message(), SOAP_CLIENT_ERROR);
@@ -298,7 +302,7 @@ function testTransportBindingError() returns error? {
}
function testTransportBindingError2() returns error? {
Client|Error soapClient = new ("http://localhost:9090",
- inboundSecurity = [
+ outboundSecurity = [
TRANSPORT_BINDING
]
);
@@ -326,145 +330,21 @@ function testSendReceiveError() returns error? {
test:assertEquals((response).message(), SOAP_ERROR);
}
-@test:Config {
- groups: ["soap11", "send_receive"]
-}
-function testSendReceiveWithTimestampTokenSecurity() returns error? {
- Client soapClient = check new ("http://localhost:9091",
- {
- inboundSecurity: [
- {
- timeToLive: 600
- }
- ]
- }
- );
- xml body = xml `
-
-
- 2
- 3
-
-
- `;
- xml response = check soapClient->sendReceive(body, "http://tempuri.org/Add");
- xml expected = xml `soap:MustUnderstandSystem.Web.Services.Protocols.SoapHeaderException: SOAP header Security was not understood.
- at System.Web.Services.Protocols.SoapHeaderHandling.SetHeaderMembers(SoapHeaderCollection headers, Object target, SoapHeaderMapping[] mappings, SoapHeaderDirection direction, Boolean client)
- at System.Web.Services.Protocols.SoapServerProtocol.CreateServerInstance()
- at System.Web.Services.Protocols.WebServiceHandler.Invoke()
- at System.Web.Services.Protocols.WebServiceHandler.CoreProcessRequest()`;
- test:assertEquals(response.toString(), expected.toString());
-}
-
@test:Config {
groups: ["soap11", "send_receive"]
}
function testSendReceiveWithUsernameTokenSecurity() returns error? {
Client soapClient = check new ("http://localhost:9091",
{
- inboundSecurity: {
+ outboundSecurity: {
username: "user",
password: "password",
passwordType: soap:TEXT
},
- outboundSecurity: {}
- }
- );
- xml body = xml `
-
-
- 2
- 3
-
-
- `;
- xml response = check soapClient->sendReceive(body, "http://tempuri.org/Add");
- xml expected = xml `soap:MustUnderstandSystem.Web.Services.Protocols.SoapHeaderException: SOAP header Security was not understood.
- at System.Web.Services.Protocols.SoapHeaderHandling.SetHeaderMembers(SoapHeaderCollection headers, Object target, SoapHeaderMapping[] mappings, SoapHeaderDirection direction, Boolean client)
- at System.Web.Services.Protocols.SoapServerProtocol.CreateServerInstance()
- at System.Web.Services.Protocols.WebServiceHandler.Invoke()
- at System.Web.Services.Protocols.WebServiceHandler.CoreProcessRequest()`;
- test:assertEquals(response.toString(), expected.toString());
-}
-
-@test:Config {
- groups: ["soap11", "send_receive"]
-}
-function testSendReceiveWithAsymmetricBindingSecurity() returns error? {
- crypto:KeyStore serverKeyStore = {
- path: X509_KEY_STORE_PATH,
- password: KEY_PASSWORD
- };
-
- crypto:PublicKey serverPublicKey = check crypto:decodeRsaPublicKeyFromTrustStore(serverKeyStore, KEY_ALIAS);
-
- crypto:KeyStore clientKeyStore = {
- path: X509_KEY_STORE_PATH_2,
- password: KEY_PASSWORD
- };
- crypto:PrivateKey clientPrivateKey = check crypto:decodeRsaPrivateKeyFromKeyStore(clientKeyStore, KEY_ALIAS, KEY_PASSWORD);
-
- Client soapClient = check new ("http://localhost:9091",
- {
- inboundSecurity: {
- signatureAlgorithm: soap:RSA_SHA256,
- encryptionAlgorithm: soap:RSA_ECB,
- signatureKey: clientPrivateKey,
- encryptionKey: serverPublicKey
- }
- }
- );
-
- xml body = xml `
-
-
- 2
- 3
-
-
- `;
- xml response = check soapClient->sendReceive(body, "http://tempuri.org/Add");
- xml expected = xml `soap:MustUnderstandSystem.Web.Services.Protocols.SoapHeaderException: SOAP header Security was not understood.
- at System.Web.Services.Protocols.SoapHeaderHandling.SetHeaderMembers(SoapHeaderCollection headers, Object target, SoapHeaderMapping[] mappings, SoapHeaderDirection direction, Boolean client)
- at System.Web.Services.Protocols.SoapServerProtocol.CreateServerInstance()
- at System.Web.Services.Protocols.WebServiceHandler.Invoke()
- at System.Web.Services.Protocols.WebServiceHandler.CoreProcessRequest()`;
- test:assertEquals(response.toString(), expected.toString());
-}
-
-@test:Config {
- groups: ["soap11", "send_receive"]
-}
-function testSendReceiveWithSymmetricBindingSecurity() returns error? {
- crypto:KeyStore serverKeyStore = {
- path: X509_KEY_STORE_PATH,
- password: KEY_PASSWORD
- };
- crypto:PublicKey serverPublicKey = check crypto:decodeRsaPublicKeyFromTrustStore(serverKeyStore, KEY_ALIAS);
-
- crypto:KeyStore keyStore = {
- path: KEY_STORE_PATH,
- password: KEY_PASSWORD
- };
- crypto:PrivateKey symmetricKey = check crypto:decodeRsaPrivateKeyFromKeyStore(keyStore, KEY_ALIAS, KEY_PASSWORD);
-
- Client soapClient = check new ("http://localhost:9091",
- {
- inboundSecurity: {
- signatureAlgorithm: soap:RSA_SHA256,
- encryptionAlgorithm: soap:RSA_ECB,
- symmetricKey: symmetricKey,
- servicePublicKey: serverPublicKey
- }
+ inboundSecurity: {}
}
);
- xml body = xml `
@@ -474,13 +354,10 @@ function testSendReceiveWithSymmetricBindingSecurity() returns error? {
`;
- xml response = check soapClient->sendReceive(body, "http://tempuri.org/Add");
- xml expected = xml `soap:MustUnderstandSystem.Web.Services.Protocols.SoapHeaderException: SOAP header Security was not understood.
- at System.Web.Services.Protocols.SoapHeaderHandling.SetHeaderMembers(SoapHeaderCollection headers, Object target, SoapHeaderMapping[] mappings, SoapHeaderDirection direction, Boolean client)
- at System.Web.Services.Protocols.SoapServerProtocol.CreateServerInstance()
- at System.Web.Services.Protocols.WebServiceHandler.Invoke()
- at System.Web.Services.Protocols.WebServiceHandler.CoreProcessRequest()`;
- test:assertEquals(response.toString(), expected.toString());
+ xml response = check soapClient->sendReceive(envelope, "http://tempuri.org/Add");
+ xmlns "http://schemas.xmlsoap.org/soap/envelope" as soap11;
+ error? assertUsernameToken = soap:assertUsernameToken(response.toString(), "user", "password", soap:TEXT, (envelope//*).toString());
+ test:assertTrue(assertUsernameToken !is error);
}
@test:Config {
@@ -491,7 +368,7 @@ function testSoapEndpoint() returns error? {
string password = "password";
Client soapClient = check new ("http://localhost:9090",
{
- inboundSecurity: {
+ outboundSecurity: {
username: username,
password: password,
passwordType: wssec:TEXT
@@ -506,157 +383,44 @@ function testSoapEndpoint() returns error? {
@test:Config {
groups: ["soap11", "send_receive"]
}
-function testSoapReceiveWithSymmetricBindingAndOutboundConfig() returns error? {
- Client soapClient = check new ("http://localhost:9090",
- {
- inboundSecurity: {
- signatureAlgorithm: wssec:RSA_SHA256,
- encryptionAlgorithm: wssec:RSA_ECB,
- symmetricKey: symmetricKey,
- servicePublicKey: serverPublicKey
- },
- outboundSecurity: {
- verificationKey: publicKey,
- signatureAlgorithm: wssec:RSA_SHA256,
- decryptionAlgorithm: wssec:RSA_ECB,
- decryptionKey: publicKey
- }
- }
- );
- xml body = xml `23`;
- xml response = check soapClient->sendReceive(body, "http://tempuri.org/Add", path = "/getSamePayload");
- return soap:assertSymmetricBinding(response.toString(), string `23`);
-}
-
-@test:Config {
- groups: ["soap11", "send_receive"]
-}
-function testSendReceiveWithAsymmetricBindingAndOutboundConfig() returns error? {
+function testSoapReceiveWithAsymmetricBindingAndInboundConfig() returns error? {
+ xmlns "http://schemas.xmlsoap.org/soap/envelope/" as soap11;
Client soapClient = check new ("http://localhost:9090",
{
- inboundSecurity: {
- signatureAlgorithm: soap:RSA_SHA256,
- encryptionAlgorithm: soap:RSA_ECB,
- signatureKey: clientPrivateKey,
- encryptionKey: serverPublicKey
- },
outboundSecurity: {
- verificationKey: serverPublicKey,
- signatureAlgorithm: soap:RSA_SHA256,
- decryptionAlgorithm: soap:RSA_ECB,
- decryptionKey: clientPrivateKey
- }
- }
- );
- xml body = xml `23`;
- xml response = check soapClient->sendReceive(body, "http://tempuri.org/Add", path = "/getSecuredPayload");
- return soap:assertSymmetricBinding(response.toString(), string `23`);
-}
-
-@test:Config {
- groups: ["soap11", "send_receive", "mime"]
-}
-function testOutboundConfigWithMime2() returns error? {
- Client soapClient = check new ("http://localhost:9090",
- {
- inboundSecurity: {
- signatureAlgorithm: soap:RSA_SHA256,
- encryptionAlgorithm: soap:RSA_ECB,
- signatureKey: clientPrivateKey,
- encryptionKey: serverPublicKey
+ signatureConfig: {
+ keystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ privateKeyAlias: ALIAS,
+ privateKeyPassword: PASSWORD,
+ signatureAlgorithm: soap:RSA_SHA512,
+ canonicalizationAlgorithm: soap:C14N_EXCL_OMIT_COMMENTS,
+ digestAlgorithm: soap:SHA512
+ },
+ encryptionConfig: {
+ keystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ publicKeyAlias: ALIAS,
+ encryptionAlgorithm: wssec:AES_128
+ }
},
- outboundSecurity: {
- verificationKey: serverPublicKey,
- signatureAlgorithm: soap:RSA_SHA256,
- decryptionAlgorithm: soap:RSA_ECB,
- decryptionKey: clientPrivateKey
- }
- }
- );
- xml body = xml `
-
-
- 2
- 3
-
-
- `;
-
- mime:Entity[] mtomMessage = [];
- mime:Entity envelope = new;
- check envelope.setContentType("application/xop+xml");
- envelope.setContentId("");
- envelope.setBody(body);
- mtomMessage.push(envelope);
-
- mime:Entity bytesPart = new;
- string readContent = check io:fileReadString(FILE_PATH);
- bytesPart.setFileAsEntityBody(FILE_PATH);
- string|byte[]|io:ReadableByteChannel|mime:EncodeError bytes = mime:base64Encode(readContent.toBytes());
- if bytes !is byte[] {
- return error("error");
- }
- bytesPart.setBody(bytes);
- check bytesPart.setContentType("image/jpeg");
- bytesPart.setContentId("");
- mtomMessage.push(bytesPart);
- xml response = check soapClient->sendReceive(mtomMessage, "http://tempuri.org/Add", path = "/getSecuredMimePayload");
- xmlns "http://schemas.xmlsoap.org/soap/envelope/" as soap11;
- test:assertEquals(response/, body/);
-}
-
-@test:Config {
- groups: ["soap11", "send_receive", "mime"]
-}
-function testInvalidOutboundConfigWithMime() returns error? {
- Client soapClient = check new ("http://localhost:9090",
- {
inboundSecurity: {
- signatureAlgorithm: soap:RSA_SHA256,
- encryptionAlgorithm: soap:RSA_ECB,
- signatureKey: clientPrivateKey,
- encryptionKey: serverPublicKey
- },
- outboundSecurity: {
- verificationKey: clientPublicKey,
- signatureAlgorithm: soap:RSA_SHA256,
- decryptionAlgorithm: soap:RSA_ECB,
- decryptionKey: serverPrivateKey
+ decryptKeystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ signatureKeystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ }
}
}
);
- xml body = xml `
-
-
- 2
- 3
-
-
- `;
-
- mime:Entity[] mtomMessage = [];
- mime:Entity envelope = new;
- check envelope.setContentType("application/xop+xml");
- envelope.setContentId("");
- envelope.setBody(body);
- mtomMessage.push(envelope);
-
- mime:Entity bytesPart = new;
- string readContent = check io:fileReadString(FILE_PATH);
- bytesPart.setFileAsEntityBody(FILE_PATH);
- string|byte[]|io:ReadableByteChannel|mime:EncodeError bytes = mime:base64Encode(readContent.toBytes());
- if bytes !is byte[] {
- return error("error");
- }
- bytesPart.setBody(bytes);
- check bytesPart.setContentType("image/jpeg");
- bytesPart.setContentId("");
- mtomMessage.push(bytesPart);
- xml|Error response = soapClient->sendReceive(mtomMessage, "http://tempuri.org/Add", path = "/getSecuredMimePayload");
- test:assertTrue(response is Error);
- test:assertEquals((response).message(), "Outbound security configurations do not match with the SOAP response");
+ xml body = xml `23`;
+ xml response = check soapClient->sendReceive(body, "http://tempuri.org/Add", path = "/getSamePayload");
+ test:assertEquals((response/).toString(), (body/).toString());
}
diff --git a/ballerina/modules/soap12/Module.md b/ballerina/modules/soap12/Module.md
index 80b55f1..1957376 100644
--- a/ballerina/modules/soap12/Module.md
+++ b/ballerina/modules/soap12/Module.md
@@ -69,9 +69,10 @@ The SOAP client module introduces a robust framework for configuring security me
There are two primary security configurations available for SOAP clients:
-- `inboundSecurity`: This configuration is applied to the SOAP envelope when a request is made. It includes various ws security policies such as Username Token, Timestamp Token, X509 Token, Symmetric Binding, Asymmetric Binding, and Transport Binding, either individually or in combination with each other.
+- `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.
+
+- `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.
-- `outboundSecurity`: This configuration is applied to the SOAP envelope when a response is received. Its purpose is to decrypt the data within the envelope and verify the digital signature for security validation.
### Policies
@@ -87,7 +88,7 @@ These policies empower SOAP clients to enhance the security of their web service
### Security Policy Configuration Types
-#### Inbound Security Configurations
+#### Outbound Security Configurations
- `TimestampTokenConfig`: Represents the record for Timestamp Token policy.
- Fields:
@@ -107,22 +108,18 @@ These policies empower SOAP clients to enhance the security of their web service
- `EncryptionAlgorithm` encryptionAlgorithm : The algorithm to encrypt the SOAP envelope
- `string` x509Token : The path or token of the X509 certificate
-- `AsymmetricBindingConfig`: Represents the record for Username Token with Asymmetric Binding policy.
+- `AsymmetricBindingConfig`: Represents the record for Asymmetric Binding policy.
- Fields:
- - `crypto:PrivateKey` signatureKey : The private key to sign the SOAP envelope
- - `crypto:PublicKey` encryptionKey : The public key to encrypt the SOAP body
- - `SignatureAlgorithm` signatureAlgorithm : The algorithm to sign the SOAP envelope
- - `EncryptionAlgorithm` encryptionAlgorithm : The algorithm to encrypt the SOAP body
- - `string` x509Token : field description
+ - `SignatureConfig` signatureConfig : Configuration for applying digital signatures
+ - `EncryptionConfig` encryptionConfig : Configuration for applying encryption
+ - `string` x509Token : The path or token of the X509 certificate
-#### Outbound Security Configurations
+#### Inbound Security Configurations
-- `OutboundSecurityConfig`: Represents the record for outbound security configurations to verify and decrypt SOAP envelopes.
+- `InboundSecurityConfig`: Represents the record for outbound security configurations to verify and decrypt SOAP envelopes.
- Fields:
- - `crypto:PublicKey` verificationKey : The public key to verify the signature of the SOAP envelope
- - `crypto:PrivateKey`|`crypto:PublicKey` decryptionKey : The private key to decrypt the SOAP envelope
- - `SignatureAlgorithm` signatureAlgorithm : The algorithm to verify the SOAP envelope
- - `EncryptionAlgorithm` decryptionAlgorithm : The algorithm to decrypt the SOAP body
+ - `crypto:KeyStore` decryptKeystore - The keystore to decrypt the SOAP envelope
+ - `crypto:KeyStore` signatureKeystore - The keystore to verify the signature of the SOAP envelope
### Apply Security Policies
@@ -135,23 +132,36 @@ import ballerina/soap;
import ballerina/soap.soap12;
public function main() returns error? {
- crypto:PrivateKey clientPrivateKey = ...//
- crypto:PublicKey clientPublicKey = ...//
- crypto:PublicKey serverPublicKey = ...//
-
soap12:Client soapClient = check new ("http://www.secured-soap-endpoint.com",
{
- inboundSecurity: {
- signatureAlgorithm: soap:RSA_SHA256,
- encryptionAlgorithm: soap:RSA_ECB,
- signatureKey: clientPrivateKey,
- encryptionKey: serverPublicKey,
- },
outboundSecurity: {
- verificationKey: serverPublicKey,
- signatureAlgorithm: soap:RSA_SHA256,
- decryptionKey: clientPrivateKey,
- decryptionAlgorithm: soap:RSA_ECB
+ signatureConfig: {
+ keystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ privateKeyAlias: ALIAS,
+ privateKeyPassword: PASSWORD,
+ signatureAlgorithm: wssec:RSA_SHA1
+ },
+ encryptionConfig: {
+ keystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ publicKeyAlias: ALIAS,
+ encryptionAlgorithm: wssec:AES_128
+ }
+ },
+ inboundSecurity: {
+ decryptKeystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ signatureKeystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ }
}
});
}
diff --git a/ballerina/modules/soap12/soap12.bal b/ballerina/modules/soap12/soap12.bal
index 44d4402..4a2db4a 100644
--- a/ballerina/modules/soap12/soap12.bal
+++ b/ballerina/modules/soap12/soap12.bal
@@ -19,12 +19,13 @@ import soap;
import ballerina/http;
import ballerina/mime;
import ballerina/jballerina.java;
+import soap.wssec;
# Object for the basic SOAP 1.2 client endpoint.
public isolated client class Client {
private final http:Client soapClient;
- private final readonly & soap:InboundSecurityConfig|soap:InboundSecurityConfig[] inboundSecurity;
- private final readonly & soap:OutboundSecurityConfig outboundSecurity;
+ private final readonly & soap:OutboundSecurityConfig|soap:OutboundSecurityConfig[] outboundSecurity;
+ private final readonly & soap:InboundSecurityConfig inboundSecurity;
# Gets invoked during object initialization.
#
@@ -36,8 +37,8 @@ public isolated client class Client {
check soap:validateTransportBindingPolicy(config);
self.soapClient = check new (url, config.httpConfig);
readonly & soap:ClientConfig readonlyConfig = soap:getReadOnlyClientConfig(config);
- self.inboundSecurity = readonlyConfig.inboundSecurity;
self.outboundSecurity = readonlyConfig.outboundSecurity;
+ self.inboundSecurity = readonlyConfig.inboundSecurity;
} on fail var err {
return error Error(SOAP_CLIENT_ERROR, err);
}
@@ -64,14 +65,14 @@ public isolated client class Client {
} external;
isolated function generateResponse(xml|mime:Entity[] body, string? action = (),
- map headers = {}, string path = "")
+ map headers = {}, string path = "")
returns xml|mime:Entity[]|Error {
do {
xml securedBody;
xml mimeEntity = body is xml ? body : check body[0].getXml();
lock {
xml envelope = body is xml ? body.clone() : mimeEntity.clone();
- securedBody = check soap:applySecurityPolicies(self.inboundSecurity.clone(), envelope.clone());
+ securedBody = check soap:applySecurityPolicies(self.outboundSecurity.clone(), envelope.clone());
}
xml|mime:Entity[] response;
if body is mime:Entity[] {
@@ -81,13 +82,13 @@ public isolated client class Client {
response = check soap:sendReceive(securedBody, self.soapClient, action, headers, path);
}
lock {
- soap:OutboundSecurityConfig? outboundSecurity = self.outboundSecurity.clone();
+ wssec:InboundConfig? inboundSecurity = self.inboundSecurity.clone();
do {
- if outboundSecurity is soap:OutboundSecurityConfig && outboundSecurity != {} {
+ if inboundSecurity is wssec:InboundConfig && inboundSecurity != {} {
if response is xml {
- return check soap:applyOutboundConfig(outboundSecurity.clone(), response.clone());
+ return check soap:applyInboundConfig(inboundSecurity.clone(), response.clone());
} else {
- return check soap:applyOutboundConfig(outboundSecurity.clone(),
+ return check soap:applyInboundConfig(inboundSecurity.clone(),
check response[0].getXml().clone());
}
}
@@ -119,7 +120,7 @@ public isolated client class Client {
xml mimeEntity = body is xml ? body : check body[0].getXml();
lock {
xml envelope = body is xml ? body.clone() : mimeEntity.clone();
- securedBody = check soap:applySecurityPolicies(self.inboundSecurity.clone(), envelope.clone());
+ securedBody = check soap:applySecurityPolicies(self.outboundSecurity.clone(), envelope.clone());
}
return check soap:sendOnly(securedBody, self.soapClient, action, headers, path);
} on fail error soapError {
diff --git a/ballerina/modules/soap12/tests/http_secured_service.bal b/ballerina/modules/soap12/tests/http_secured_service.bal
index 13ca84a..1159b35 100644
--- a/ballerina/modules/soap12/tests/http_secured_service.bal
+++ b/ballerina/modules/soap12/tests/http_secured_service.bal
@@ -18,12 +18,7 @@ import ballerina/http;
service / on new http:Listener(9091) {
- resource function post .() returns xml|error {
- return xml `soap:SenderSystem.Web.Services.Protocols.SoapException: Unable to handle request without a valid action parameter. Please supply a valid soap action.
- at System.Web.Services.Protocols.Soap12ServerProtocolHelper.RouteRequest()
- at System.Web.Services.Protocols.SoapServerProtocol.RouteRequest(SoapServerMessage message)
- at System.Web.Services.Protocols.SoapServerProtocol.Initialize()
- at System.Web.Services.Protocols.ServerProtocol.SetContext(Type type, HttpContext context, HttpRequest request, HttpResponse response)
- at System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type, HttpContext context, HttpRequest request, HttpResponse response, Boolean& abortProcessing)`;
+ resource function post .(http:Request request) returns xml|error {
+ return check request.getXmlPayload();
}
}
diff --git a/ballerina/modules/soap12/tests/http_soap_service.bal b/ballerina/modules/soap12/tests/http_soap_service.bal
index 162544c..bbe40b3 100644
--- a/ballerina/modules/soap12/tests/http_soap_service.bal
+++ b/ballerina/modules/soap12/tests/http_soap_service.bal
@@ -78,52 +78,43 @@ service / on new http:Listener(9090) {
resource function post getSecuredPayload(http:Request request) returns xml|error {
xml payload = check request.getXmlPayload();
- xml applyOutboundConfig = check soap:applyOutboundConfig(
+ xml applyInboundConfig = check soap:applyInboundConfig(
{
- verificationKey: clientPublicKey,
- signatureAlgorithm: soap:RSA_SHA256,
- decryptionAlgorithm: soap:RSA_ECB,
- decryptionKey: serverPrivateKey
+ decryptKeystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ signatureKeystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ }
},
payload
);
- return check soap:applySecurityPolicies(
- {
- signatureAlgorithm: soap:RSA_SHA256,
- encryptionAlgorithm: soap:RSA_ECB,
- signatureKey: serverPrivateKey,
- encryptionKey: clientPublicKey
- },
- applyOutboundConfig
- );
+ return applyInboundConfig;
}
resource function post getSecuredMimePayload(http:Request request) returns http:Response|error {
xml payload = check (check request.getBodyParts())[0].getXml();
- xml applyOutboundConfig = check soap:applyOutboundConfig(
+ xml applyInboundConfig = check soap:applyInboundConfig(
{
- verificationKey: clientPublicKey,
- signatureAlgorithm: soap:RSA_SHA256,
- decryptionAlgorithm: soap:RSA_ECB,
- decryptionKey: serverPrivateKey
+ decryptKeystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ signatureKeystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ }
},
payload
);
- xml securedEnv = check soap:applySecurityPolicies(
- {
- signatureAlgorithm: soap:RSA_SHA256,
- encryptionAlgorithm: soap:RSA_ECB,
- signatureKey: serverPrivateKey,
- encryptionKey: clientPublicKey
- },
- applyOutboundConfig
- );
http:Response response = new;
mime:Entity[] mtomMessage = [];
mime:Entity envelope = new;
check envelope.setContentType("application/xop+xml");
envelope.setContentId("");
- envelope.setBody(securedEnv);
+ envelope.setBody(applyInboundConfig);
mtomMessage.push(envelope);
response.setBodyParts(mtomMessage);
response.setPayload(mtomMessage);
diff --git a/ballerina/modules/soap12/tests/soap12_client_test.bal b/ballerina/modules/soap12/tests/soap12_client_test.bal
index 21f50f8..ef9eba9 100644
--- a/ballerina/modules/soap12/tests/soap12_client_test.bal
+++ b/ballerina/modules/soap12/tests/soap12_client_test.bal
@@ -32,6 +32,10 @@ const X509_KEY_STORE_PATH_2 = "modules/wssec/tests/resources/x509_certificate_2.
const wssec:TransportBindingConfig TRANSPORT_BINDING = "TransportBinding";
const wssec:NoPolicy NO_POLICY = "NoPolicy";
+const KEY_STORE_PATH_2 = "modules/wssec/tests/resources/keystore.jks";
+const ALIAS = "mykey";
+const PASSWORD = "password";
+
const crypto:KeyStore clientKeyStore = {
path: X509_KEY_STORE_PATH_2,
password: KEY_PASSWORD
@@ -321,7 +325,7 @@ function testSendOnly12WithoutSoapAction() returns error? {
groups: ["soap12"]
}
function testTransportBindingError() returns error? {
- Client|Error soapClient = new ("http://localhost:9091", inboundSecurity = TRANSPORT_BINDING);
+ Client|Error soapClient = new ("http://localhost:9091", outboundSecurity = TRANSPORT_BINDING);
test:assertTrue(soapClient is Error);
test:assertEquals((soapClient).message(), SOAP_CLIENT_ERROR);
}
@@ -331,7 +335,7 @@ function testTransportBindingError() returns error? {
}
function testTransportBindingError2() returns error? {
Client|Error soapClient = new ("http://localhost:9091",
- inboundSecurity = [
+ outboundSecurity = [
TRANSPORT_BINDING
]
);
@@ -359,55 +363,21 @@ function testSendReceiveError() returns error? {
test:assertEquals((response).message(), SOAP_ERROR);
}
-@test:Config {
- groups: ["soap12", "send_receive"]
-}
-function testSendReceiveWithTimestampTokenSecurity() returns error? {
- Client soapClient = check new ("http://localhost:9091",
- {
- inboundSecurity: [
- {
- timeToLive: 600
- }
- ]
- }
- );
- xml body = xml `
-
-
- 2
- 3
-
-
- `;
- xml response = check soapClient->sendReceive(body);
- xml expected = xml `soap:SenderSystem.Web.Services.Protocols.SoapException: Unable to handle request without a valid action parameter. Please supply a valid soap action.
- at System.Web.Services.Protocols.Soap12ServerProtocolHelper.RouteRequest()
- at System.Web.Services.Protocols.SoapServerProtocol.RouteRequest(SoapServerMessage message)
- at System.Web.Services.Protocols.SoapServerProtocol.Initialize()
- at System.Web.Services.Protocols.ServerProtocol.SetContext(Type type, HttpContext context, HttpRequest request, HttpResponse response)
- at System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type, HttpContext context, HttpRequest request, HttpResponse response, Boolean& abortProcessing)`;
-
- test:assertEquals(response.toString(), expected.toString());
-}
-
@test:Config {
groups: ["soap12", "send_receive"]
}
function testSendReceiveWithUsernameTokenSecurity() returns error? {
Client soapClient = check new ("http://localhost:9091",
{
- inboundSecurity: {
+ outboundSecurity: {
username: "user",
password: "password",
passwordType: soap:TEXT
},
- outboundSecurity: {}
+ inboundSecurity: {}
}
);
- xml body = xml `
@@ -417,109 +387,10 @@ function testSendReceiveWithUsernameTokenSecurity() returns error? {
`;
- xml response = check soapClient->sendReceive(body);
- xml expected = xml `soap:SenderSystem.Web.Services.Protocols.SoapException: Unable to handle request without a valid action parameter. Please supply a valid soap action.
- at System.Web.Services.Protocols.Soap12ServerProtocolHelper.RouteRequest()
- at System.Web.Services.Protocols.SoapServerProtocol.RouteRequest(SoapServerMessage message)
- at System.Web.Services.Protocols.SoapServerProtocol.Initialize()
- at System.Web.Services.Protocols.ServerProtocol.SetContext(Type type, HttpContext context, HttpRequest request, HttpResponse response)
- at System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type, HttpContext context, HttpRequest request, HttpResponse response, Boolean& abortProcessing)`;
-
- test:assertEquals(response.toString(), expected.toString());
-}
-
-@test:Config {
- groups: ["soap12", "send_receive"]
-}
-function testSendReceiveWithAsymmetricBindingSecurity() returns error? {
- crypto:KeyStore serverKeyStore = {
- path: X509_KEY_STORE_PATH,
- password: KEY_PASSWORD
- };
-
- crypto:PublicKey serverPublicKey = check crypto:decodeRsaPublicKeyFromTrustStore(serverKeyStore, KEY_ALIAS);
-
- crypto:KeyStore clientKeyStore = {
- path: X509_KEY_STORE_PATH_2,
- password: KEY_PASSWORD
- };
- crypto:PrivateKey clientPrivateKey = check crypto:decodeRsaPrivateKeyFromKeyStore(clientKeyStore, KEY_ALIAS, KEY_PASSWORD);
-
- Client soapClient = check new ("http://localhost:9091",
- {
- inboundSecurity: {
- signatureAlgorithm: soap:RSA_SHA256,
- encryptionAlgorithm: soap:RSA_ECB,
- signatureKey: clientPrivateKey,
- encryptionKey: serverPublicKey
- }
- }
- );
- xml body = xml `
-
-
- 2
- 3
-
-
- `;
- xml response = check soapClient->sendReceive(body);
- xml expected = xml `soap:SenderSystem.Web.Services.Protocols.SoapException: Unable to handle request without a valid action parameter. Please supply a valid soap action.
- at System.Web.Services.Protocols.Soap12ServerProtocolHelper.RouteRequest()
- at System.Web.Services.Protocols.SoapServerProtocol.RouteRequest(SoapServerMessage message)
- at System.Web.Services.Protocols.SoapServerProtocol.Initialize()
- at System.Web.Services.Protocols.ServerProtocol.SetContext(Type type, HttpContext context, HttpRequest request, HttpResponse response)
- at System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type, HttpContext context, HttpRequest request, HttpResponse response, Boolean& abortProcessing)`;
-
- test:assertEquals(response.toString(), expected.toString());
-}
-
-@test:Config {
- groups: ["soap12", "send_receive"]
-}
-function testSendReceiveWithSymmetricBindingSecurity() returns error? {
- crypto:KeyStore serverKeyStore = {
- path: X509_KEY_STORE_PATH,
- password: KEY_PASSWORD
- };
- crypto:PublicKey serverPublicKey = check crypto:decodeRsaPublicKeyFromTrustStore(serverKeyStore, KEY_ALIAS);
-
- crypto:KeyStore keyStore = {
- path: KEY_STORE_PATH,
- password: KEY_PASSWORD
- };
- crypto:PrivateKey symmetricKey = check crypto:decodeRsaPrivateKeyFromKeyStore(keyStore, KEY_ALIAS, KEY_PASSWORD);
-
- Client soapClient = check new ("http://localhost:9091",
- {
- inboundSecurity: {
- signatureAlgorithm: soap:RSA_SHA256,
- encryptionAlgorithm: soap:RSA_ECB,
- symmetricKey: symmetricKey,
- servicePublicKey: serverPublicKey
- }
- }
- );
- xml body = xml `
-
-
- 2
- 3
-
-
- `;
- xml response = check soapClient->sendReceive(body);
- xml expected = xml `soap:SenderSystem.Web.Services.Protocols.SoapException: Unable to handle request without a valid action parameter. Please supply a valid soap action.
- at System.Web.Services.Protocols.Soap12ServerProtocolHelper.RouteRequest()
- at System.Web.Services.Protocols.SoapServerProtocol.RouteRequest(SoapServerMessage message)
- at System.Web.Services.Protocols.SoapServerProtocol.Initialize()
- at System.Web.Services.Protocols.ServerProtocol.SetContext(Type type, HttpContext context, HttpRequest request, HttpResponse response)
- at System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type, HttpContext context, HttpRequest request, HttpResponse response, Boolean& abortProcessing)`;
- test:assertEquals(response.toString(), expected.toString());
+ xml response = check soapClient->sendReceive(envelope);
+ xmlns "http://www.w3.org/2003/05/soap-envelope" as soap12;
+ error? assertUsernameToken = soap:assertUsernameToken(response.toString(), "user", "password", soap:TEXT, (envelope//*).toString());
+ test:assertTrue(assertUsernameToken !is error);
}
@test:Config {
@@ -530,7 +401,7 @@ function testSoapEndpoint() returns error? {
string password = "password";
Client soapClient = check new ("http://localhost:9090",
{
- inboundSecurity: {
+ outboundSecurity: {
username: username,
password: password,
passwordType: wssec:TEXT
@@ -543,107 +414,46 @@ function testSoapEndpoint() returns error? {
}
@test:Config {
- groups: ["soap12", "send_receive"]
+ groups: ["soap12", "send_receive", "new2"]
}
-function testSoapReceiveWithSymmetricBindingAndOutboundConfig() returns error? {
- Client soapClient = check new ("http://localhost:9090",
+function testSoapReceiveWithAsymmetricBindingAndInboundConfig() returns error? {
+ xmlns "http://www.w3.org/2003/05/soap-envelope" as soap11;
+ Client soapClient = check new ("http://localhost:9091",
{
- inboundSecurity: {
- signatureAlgorithm: wssec:RSA_SHA256,
- encryptionAlgorithm: wssec:RSA_ECB,
- symmetricKey: symmetricKey,
- servicePublicKey: serverPublicKey
- },
outboundSecurity: {
- verificationKey: publicKey,
- signatureAlgorithm: wssec:RSA_SHA256,
- decryptionAlgorithm: wssec:RSA_ECB,
- decryptionKey: publicKey
- }
- }
- );
- xml body = xml `23`;
- xml response = check soapClient->sendReceive(body, "http://tempuri.org/Add", path = "/getSamePayload");
- return soap:assertSymmetricBinding(response.toString(), string `23`);
-}
-
-@test:Config {
- groups: ["soap12", "send_receive"]
-}
-function testSendReceiveWithAsymmetricBindingAndOutboundConfig() returns error? {
- Client soapClient = check new ("http://localhost:9090",
- {
- inboundSecurity: {
- signatureAlgorithm: soap:RSA_SHA256,
- encryptionAlgorithm: soap:RSA_ECB,
- signatureKey: clientPrivateKey,
- encryptionKey: serverPublicKey
+ signatureConfig: {
+ keystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ privateKeyAlias: ALIAS,
+ privateKeyPassword: PASSWORD,
+ signatureAlgorithm: soap:RSA_SHA512,
+ canonicalizationAlgorithm: soap:C14N_EXCL_OMIT_COMMENTS,
+ digestAlgorithm: soap:SHA512
+ },
+ encryptionConfig: {
+ keystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ publicKeyAlias: ALIAS,
+ encryptionAlgorithm: wssec:AES_128
+ }
},
- outboundSecurity: {
- verificationKey: serverPublicKey,
- signatureAlgorithm: soap:RSA_SHA256,
- decryptionAlgorithm: soap:RSA_ECB,
- decryptionKey: clientPrivateKey
- }
- }
- );
-
- xml body = xml `23`;
- xml response = check soapClient->sendReceive(body, "http://tempuri.org/Add", path = "/getSecuredPayload");
- return soap:assertSymmetricBinding(response.toString(), string `23`);
-}
-
-@test:Config {
- groups: ["soap12", "send_receive"]
-}
-function testInvalidOutboundConfigWithMime12() returns error? {
- Client soapClient = check new ("http://localhost:9090",
- {
inboundSecurity: {
- signatureAlgorithm: soap:RSA_SHA256,
- encryptionAlgorithm: soap:RSA_ECB,
- signatureKey: clientPrivateKey,
- encryptionKey: serverPublicKey
- },
- outboundSecurity: {
- verificationKey: clientPublicKey,
- signatureAlgorithm: soap:RSA_SHA256,
- decryptionAlgorithm: soap:RSA_ECB,
- decryptionKey: serverPrivateKey
+ decryptKeystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ signatureKeystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ }
}
}
);
- xml body = xml `
-
-
- 2
- 3
-
-
- `;
-
- mime:Entity[] mtomMessage = [];
- mime:Entity envelope = new;
- check envelope.setContentType("application/xop+xml");
- envelope.setContentId("");
- envelope.setBody(body);
- mtomMessage.push(envelope);
-
- mime:Entity bytesPart = new;
- string readContent = check io:fileReadString(FILE_PATH);
- bytesPart.setFileAsEntityBody(FILE_PATH);
- string|byte[]|io:ReadableByteChannel|mime:EncodeError bytes = mime:base64Encode(readContent.toBytes());
- if bytes !is byte[] {
- return error("error");
- }
- bytesPart.setBody(bytes);
- check bytesPart.setContentType("image/jpeg");
- bytesPart.setContentId("");
- mtomMessage.push(bytesPart);
-
- mime:Entity[]|Error response = soapClient->sendReceive(mtomMessage, "http://tempuri.org/Add", path = "/getSecuredMimePayload");
- test:assertTrue(response is Error);
- test:assertEquals((response).message(), "Outbound security configurations do not match with the SOAP response");
+ xml body = xml `23`;
+ xml response = check soapClient->sendReceive(body, "http://tempuri.org/Add");
+ test:assertEquals((response/).toString(), (body/).toString());
}
diff --git a/ballerina/modules/wssec/document.bal b/ballerina/modules/wssec/document.bal
index d70dd38..1f8fa38 100644
--- a/ballerina/modules/wssec/document.bal
+++ b/ballerina/modules/wssec/document.bal
@@ -16,7 +16,7 @@
import ballerina/jballerina.java;
-isolated class Document {
+public isolated class Document {
public isolated function init(xml xmlPayload) returns Error? {
handle|error documentBuilder = newDocument(self, xmlPayload);
@@ -25,6 +25,10 @@ isolated class Document {
}
}
+ public isolated function getEnvelope() returns xml|Error = @java:Method {
+ 'class: "org.wssec.DocumentBuilder"
+ } external;
+
public isolated function getEncryptedData() returns byte[] = @java:Method {
'class: "org.wssec.DocumentBuilder"
} external;
diff --git a/ballerina/modules/wssec/records.bal b/ballerina/modules/wssec/records.bal
index 8d9a3be..38bf16e 100644
--- a/ballerina/modules/wssec/records.bal
+++ b/ballerina/modules/wssec/records.bal
@@ -17,8 +17,8 @@
import ballerina/crypto;
# Union type of all the inbound web service security configurations.
-public type InboundSecurityConfig NoPolicy|UsernameTokenConfig|TimestampTokenConfig|SymmetricBindingConfig
- |AsymmetricBindingConfig|TransportBindingConfig;
+public type OutboundSecurityConfig NoPolicy|UsernameTokenConfig|TimestampTokenConfig|SymmetricBindingConfig
+ |TransportBindingConfig|AsymmetricBindingConfig;
# Represents the record for outbound security configurations to verify and decrypt SOAP envelopes.
#
@@ -26,7 +26,7 @@ public type InboundSecurityConfig NoPolicy|UsernameTokenConfig|TimestampTokenCon
# + decryptionKey - The private key to decrypt the SOAP envelope
# + signatureAlgorithm - The algorithm to verify the SOAP envelope
# + decryptionAlgorithm - The algorithm to decrypt the SOAP body
-public type OutboundSecurityConfig record {|
+public type InboundSecurityConfig record {|
crypto:PublicKey verificationKey?;
crypto:PrivateKey|crypto:PublicKey decryptionKey?;
SignatureAlgorithm signatureAlgorithm?;
@@ -66,19 +66,43 @@ public type SymmetricBindingConfig record {|
string x509Token?;
|};
-# Represents the record for Username Token with Asymmetric Binding policy.
+# Represents the record for Asymmetric Binding policy.
#
-# + signatureKey - The private key to sign the SOAP envelope
-# + encryptionKey - The public key to encrypt the SOAP body
-# + signatureAlgorithm - The algorithm to sign the SOAP envelope
-# + encryptionAlgorithm - The algorithm to encrypt the SOAP body
-# + x509Token - field description
+# + signatureConfig - Configuration for applying digital signatures
+# + encryptionConfig - Configuration for applying encryption
+# + x509Token - The path or token of the X509 certificate
public type AsymmetricBindingConfig record {|
- crypto:PrivateKey signatureKey?;
- crypto:PublicKey encryptionKey?;
+ SignatureConfig signatureConfig?;
+ EncryptionConfig encryptionConfig?;
+ string x509Token?;
+|};
+
+# Represents the record for signature configurations.
+#
+# + keystore - The keystore to store the private key
+# + privateKeyAlias - The alias of the private key
+# + privateKeyPassword - The password of the private key
+# + signatureAlgorithm - The algorithm to sign the SOAP envelope
+# + canonicalizationAlgorithm - The algorithm to canonicalize the SOAP envelope
+# + digestAlgorithm - The algorithm to digest the SOAP envelope
+public type SignatureConfig record {|
+ crypto:KeyStore keystore;
+ string privateKeyAlias;
+ string privateKeyPassword;
SignatureAlgorithm signatureAlgorithm?;
+ CanonicalizationAlgorithm canonicalizationAlgorithm = C14N_EXCL_OMIT_COMMENTS;
+ DigestAlgorithm digestAlgorithm = SHA1;
+|};
+
+# Represents the record for encryption configurations.
+#
+# + keystore - The keystore to store the public key
+# + publicKeyAlias - The alias of the public key
+# + encryptionAlgorithm - The algorithm to encrypt the SOAP envelope
+public type EncryptionConfig record {|
+ crypto:KeyStore keystore;
+ string publicKeyAlias;
EncryptionAlgorithm encryptionAlgorithm?;
- string x509Token?;
|};
# Represents the record for Transport Binding policy.
@@ -87,3 +111,12 @@ public type TransportBindingConfig "TransportBinding";
# Represents the record to send SOAP envelopes with no security policy.
public type NoPolicy "NoPolicy";
+
+# Represents the record for outbound security configurations to verify and decrypt SOAP envelopes.
+#
+# + decryptKeystore - The keystore to decrypt the SOAP envelope
+# + signatureKeystore - The keystore to verify the signature of the SOAP envelope
+public type InboundConfig record {|
+ crypto:KeyStore decryptKeystore?;
+ crypto:KeyStore signatureKeystore?;
+|};
diff --git a/ballerina/modules/wssec/tests/resources/certificate.pem b/ballerina/modules/wssec/tests/resources/certificate.pem
new file mode 100644
index 0000000..18d52b2
--- /dev/null
+++ b/ballerina/modules/wssec/tests/resources/certificate.pem
@@ -0,0 +1,26 @@
+Bag Attributes
+ friendlyName: mykey
+ localKeyID: 54 69 6D 65 20 31 37 32 38 32 32 31 33 34 37 35 35 38
+subject=C=Unknown, ST=Unknown, L=Unknown, O=Unknown, OU=Unknown, CN=Unknown
+issuer=C=Unknown, ST=Unknown, L=Unknown, O=Unknown, OU=Unknown, CN=Unknown
+-----BEGIN CERTIFICATE-----
+MIIDezCCAmOgAwIBAgIIZbI69qIsxNgwDQYJKoZIhvcNAQELBQAwbDEQMA4GA1UE
+BhMHVW5rbm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQ
+MA4GA1UEChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5r
+bm93bjAeFw0yNDEwMDYxMzI3MzhaFw0yNTEwMDYxMzI3MzhaMGwxEDAOBgNVBAYT
+B1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vua25vd24xEDAO
+BgNVBAoTB1Vua25vd24xEDAOBgNVBAsTB1Vua25vd24xEDAOBgNVBAMTB1Vua25v
+d24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7rrO9u6/H4VboCxbs
+WX7eF/Kbjhzjx61zd2gIot4t+/e7j4R/4Hejn9+cgB++NY3uHtJ5wlVYtSDn5XJO
+XwjyNClqv8adBCkiCiwGClzgd+pUk6w+8ObbCgT7NZzVU7oh6LNpzYZXYsr4FkPr
+tRwopksO1pFGMJtDxWEkUAIj/NjscwgTmZJ+Tt2ISWx8Vv0h3rYVSyLqHdgjIl/W
+FAPMbHgiPL2lqWRK7/sOUqtn+hHuj2W+T1rzSf70642Ng++DHKwiGc+N33AMXyvH
+0qkhCBytC1Bd6JeWwZaonZKkdWj/4qhWhLcKGxJWrMDLIDhEo/I2aB4DUgAEFgkv
+GaUNAgMBAAGjITAfMB0GA1UdDgQWBBTxqECeIvo1iOqIh+ewk2O9H9+PTDANBgkq
+hkiG9w0BAQsFAAOCAQEAGUbw159JMWFavJulqNaBzDe70Zd5Rtp+uGP9xgQN3Gqa
+TBK/UhlmnMJw+0ess9iHELDJsMAexcJFajZc2p2W3qCrGvWtMglB7FGWjJU9N5SQ
+eX1d5wXSLg4i2G0DFx6bQcRbbBqwoF392JQjx6aiPXfP90hp/R3OkznNUXhpFFmq
+AFFe/eg3RtI3aDBYxlDDHh92JxwVrq1QMh2vaGuLJFGV3AEa+Zn4lSRX5cB2NcxI
+1PZSCQx/cl8AO8x0WRyU+xvMVCtXG/Izz+iCUSnkC7tSVTAccaJgnIVPHRx+UkGm
+vBX2ttTLDhFUrDYMYEEyXu+aqmEIXPoIHwa2qevgtQ==
+-----END CERTIFICATE-----
diff --git a/ballerina/modules/wssec/tests/resources/invalid_keystore.jks b/ballerina/modules/wssec/tests/resources/invalid_keystore.jks
new file mode 100644
index 0000000..7d5958b
Binary files /dev/null and b/ballerina/modules/wssec/tests/resources/invalid_keystore.jks differ
diff --git a/ballerina/modules/wssec/tests/resources/keystore.jks b/ballerina/modules/wssec/tests/resources/keystore.jks
new file mode 100644
index 0000000..ce7009b
Binary files /dev/null and b/ballerina/modules/wssec/tests/resources/keystore.jks differ
diff --git a/ballerina/modules/wssec/tests/resources/keystore.p12 b/ballerina/modules/wssec/tests/resources/keystore.p12
new file mode 100644
index 0000000..d2fae6e
Binary files /dev/null and b/ballerina/modules/wssec/tests/resources/keystore.p12 differ
diff --git a/ballerina/modules/wssec/tests/resources/keystoretest.jks b/ballerina/modules/wssec/tests/resources/keystoretest.jks
new file mode 100644
index 0000000..d6d1618
Binary files /dev/null and b/ballerina/modules/wssec/tests/resources/keystoretest.jks differ
diff --git a/ballerina/modules/wssec/tests/resources/mykeystore.jks b/ballerina/modules/wssec/tests/resources/mykeystore.jks
new file mode 100644
index 0000000..9ab60ef
Binary files /dev/null and b/ballerina/modules/wssec/tests/resources/mykeystore.jks differ
diff --git a/ballerina/modules/wssec/tests/resources/private_key1.pem b/ballerina/modules/wssec/tests/resources/private_key1.pem
new file mode 100644
index 0000000..642ceb9
--- /dev/null
+++ b/ballerina/modules/wssec/tests/resources/private_key1.pem
@@ -0,0 +1,32 @@
+Bag Attributes
+ friendlyName: mykey
+ localKeyID: 54 69 6D 65 20 31 37 32 38 32 32 31 33 34 37 35 35 38
+Key Attributes:
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC7rrO9u6/H4Vbo
+CxbsWX7eF/Kbjhzjx61zd2gIot4t+/e7j4R/4Hejn9+cgB++NY3uHtJ5wlVYtSDn
+5XJOXwjyNClqv8adBCkiCiwGClzgd+pUk6w+8ObbCgT7NZzVU7oh6LNpzYZXYsr4
+FkPrtRwopksO1pFGMJtDxWEkUAIj/NjscwgTmZJ+Tt2ISWx8Vv0h3rYVSyLqHdgj
+Il/WFAPMbHgiPL2lqWRK7/sOUqtn+hHuj2W+T1rzSf70642Ng++DHKwiGc+N33AM
+XyvH0qkhCBytC1Bd6JeWwZaonZKkdWj/4qhWhLcKGxJWrMDLIDhEo/I2aB4DUgAE
+FgkvGaUNAgMBAAECggEALm7cfTZwGM2BSMtlknfZ0WyvUxjnwNrn6MdD788LlOjf
+s4GgUFrifpLRKdDxCYgKYz0w6XrQzq+RQo4bp5QPjIynKofjxXkADDHkDmKF8+r3
+CJG4baIAG3TxIo1zDbw3Mqh1qtl0QS5p9NLdXvVh0BTEQRmIu4rO/wdYLzm0Ld61
+nnB8TCxdgniJfFyHP86bZuOOtFT2X7FpDxP+4UMZzR+9rjvfFezuCZin8Gf4oq18
+Yf+6evBYSIPwAlAm9QbM5iwLREdVbAceNe1/utrIIl//OAH10DOzYGrLpLH2/D7v
+aYjWT8FlCt5Yspsv50W1m8f44xn+cpdVDsFzEt73QQKBgQDJtd8QCjohjNzViKn/
+LN43EYuvDH2tal+vg2lOrz8OcQDHiz8DFJzoxAwoSwcwcN+JPOVIJqKov+ztgVYq
+S1+9lK+6Gv4JasTcypPMCLN27bchp7KsZCBu2wHdr8sp19+vfEu1X48Ubb0fkX/c
+4huiAV1wjaaa+nmOpcA4/oo+VQKBgQDuMkgjqqEgsO56vM3iRM0A9stgVnUP3yyC
+vSL6pgblwROLO913l/bKDV5B1hXAFBcLLlTRGdMbVzNgnNpdZdwKkfufQfWyMKx1
+z2SoRlxgwlxrBtfmunHdMqLT+piwwuRLlbYWSmyDL9ghDEo/22oAHn57rJAZlmlb
+tHB/waCT2QKBgQClu+HD9CM/XdY1PU0wdVVAOhJjigfZbQWh2H+2Pxe4bfEOA8OK
+bG1gc3TpxnvpuVRyFq7tUZFkxg2OOC7sIXJQ+tJIP9VrN2b5Yxl9E8khdsB5zqho
+LPzZGOm3lLGBd/Y64g3ywMl3J5O1VH+SpdW+jxCPYlP6EsO+CUKfkcVU4QKBgQDm
+96Kz0vRCes4D/ae1y/jtAmHanHsOVN0YOMX+PZdamYmV7QqmuJf4/FV1iV21zsU5
+dkeQKnZlgHy1JeMnxWlEZqGSn6bajg/sfJmiAff5av2qWgxoEknurvbsjYYZgCFW
+mWji3G+0FWSBRyWIHf3+95K14XIpHYwz/BdKCjrmoQKBgDwoPA5+foz6BH/Ut/KV
+Hj+zqrJO8M0p4Ys4/+vB7r4Mcin8hcdY920dYxPmkmz2pMEnplOas8GZUzE/KyX5
+wOSNzobJN+Rj3q851+u1fgl/vO78nXod2e9tvojXVz9a8EW23i17fsRt9221Nfdv
+6RlOnqnMghUgVz8D7irlWLnD
+-----END PRIVATE KEY-----
diff --git a/ballerina/modules/wssec/tests/resources/xml/soap_envelope.xml b/ballerina/modules/wssec/tests/resources/xml/soap_envelope.xml
new file mode 100644
index 0000000..664d67b
--- /dev/null
+++ b/ballerina/modules/wssec/tests/resources/xml/soap_envelope.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+ 3c9c5c6d-2123-405f-ab25-7399001e9512
+ 2023-08-08T16:15:36.806+02:00
+
+ MunicipalityCitizenRight
+
+
+ 01051537140
+
+ 2024-08-08+02:00
+
+
+
+
diff --git a/ballerina/modules/wssec/tests/test_utils.bal b/ballerina/modules/wssec/tests/test_utils.bal
index 93eef26..14e1ae3 100644
--- a/ballerina/modules/wssec/tests/test_utils.bal
+++ b/ballerina/modules/wssec/tests/test_utils.bal
@@ -23,6 +23,7 @@ const PASSWORD = "password";
const KEY_ALIAS = "wss40";
const KEY_PASSWORD = "security";
+const SOAP_ENVELOPE_PATH = "modules/wssec/tests/resources/xml/soap_envelope.xml";
const PUBLIC_KEY_PATH = "modules/wssec/tests/resources/public_key.cer";
const PRIVATE_KEY_PATH = "modules/wssec/tests/resources/private_key.pem";
const KEY_STORE_PATH = "modules/wssec/tests/resources/wss40.p12";
@@ -31,6 +32,9 @@ const X509_PUBLIC_CERT_PATH_2 = "modules/wssec/tests/resources/x509_certificate_
const X509_KEY_STORE_PATH = "modules/wssec/tests/resources/x509_certificate.p12";
const X509_KEY_STORE_PATH_2 = "modules/wssec/tests/resources/x509_certificate_2.p12";
+const KEY_STORE_PATH_2 = "modules/wssec/tests/resources/keystore.jks";
+const ALIAS = "mykey";
+
const crypto:KeyStore clientKeyStore = {
path: X509_KEY_STORE_PATH_2,
password: KEY_PASSWORD
@@ -97,13 +101,14 @@ function assertSignatureWithX509(string securedEnvelope) {
}
function assertSignatureWithoutX509(string securedEnvelope) {
- string:RegExp signature = re `.*`;
- string:RegExp signatureInfo = re `.*`;
+ string:RegExp signature = re ``;
+ string:RegExp signatureInfo = re ``;
string:RegExp canonicalizationMethod = re ``;
string:RegExp signatureMethod = re ``;
string:RegExp transformMethod = re ``;
string:RegExp digestMethod = re ``;
- string:RegExp signatureValue = re `.*`;
+ string:RegExp digestValue = re `ds:DigestValue>`;
+ string:RegExp signatureValue = re ``;
test:assertTrue(securedEnvelope.includesMatch(signature));
test:assertTrue(securedEnvelope.includesMatch(signatureInfo));
@@ -111,31 +116,28 @@ function assertSignatureWithoutX509(string securedEnvelope) {
test:assertTrue(securedEnvelope.includesMatch(signatureMethod));
test:assertTrue(securedEnvelope.includesMatch(transformMethod));
test:assertTrue(securedEnvelope.includesMatch(digestMethod));
+ test:assertTrue(securedEnvelope.includesMatch(digestValue));
test:assertTrue(securedEnvelope.includesMatch(signatureValue));
}
function assertEncryptedSymmetricKey(string securedEnvelope) {
- string:RegExp encryptedKey = re `.*`;
+ string:RegExp encryptedKey = re ``;
string:RegExp encryptionMethod = re ``;
- string:RegExp keyInfo = re ``;
- string:RegExp cipherData = re `.*`;
+ string:RegExp cipherData = re ``;
test:assertTrue(securedEnvelope.includesMatch(encryptedKey));
test:assertTrue(securedEnvelope.includesMatch(encryptionMethod));
- test:assertTrue(securedEnvelope.includesMatch(keyInfo));
test:assertTrue(securedEnvelope.includesMatch(cipherData));
}
function assertEncryptedPart(string securedEnvelope) {
string:RegExp encryptedData = re ``;
- string:RegExp keyInfo = re ``;
- string:RegExp cipherData = re `.*`;
- string:RegExp cipherValue = re `.*`;
+ string:RegExp cipherData = re ``;
+ string:RegExp cipherValue = re ``;
test:assertTrue(securedEnvelope.includesMatch(encryptedData));
test:assertTrue(securedEnvelope.includesMatch(encMethod));
- test:assertTrue(securedEnvelope.includesMatch(keyInfo));
test:assertTrue(securedEnvelope.includesMatch(cipherData));
test:assertTrue(securedEnvelope.includesMatch(cipherValue));
}
diff --git a/ballerina/modules/wssec/tests/ws_security_tests.bal b/ballerina/modules/wssec/tests/ws_security_tests.bal
index 29addfa..593eda6 100644
--- a/ballerina/modules/wssec/tests/ws_security_tests.bal
+++ b/ballerina/modules/wssec/tests/ws_security_tests.bal
@@ -17,6 +17,7 @@
import ballerina/crypto;
import ballerina/test;
import ballerina/lang.regexp;
+import ballerina/io;
@test:Config {
groups: ["timestamp_token"]
@@ -234,7 +235,7 @@ function testSymmetricBindingPolicyEncryptionOnly() returns error? {
xmlns "http://schemas.xmlsoap.org/soap/envelope/" as soap;
SymmetricBindingConfig symmetricBinding = {
- encryptionAlgorithm: RSA_ECB,
+ encryptionAlgorithm: AES_128,
symmetricKey: symmetricKey,
servicePublicKey: serverPublicKey
};
@@ -262,7 +263,7 @@ function testSymmetricBindingWithSignatureAndEncryption() returns error? {
SymmetricBindingConfig symmetricBinding = {
signatureAlgorithm: RSA_SHA256,
- encryptionAlgorithm: RSA_ECB,
+ encryptionAlgorithm: AES_128,
symmetricKey: symmetricKey,
servicePublicKey: serverPublicKey
};
@@ -296,7 +297,7 @@ function testSymmetricBindingPolicyWithX509SignatureAndEncryption() returns erro
SymmetricBindingConfig symmetricBinding = {
signatureAlgorithm: RSA_SHA256,
- encryptionAlgorithm: RSA_ECB,
+ encryptionAlgorithm: AES_128,
symmetricKey: symmetricKey,
servicePublicKey: serverPublicKey,
x509Token: X509_PUBLIC_CERT_PATH_2
@@ -340,7 +341,7 @@ function testUsernameTokenWithSymmetricBinding() returns error? {
SymmetricBindingConfig symmetricBinding = {
signatureAlgorithm: RSA_SHA256,
- encryptionAlgorithm: RSA_ECB,
+ encryptionAlgorithm: AES_128,
symmetricKey: symmetricKey,
servicePublicKey: serverPublicKey
};
@@ -397,7 +398,7 @@ function testUsernameTokenTimestampWithSymmetricBindingAndX509Token() returns er
SymmetricBindingConfig symmetricBinding = {
signatureAlgorithm: RSA_SHA256,
- encryptionAlgorithm: RSA_ECB,
+ encryptionAlgorithm: AES_128,
symmetricKey: symmetricKey,
servicePublicKey: serverPublicKey,
x509Token: X509_PUBLIC_CERT_PATH_2
@@ -447,7 +448,7 @@ function testSymmetricBindingWithOutboundConfig() returns error? {
SymmetricBindingConfig symmetricBinding = {
signatureAlgorithm: RSA_SHA256,
- encryptionAlgorithm: RSA_ECB,
+ encryptionAlgorithm: AES_128,
symmetricKey: symmetricKey,
servicePublicKey: serverPublicKey
};
@@ -455,10 +456,10 @@ function testSymmetricBindingWithOutboundConfig() returns error? {
xml securedEnvelope = check applySymmetricBinding(envelope, false, symmetricBinding);
string envelopeString = securedEnvelope.toString();
- OutboundSecurityConfig outboundConfig = {
+ InboundSecurityConfig outboundConfig = {
verificationKey: publicKey,
signatureAlgorithm: RSA_SHA256,
- decryptionAlgorithm: RSA_ECB,
+ decryptionAlgorithm: AES_128,
decryptionKey: publicKey
};
@@ -478,7 +479,7 @@ function testSymmetricBindingWithOutboundConfig() returns error? {
}
@test:Config {
- groups: ["username_token", "signature", "asymmetric_binding"]
+ groups: ["username_token", "signature", "asymmetric_binding", "new"]
}
function testAsymmetricBindingWithSignatureRsaSha256() returns error? {
xml envelope =
@@ -487,143 +488,34 @@ function testAsymmetricBindingWithSignatureRsaSha256() returns error? {
`;
xmlns "http://schemas.xmlsoap.org/soap/envelope/" as soap;
- AsymmetricBindingConfig asymmetricBinding = {
- signatureAlgorithm: RSA_SHA256,
- signatureKey: clientPrivateKey,
- encryptionKey: serverPublicKey
- };
- xml securedEnvelope = check applyAsymmetricBinding(envelope, false, asymmetricBinding);
- string envelopeString = securedEnvelope.toString();
- byte[] signedData = check getSignatureData(securedEnvelope);
- Error? validity = check verifyData((envelope//*).toString().toBytes(), signedData,
- clientPublicKey, RSA_SHA256);
- test:assertTrue(validity is ());
-
- assertSignatureWithoutX509(envelopeString);
-}
-
-@test:Config {
- groups: ["username_token", "signature", "asymmetric_binding"]
-}
-function testAsymmetricBindingWithX509Signature() returns error? {
- xml envelope =
- xml `
-
- `;
- xmlns "http://schemas.xmlsoap.org/soap/envelope/" as soap;
-
- AsymmetricBindingConfig asymmetricBinding = {
- signatureAlgorithm: RSA_SHA256,
- signatureKey: clientPrivateKey,
- encryptionKey: serverPublicKey,
- x509Token: X509_PUBLIC_CERT_PATH_2
- };
- xml securedEnvelope = check applyAsymmetricBinding(envelope, false, asymmetricBinding);
- string envelopeString = securedEnvelope.toString();
-
- byte[] signedData = check getSignatureData(securedEnvelope);
- boolean validity = check crypto:verifyRsaSha256Signature((envelope//*).toString().toBytes(),
- signedData, clientPublicKey);
- test:assertTrue(validity);
-
- assertSignatureWithX509(envelopeString);
+ AsymmetricBindingConfig asymmetricConfig = {
+ signatureConfig: {
+ keystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ privateKeyAlias: ALIAS,
+ privateKeyPassword: PASSWORD,
+ signatureAlgorithm: RSA_SHA256,
+ canonicalizationAlgorithm: C14N_EXCL_OMIT_COMMENTS,
+ digestAlgorithm: SHA256
+ }
+ };
+ xml securedEnvelope = check applyAsymmetricConfigurations(envelope, false, asymmetricConfig);
+ InboundConfig inboundConfig = {
+ signatureKeystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ }
+ };
+ boolean validity = check verifySignature(securedEnvelope, inboundConfig);
+ test:assertTrue(validity is true);
}
@test:Config {
- groups: ["username_token", "signature", "asymmetric_binding"]
+ groups: ["username_token", "signature", "asymmetric_binding", "new"]
}
-function testAsymmetricBindingWithEncryption() returns error? {
- xml envelope =
- xml `
-
- `;
- xmlns "http://schemas.xmlsoap.org/soap/envelope/" as soap;
-
- AsymmetricBindingConfig asymmetricBinding = {
- encryptionAlgorithm: RSA_ECB,
- signatureKey: clientPrivateKey,
- encryptionKey: serverPublicKey
- };
- xml securedEnvelope = check applyAsymmetricBinding(envelope, false, asymmetricBinding);
- string envelopeString = securedEnvelope.toString();
-
- byte[] encData = check getEncryptedData(securedEnvelope);
- byte[] decryptDataResult = check crypto:decryptRsaEcb(encData, serverPrivateKey);
- test:assertEquals(check string:fromBytes(decryptDataResult), (envelope//*).toString());
-
- assertEncryptedPart(envelopeString);
-}
-
-@test:Config {
- groups: ["username_token", "signature", "asymmetric_binding", "rr"]
-}
-function testAsymmetricBindingWithSignatureAndEncryption() returns error? {
- xml envelope =
- xml `
- John Doe
- `;
- xmlns "http://schemas.xmlsoap.org/soap/envelope/" as soap;
-
- AsymmetricBindingConfig asymmetricBinding = {
- signatureAlgorithm: RSA_SHA256,
- encryptionAlgorithm: RSA_ECB,
- signatureKey: clientPrivateKey,
- encryptionKey: serverPublicKey
- };
-
- xml securedEnvelope = check applyAsymmetricBinding(envelope, false, asymmetricBinding);
- string envelopeString = securedEnvelope.toString();
-
- byte[] signedData = check getSignatureData(securedEnvelope);
- boolean validity = check crypto:verifyRsaSha256Signature((envelope//*).toString().toBytes(),
- signedData, clientPublicKey);
- test:assertTrue(validity);
-
- byte[] encData = check getEncryptedData(securedEnvelope);
- byte[] decryptDataResult = check crypto:decryptRsaEcb(encData, serverPrivateKey);
- test:assertEquals(check string:fromBytes(decryptDataResult), (envelope//*).toString());
-
- assertSignatureWithoutX509(envelopeString);
- assertEncryptedPart(envelopeString);
-}
-
-@test:Config {
- groups: ["username_token", "signature", "asymmetric_binding"]
-}
-function testAsymmetricBindingWithX509SignatureAndEncryption() returns error? {
- xml envelope =
- xml `
-
- `;
- xmlns "http://schemas.xmlsoap.org/soap/envelope/" as soap;
-
- AsymmetricBindingConfig asymmetricBinding = {
- signatureAlgorithm: RSA_SHA256,
- encryptionAlgorithm: RSA_ECB,
- signatureKey: clientPrivateKey,
- encryptionKey: serverPublicKey,
- x509Token: X509_PUBLIC_CERT_PATH_2
- };
- xml securedEnvelope = check applyAsymmetricBinding(envelope, false, asymmetricBinding);
- string envelopeString = securedEnvelope.toString();
-
- byte[] signedData = check getSignatureData(securedEnvelope);
- boolean validity = check crypto:verifyRsaSha256Signature((envelope//*).toString().toBytes(),
- signedData, clientPublicKey);
- test:assertTrue(validity);
-
- byte[] encData = check getEncryptedData(securedEnvelope);
- byte[] decryptDataResult = check crypto:decryptRsaEcb(encData, serverPrivateKey);
- test:assertEquals((envelope//*).toString(), check string:fromBytes(decryptDataResult));
-
- assertSignatureWithX509(envelopeString);
- assertEncryptedPart(envelopeString);
-}
-
-@test:Config {
- groups: ["username_token", "signature", "asymmetric_binding"]
-}
-function testUsernameTokenWithAsymmetricBindingAndX509() returns error? {
+function testUsernameTokenWithAsymmetricBinding() returns error? {
xml envelope =
xml `
@@ -637,32 +529,33 @@ function testUsernameTokenWithAsymmetricBindingAndX509() returns error? {
};
envelope = check applyUsernameToken(envelope, utRecord);
- AsymmetricBindingConfig asymmetricBinding = {
- signatureAlgorithm: RSA_SHA256,
- encryptionAlgorithm: RSA_ECB,
- signatureKey: clientPrivateKey,
- encryptionKey: serverPublicKey,
- x509Token: X509_PUBLIC_CERT_PATH_2
- };
- xml securedEnvelope = check applyAsymmetricBinding(envelope, false, asymmetricBinding);
- string envelopeString = securedEnvelope.toString();
-
- byte[] signedData = check getSignatureData(securedEnvelope);
- boolean validity = check crypto:verifyRsaSha256Signature((envelope//*).toString().toBytes(),
- signedData, clientPublicKey);
- test:assertTrue(validity);
-
- byte[] encData = check getEncryptedData(securedEnvelope);
- byte[] decryptDataResult = check crypto:decryptRsaEcb(encData, serverPrivateKey);
- test:assertEquals((envelope//*).toString(), check string:fromBytes(decryptDataResult));
-
- assertUsernameToken(envelopeString, DIGEST);
- assertSignatureWithX509(envelopeString);
- assertEncryptedPart(envelopeString);
+ AsymmetricBindingConfig asymmetricConfig = {
+ signatureConfig: {
+ keystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ privateKeyAlias: ALIAS,
+ privateKeyPassword: PASSWORD,
+ signatureAlgorithm: RSA_SHA256,
+ canonicalizationAlgorithm: C14N_EXCL_OMIT_COMMENTS,
+ digestAlgorithm: SHA256
+ }
+ };
+ xml securedEnvelope = check applyAsymmetricConfigurations(envelope, false, asymmetricConfig);
+ InboundConfig inboundConfig = {
+ signatureKeystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ }
+ };
+ boolean validity = check verifySignature(securedEnvelope, inboundConfig);
+ assertUsernameToken(securedEnvelope.toString(), DIGEST);
+ test:assertTrue(validity is true);
}
@test:Config {
- groups: ["username_token", "signature", "asymmetric_binding"]
+ groups: ["username_token", "signature", "asymmetric_binding", "new"]
}
function testUsernameTokenTimestampWithAsymmetricBindingAndX509() returns error? {
xml envelope =
@@ -679,143 +572,186 @@ function testUsernameTokenTimestampWithAsymmetricBindingAndX509() returns error?
envelope = check applyUsernameToken(envelope, utRecord);
envelope = check applyTimestampToken(envelope = envelope, timeToLive = 600);
- AsymmetricBindingConfig asymmetricBinding = {
- signatureAlgorithm: RSA_SHA256,
- encryptionAlgorithm: RSA_ECB,
- signatureKey: clientPrivateKey,
- encryptionKey: serverPublicKey,
- x509Token: X509_PUBLIC_CERT_PATH_2
- };
- xml securedEnvelope = check applyAsymmetricBinding(envelope, false, asymmetricBinding);
- string envelopeString = securedEnvelope.toString();
-
- byte[] signedData = check getSignatureData(securedEnvelope);
- boolean validity = check crypto:verifyRsaSha256Signature((envelope//*).toString().toBytes(),
- signedData, clientPublicKey);
- test:assertTrue(validity);
-
- byte[] encData = check getEncryptedData(securedEnvelope);
- byte[] decryptDataResult = check crypto:decryptRsaEcb(encData, serverPrivateKey);
- test:assertEquals((envelope//*).toString(), check string:fromBytes(decryptDataResult));
-
- assertUsernameToken(envelopeString, DIGEST);
- assertTimestampToken(envelopeString);
- assertSignatureWithX509(envelopeString);
- assertEncryptedPart(envelopeString);
+ AsymmetricBindingConfig asymmetricConfig = {
+ signatureConfig: {
+ keystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ privateKeyAlias: ALIAS,
+ privateKeyPassword: PASSWORD,
+ signatureAlgorithm: RSA_SHA256,
+ canonicalizationAlgorithm: C14N_EXCL_OMIT_COMMENTS,
+ digestAlgorithm: SHA256
+ }
+ };
+ xml securedEnvelope = check applyAsymmetricConfigurations(envelope, false, asymmetricConfig);
+ InboundConfig inboundConfig = {
+ signatureKeystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ }
+ };
+ boolean validity = check verifySignature(securedEnvelope, inboundConfig);
+ assertUsernameToken(securedEnvelope.toString(), DIGEST);
+ assertTimestampToken(securedEnvelope.toString());
+ test:assertTrue(validity is true);
}
-
@test:Config {
- groups: ["username_token", "signature", "asymmetric_binding", "outbound_config"]
+ groups: ["username_token", "signature", "asymmetric_binding", "new"]
}
-function testAsymmetricBindingWithOutboundConfig() returns error? {
+function testAsymmetricBindingWithSignatureWithRsaSha1() returns error? {
xml envelope =
xml `
- John Doe
+
`;
xmlns "http://schemas.xmlsoap.org/soap/envelope/" as soap;
- AsymmetricBindingConfig asymmetricBinding = {
- signatureAlgorithm: RSA_SHA256,
- encryptionAlgorithm: RSA_ECB,
- signatureKey: clientPrivateKey,
- encryptionKey: serverPublicKey
- };
-
- OutboundSecurityConfig outboundConfig = {
- verificationKey: clientPublicKey,
- signatureAlgorithm: RSA_SHA256,
- decryptionAlgorithm: RSA_ECB,
- decryptionKey: serverPrivateKey
- };
-
- xml securedEnvelope = check applyAsymmetricBinding(envelope,false, asymmetricBinding);
- string envelopeString = securedEnvelope.toString();
- crypto:PrivateKey|crypto:PublicKey? privateKey = outboundConfig.decryptionKey;
- if privateKey is crypto:PrivateKey|crypto:PublicKey {
- byte[] encData = check getEncryptedData(securedEnvelope);
- byte[] decryptDataResult = check crypto:decryptRsaEcb(encData, privateKey);
- string decryptedBody = "" + check string:fromBytes(decryptDataResult) + "";
- envelopeString = regexp:replace(re `.*`, envelopeString, decryptedBody);
- securedEnvelope = check xml:fromString(envelopeString);
- }
- byte[] signedData = check getSignatureData(securedEnvelope);
- boolean validity = check crypto:verifyRsaSha256Signature((envelope//*).toString().toBytes(),
- signedData, clientPublicKey);
- test:assertTrue(validity);
+ AsymmetricBindingConfig asymmetricConfig = {
+ signatureConfig: {
+ keystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ privateKeyAlias: ALIAS,
+ privateKeyPassword: PASSWORD,
+ signatureAlgorithm: RSA_SHA1,
+ canonicalizationAlgorithm: C14N_EXCL_OMIT_COMMENTS,
+ digestAlgorithm: SHA1
+ }
+ };
+ xml securedEnvelope = check applyAsymmetricConfigurations(envelope, false, asymmetricConfig);
+ InboundConfig inboundConfig = {
+ signatureKeystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ }
+ };
+ boolean validity = check verifySignature(securedEnvelope, inboundConfig);
+ test:assertTrue(validity is true);
}
@test:Config {
- groups: ["username_token", "signature", "asymmetric_binding"]
+ groups: ["username_token", "signature", "asymmetric_binding", "new"]
}
-function testAsymmetricBindingWithSignatureWithRsaSha1() returns error? {
- xml envelope =
- xml `
-
- `;
- xmlns "http://schemas.xmlsoap.org/soap/envelope/" as soap;
-
- AsymmetricBindingConfig asymmetricBinding = {
- signatureAlgorithm: RSA_SHA1,
- signatureKey: clientPrivateKey,
- encryptionKey: serverPublicKey
- };
- xml securedEnvelope = check applyAsymmetricBinding(envelope, false, asymmetricBinding);
+function testAsymmetricBindingWithSignatureWithRsaSha512() returns error? {
+ xml envelope = xml `
+
+
+
+
+
+
+ 2
+ 3
+
+
+ `;
+
+ AsymmetricBindingConfig asymmetricConfig = {
+ signatureConfig: {
+ keystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ privateKeyAlias: ALIAS,
+ privateKeyPassword: PASSWORD,
+ signatureAlgorithm: RSA_SHA512,
+ canonicalizationAlgorithm: C14N_EXCL_OMIT_COMMENTS,
+ digestAlgorithm: SHA512
+ }
+ };
+ xml securedEnvelope = check applyAsymmetricConfigurations(envelope, true, asymmetricConfig);
string envelopeString = securedEnvelope.toString();
- byte[] signedData = check getSignatureData(securedEnvelope);
- Error? validity = check verifyData((envelope//*).toString().toBytes(), signedData,
- clientPublicKey, RSA_SHA1);
- test:assertTrue(validity is ());
-
+ InboundConfig inboundConfig = {
+ signatureKeystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ }
+ };
+ boolean validity = check verifySignature(securedEnvelope, inboundConfig);
+ test:assertTrue(validity is true);
assertSignatureWithoutX509(envelopeString);
}
@test:Config {
- groups: ["username_token", "signature", "asymmetric_binding"]
+ groups: ["username_token", "signature", "symmetric_binding", "new4"]
}
-function testAsymmetricBindingWithSignatureWithRsaSha384() returns error? {
- xml envelope =
- xml `
-
- `;
+function testAsymmetricBindingPolicyWithSignatureAndEncryption() returns error? {
+ xml envelope = check io:fileReadXml(SOAP_ENVELOPE_PATH);
xmlns "http://schemas.xmlsoap.org/soap/envelope/" as soap;
- AsymmetricBindingConfig asymmetricBinding = {
- signatureAlgorithm: RSA_SHA384,
- signatureKey: clientPrivateKey,
- encryptionKey: serverPublicKey
- };
- xml securedEnvelope = check applyAsymmetricBinding(envelope, false, asymmetricBinding);
+ AsymmetricBindingConfig asymmetricConfig = {
+ signatureConfig: {
+ keystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ privateKeyAlias: ALIAS,
+ privateKeyPassword: PASSWORD,
+ signatureAlgorithm: RSA_SHA512,
+ canonicalizationAlgorithm: C14N_EXCL_OMIT_COMMENTS,
+ digestAlgorithm: SHA512
+ },
+ encryptionConfig: {
+ keystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ publicKeyAlias: ALIAS,
+ encryptionAlgorithm: AES_128
+ }
+ };
+ xml securedEnvelope = check applyAsymmetricConfigurations(envelope, false, asymmetricConfig);
string envelopeString = securedEnvelope.toString();
- byte[] signedData = check getSignatureData(securedEnvelope);
- Error? validity = check verifyData((envelope//*).toString().toBytes(), signedData,
- clientPublicKey, RSA_SHA384);
- test:assertTrue(validity is ());
-
- assertSignatureWithoutX509(envelopeString);
+ InboundConfig inboundConfig = {
+ decryptKeystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ signatureKeystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ }
+ };
+ Document doc = check decryptEnvelope(securedEnvelope, inboundConfig);
+ boolean validity = check verifySignature(doc, inboundConfig);
+ test:assertTrue(validity is true);
+ assertEncryptedSymmetricKey(envelopeString);
+ assertEncryptedPart(envelopeString);
}
@test:Config {
- groups: ["username_token", "signature", "asymmetric_binding"]
+ groups: ["username_token", "signature", "symmetric_binding", "new3"]
}
-function testAsymmetricBindingWithSignatureWithRsaSha512() returns error? {
- xml envelope =
- xml `
-
- `;
+function testAsymmetricBindingPolicyWithEncryption() returns error? {
+ xml envelope = check io:fileReadXml(SOAP_ENVELOPE_PATH);
xmlns "http://schemas.xmlsoap.org/soap/envelope/" as soap;
- AsymmetricBindingConfig asymmetricBinding = {
- signatureAlgorithm: RSA_SHA512,
- signatureKey: clientPrivateKey,
- encryptionKey: serverPublicKey
- };
- xml securedEnvelope = check applyAsymmetricBinding(envelope, false, asymmetricBinding);
+ AsymmetricBindingConfig asymmetricConfig = {
+ encryptionConfig: {
+ keystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ publicKeyAlias: ALIAS,
+ encryptionAlgorithm: AES_256
+ }
+ };
+ xml securedEnvelope = check applyAsymmetricConfigurations(envelope, false, asymmetricConfig);
string envelopeString = securedEnvelope.toString();
- byte[] signedData = check getSignatureData(securedEnvelope);
- Error? validity = check verifyData((envelope//*).toString().toBytes(), signedData,
- clientPublicKey, RSA_SHA512);
- test:assertTrue(validity is ());
-
- assertSignatureWithoutX509(envelopeString);
+ InboundConfig inboundConfig = {
+ decryptKeystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ }
+ };
+ assertEncryptedSymmetricKey(envelopeString);
+ assertEncryptedPart(envelopeString);
+ Document doc = check decryptEnvelope(securedEnvelope, inboundConfig);
+ xml body = (check doc.getEnvelope())/;
+ test:assertEquals(body, envelope/);
}
diff --git a/ballerina/modules/wssec/types.bal b/ballerina/modules/wssec/types.bal
index 6767a51..2990f24 100644
--- a/ballerina/modules/wssec/types.bal
+++ b/ballerina/modules/wssec/types.bal
@@ -28,6 +28,22 @@ public enum SignatureAlgorithm {
RSA_SHA512 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"
}
+public enum CanonicalizationAlgorithm {
+ C14N_OMIT_COMMENTS = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315",
+ C14N_WITH_COMMENTS = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments",
+ C14N_EXCL_OMIT_COMMENTS = "http://www.w3.org/2001/10/xml-exc-c14n#",
+ C14N_EXCL_WITH_COMMENTS = "http://www.w3.org/2001/10/xml-exc-c14n#WithComments"
+}
+
+public enum DigestAlgorithm {
+ SHA1 = "http://www.w3.org/2000/09/xmldsig#sha1",
+ SHA256 = "http://www.w3.org/2001/04/xmlenc#sha256",
+ SHA384 = "http://www.w3.org/2001/04/xmldsig-more#sha384",
+ SHA512 = "http://www.w3.org/2001/04/xmlenc#sha512"
+}
+
public enum EncryptionAlgorithm {
- RSA_ECB = "http://www.w3.org/2001/04/xmlenc#rsa-1_5"
+ TRIPLE_DES = "http://www.w3.org/2001/04/xmlenc#tripledes-cbc",
+ AES_128 = "http://www.w3.org/2001/04/xmlenc#aes128-cbc",
+ AES_256 = "http://www.w3.org/2001/04/xmlenc#aes256-cbc"
}
diff --git a/ballerina/modules/wssec/ws_security.bal b/ballerina/modules/wssec/ws_security.bal
index 1b570db..cc5b0fd 100644
--- a/ballerina/modules/wssec/ws_security.bal
+++ b/ballerina/modules/wssec/ws_security.bal
@@ -27,7 +27,23 @@ isolated class WsSecurity {
'class: "org.wssec.WsSecurity"
} external;
- isolated function applySignatureOnlyPolicy(WSSecurityHeader wsSecurityPolicy, Signature signature, string? x509FilePath)
+ isolated function applySignatureOnlyPolicy(WSSecurityHeader wsSecurityPolicy, Signature signature,
+ string? x509FilePath) returns string|Error = @java:Method {
+ 'class: "org.wssec.WsSecurity"
+ } external;
+
+ isolated function applySignatureOnly(Document soapEnvelope, boolean soap12, SignatureConfig signatureConfig)
+ returns string|Error = @java:Method {
+ 'class: "org.wssec.WsSecurity"
+ } external;
+
+ isolated function applyEncryptionOnly(Document soapEnvelope, boolean soap12, EncryptionConfig encryptionConfig)
+ returns string|Error = @java:Method {
+ 'class: "org.wssec.WsSecurity"
+ } external;
+
+ isolated function applySignatureAndEncryption(Document soapEnvelope, boolean soap12,
+ SignatureConfig signatureConfig, EncryptionConfig encryptionConfig)
returns string|Error = @java:Method {
'class: "org.wssec.WsSecurity"
} external;
@@ -36,4 +52,14 @@ isolated class WsSecurity {
returns string|Error = @java:Method {
'class: "org.wssec.WsSecurity"
} external;
+
+ isolated function verifySignature(Document soapEnvelope, InboundConfig config)
+ returns boolean|error = @java:Method {
+ 'class: "org.wssec.WsSecurity"
+ } external;
+
+ isolated function decryptEnvelope(Document soapEnvelope, InboundConfig config)
+ returns Document|error = @java:Method {
+ 'class: "org.wssec.WsSecurity"
+ } external;
}
diff --git a/ballerina/modules/wssec/ws_security_methods.bal b/ballerina/modules/wssec/ws_security_methods.bal
index 134746a..8188125 100644
--- a/ballerina/modules/wssec/ws_security_methods.bal
+++ b/ballerina/modules/wssec/ws_security_methods.bal
@@ -21,6 +21,24 @@ xmlns "http://schemas.xmlsoap.org/soap/envelope/" as soap11;
xmlns "http://www.w3.org/2003/05/soap-envelope" as soap12;
xmlns "http://www.w3.org/2000/09/xmldsig#" as ds;
+
+public isolated function verifySignature(xml|Document soapEnvelope, InboundConfig config) returns boolean|error {
+ WsSecurity wsSecurity = new;
+ Document document;
+ if soapEnvelope is xml {
+ document = check new (soapEnvelope);
+ } else {
+ document = soapEnvelope;
+ }
+ return check wsSecurity.verifySignature(document, config);
+}
+
+public isolated function decryptEnvelope(xml soapEnvelope, InboundConfig config) returns Document|error {
+ WsSecurity wsSecurity = new;
+ Document document = check new (soapEnvelope);
+ return check wsSecurity.decryptEnvelope(document, config);
+}
+
isolated function addSecurityHeader(Document document) returns WSSecurityHeader|Error {
WSSecurityHeader wsSecHeader = check new (document);
Error? insertHeader = wsSecHeader.insertSecHeader();
@@ -181,48 +199,23 @@ public isolated function applySymmetricBinding(xml envelope, boolean soap12, *Sy
# + soap12 - A boolean flag. Set to `true` for SOAP 1.2, or `false` for SOAP 1.1.
# + asymmetricBinding - The `AsymmetricBindingConfig` record with the required parameters
# + return - A `xml` type of SOAP envelope if the security binding is successfully added or else `wssec:Error`
-public isolated function applyAsymmetricBinding(xml envelope, boolean soap12,
- *AsymmetricBindingConfig asymmetricBinding)
- returns xml|crypto:Error|Error {
+public isolated function applyAsymmetricConfigurations(xml envelope, boolean soap12,
+ *AsymmetricBindingConfig asymmetricBinding)
+ returns xml|Error {
Document document = check new (envelope);
- WSSecurityHeader wsSecurityHeader = check addSecurityHeader(document);
- string securedEnvelope = envelope.toBalString();
- SignatureAlgorithm? signatureAlgorithm = asymmetricBinding.signatureAlgorithm;
- EncryptionAlgorithm? encryptionAlgorithm = asymmetricBinding.encryptionAlgorithm;
- if signatureAlgorithm is SignatureAlgorithm {
- Signature signature = check new ();
- crypto:PrivateKey? signatureKey = asymmetricBinding.signatureKey;
- if signatureKey !is crypto:PrivateKey {
- return error Error("Signature key cannot be nil");
- }
- byte[] signedData;
- if soap12 {
- signedData = check signature.signData((envelope//*).toString(),
- signatureAlgorithm, signatureKey);
- } else {
- signedData = check signature.signData((envelope//*).toString(),
- signatureAlgorithm, signatureKey);
- }
- Signature signatureResult = check addSignature(signature, signatureAlgorithm, signedData);
- WsSecurity wsSecurity = new;
- securedEnvelope = check wsSecurity.applySignatureOnlyPolicy(wsSecurityHeader, signatureResult,
- asymmetricBinding.x509Token);
- }
- if encryptionAlgorithm is EncryptionAlgorithm {
- Encryption encryption = check new ();
- crypto:PublicKey? encryptionKey = asymmetricBinding.encryptionKey;
- if encryptionKey !is crypto:PublicKey {
- return error Error("Encryption key cannot be nil");
- }
- byte[] encryptData;
- if soap12 {
- encryptData = check crypto:encryptRsaEcb((envelope//*).toString().toBytes(), encryptionKey);
- } else {
- encryptData = check crypto:encryptRsaEcb((envelope//*).toString().toBytes(), encryptionKey);
- }
- Encryption encryptionResult = check addEncryption(encryption, encryptionAlgorithm, encryptData);
- WsSecurity wsSecurity = new;
- securedEnvelope = check wsSecurity.applyEncryptionOnlyPolicy(wsSecurityHeader, encryptionResult);
+ WsSecurity wsSecurity = new;
+ _ = check addSecurityHeader(document);
+ SignatureConfig? signatureConfig = asymmetricBinding.signatureConfig;
+ EncryptionConfig? encryptionConfig = asymmetricBinding.encryptionConfig;
+ string securedEnvelope = envelope.toString();
+ if signatureConfig !is () && encryptionConfig !is () {
+ securedEnvelope = check wsSecurity
+ .applySignatureAndEncryption(document, soap12, signatureConfig, encryptionConfig);
+ } else if signatureConfig !is () {
+ securedEnvelope = check wsSecurity.applySignatureOnly(document, soap12, signatureConfig);
+ } else if encryptionConfig !is () {
+ securedEnvelope = check wsSecurity.applyEncryptionOnly(document, soap12, encryptionConfig);
}
return convertStringToXml(securedEnvelope);
}
+
diff --git a/ballerina/soap_utils.bal b/ballerina/soap_utils.bal
index 5891c77..e78497f 100644
--- a/ballerina/soap_utils.bal
+++ b/ballerina/soap_utils.bal
@@ -25,11 +25,11 @@ import ballerina/test;
public isolated function validateTransportBindingPolicy(ClientConfig config) returns Error? {
if config.httpConfig.secureSocket is () {
- wssec:InboundSecurityConfig|wssec:InboundSecurityConfig[] securityPolicy = config.inboundSecurity;
+ wssec:OutboundSecurityConfig|wssec:OutboundSecurityConfig[] securityPolicy = config.outboundSecurity;
if securityPolicy is wssec:TransportBindingConfig {
return error Error(INVALID_PROTOCOL_ERROR);
- } else if securityPolicy is wssec:InboundSecurityConfig[] {
- foreach wssec:InboundSecurityConfig policy in securityPolicy {
+ } else if securityPolicy is wssec:OutboundSecurityConfig[] {
+ foreach wssec:OutboundSecurityConfig policy in securityPolicy {
if policy is wssec:TransportBindingConfig {
return error Error(INVALID_PROTOCOL_ERROR);
}
@@ -42,7 +42,7 @@ public isolated function getReadOnlyClientConfig(ClientConfig original) returns
'class: "org.wssec.WsSecurity"
} external;
-public isolated function applySecurityPolicies(wssec:InboundSecurityConfig|wssec:InboundSecurityConfig[] security,
+public isolated function applySecurityPolicies(wssec:OutboundSecurityConfig|wssec:OutboundSecurityConfig[] security,
xml envelope, boolean soap12 = true)
returns xml|crypto:Error|wssec:Error {
if security is wssec:TimestampTokenConfig {
@@ -52,49 +52,34 @@ public isolated function applySecurityPolicies(wssec:InboundSecurityConfig|wssec
} else if security is wssec:SymmetricBindingConfig {
return wssec:applySymmetricBinding(envelope, soap12, security);
} else if security is wssec:AsymmetricBindingConfig {
- return wssec:applyAsymmetricBinding(envelope, soap12, security);
- } else if security is wssec:InboundSecurityConfig {
+ return wssec:applyAsymmetricConfigurations(envelope, soap12, security);
+ } else if security is wssec:OutboundSecurityConfig {
return envelope;
} else {
- xml securedEnvelope;
- foreach wssec:InboundSecurityConfig policy in security {
- securedEnvelope = check applySecurityPolicies(policy, envelope);
+ xml securedEnvelope = envelope.clone();
+ foreach wssec:OutboundSecurityConfig policy in security {
+ securedEnvelope = check applySecurityPolicies(policy, securedEnvelope);
}
return securedEnvelope;
}
}
-public isolated function applyOutboundConfig(OutboundSecurityConfig outboundSecurity, xml envelope,
+public isolated function applyInboundConfig(wssec:InboundConfig inboundSecurity, xml envelope,
boolean soap12 = true) returns xml|Error {
xmlns "http://schemas.xmlsoap.org/soap/envelope/" as soap11;
xmlns "http://www.w3.org/2003/05/soap-envelope" as soap12;
xml soapEnvelope = envelope;
do {
- wssec:EncryptionAlgorithm? encryptionAlgorithm = outboundSecurity.decryptionAlgorithm;
- if encryptionAlgorithm is wssec:EncryptionAlgorithm {
- crypto:PrivateKey|crypto:PublicKey? clientPrivateKey = outboundSecurity.decryptionKey;
- if clientPrivateKey is crypto:PrivateKey|crypto:PublicKey {
- byte[] encData = check wssec:getEncryptedData(soapEnvelope);
- byte[] decryptDataResult = check crypto:decryptRsaEcb(encData, clientPrivateKey);
- string decryptedBody = "" + check string:fromBytes(decryptDataResult) + "";
- string decryptedEnv = regexp:replace(re `.*`, soapEnvelope.toString(),
- decryptedBody);
- soapEnvelope = check xml:fromString(decryptedEnv);
- }
+ crypto:KeyStore? encryptionAlgorithm = inboundSecurity.decryptKeystore;
+ if encryptionAlgorithm is crypto:KeyStore {
+ wssec:Document doc = check wssec:decryptEnvelope(envelope, inboundSecurity);
+ soapEnvelope = check doc.getEnvelope();
}
- wssec:SignatureAlgorithm? signatureAlgorithm = outboundSecurity.signatureAlgorithm;
- if signatureAlgorithm is wssec:SignatureAlgorithm {
- crypto:PublicKey? serverPublicKey = outboundSecurity.verificationKey;
- if serverPublicKey is crypto:PublicKey {
- byte[] signatureData = check wssec:getSignatureData(soapEnvelope);
- if soap12 {
- check wssec:verifyData((soapEnvelope//*).toString().toBytes(),
- signatureData, serverPublicKey, signatureAlgorithm);
- } else {
- check wssec:verifyData((soapEnvelope//*).toString().toBytes(),
- signatureData, serverPublicKey, signatureAlgorithm);
- }
-
+ crypto:KeyStore? signatureAlgorithm = inboundSecurity.signatureKeystore;
+ if signatureAlgorithm is crypto:KeyStore {
+ boolean validity = check wssec:verifySignature(soapEnvelope, inboundSecurity);
+ if !validity {
+ return error Error("Signature verification failed");
}
}
return soapEnvelope;
diff --git a/ballerina/types.bal b/ballerina/types.bal
index aca2f2a..bba1c77 100644
--- a/ballerina/types.bal
+++ b/ballerina/types.bal
@@ -37,18 +37,35 @@ public enum SignatureAlgorithm {
# Represents enums for all the supported encryption algorithms.
#
public enum EncryptionAlgorithm {
- RSA_ECB = "http://www.w3.org/2001/04/xmlenc#rsa-1_5"
+ TRIPLE_DES = "http://www.w3.org/2001/04/xmlenc#tripledes-cbc",
+ AES_128 = "http://www.w3.org/2001/04/xmlenc#aes128-cbc",
+ AES_256 = "http://www.w3.org/2001/04/xmlenc#aes256-cbc"
+}
+
+# Represents enums for all the supported canonicalization algorithms.
+#
+public enum CanonicalizationAlgorithm {
+ C14N_OMIT_COMMENTS = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315",
+ C14N_WITH_COMMENTS = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments",
+ C14N_EXCL_OMIT_COMMENTS = "http://www.w3.org/2001/10/xml-exc-c14n#",
+ C14N_EXCL_WITH_COMMENTS = "http://www.w3.org/2001/10/xml-exc-c14n#WithComments"
+}
+
+# Represents enums for all the supported digest algorithms.
+#
+public enum DigestAlgorithm {
+ SHA1 = "http://www.w3.org/2000/09/xmldsig#sha1",
+ SHA256 = "http://www.w3.org/2001/04/xmlenc#sha256",
+ SHA384 = "http://www.w3.org/2001/04/xmldsig-more#sha384",
+ SHA512 = "http://www.w3.org/2001/04/xmlenc#sha512"
}
# Represents the record for outbound security configurations to verify and decrypt SOAP envelopes.
-#
-# + verificationKey - The public key to verify the signature of the SOAP envelope
-# + decryptionKey - The private key to decrypt the SOAP envelope
-# + signatureAlgorithm - The algorithm to verify the SOAP envelope
-# + decryptionAlgorithm - The algorithm to decrypt the SOAP body
-public type OutboundSecurityConfig record {
- *wssec:OutboundSecurityConfig;
-};
-
-# Union type of all the inbound web service security configurations.
-public type InboundSecurityConfig wssec:InboundSecurityConfig;
+#
+# + decryptKeystore - The keystore to decrypt the SOAP envelope
+# + signatureKeystore - The keystore to verify the signature of the SOAP envelope
+public type InboundSecurityConfig wssec:InboundConfig;
+
+# Union type of all the outbound web service security configurations.
+public type OutboundSecurityConfig wssec:OutboundSecurityConfig;
+
diff --git a/docs/spec/spec.md b/docs/spec/spec.md
index 90c4d4b..c9b9b63 100644
--- a/docs/spec/spec.md
+++ b/docs/spec/spec.md
@@ -36,8 +36,8 @@ The conforming implementation of the specification is released and included in t
3. [Security](#3-security)
* 3.1 [Policies](#31-policies)
* 3.2 [Security Policy Configuration Types](#32-security-policy-configuration-types)
- * 3.2.1 [Inbound Security Configurations](#321-inbound-security-configurations)
- * 3.2.2 [Outbound Security Configurations](#322-outbound-security-configurations)
+ * 3.2.1 [Outbound Security Configurations](#321-outbound-security-configurations)
+ * 3.2.2 [Inbound Security Configurations](#322-inbound-security-configurations)
* 3.3 [Configure Security Policies](#33-configure-security-policies)
* [UsernameToken and TranportBinding Policy with SOAP 1.1 Client](#331-usernametoken-and-tranportbinding-policy-with-soap-11-client)
* [Asymmetric Binding and Outbound Security Configuration with SOAP 1.2 Client](#332-asymmetric-binding-and-outbound-security-configuration-with-soap-12-client)
@@ -279,9 +279,9 @@ The SOAP client module introduces a robust framework for configuring security me
There are two primary security configurations available for SOAP clients:
-* `inboundSecurity`: This configuration is applied to the SOAP envelope when a request is made. It includes various ws security policies such as Username Token, Timestamp Token, X509 Token, Symmetric Binding, Asymmetric Binding, and Transport Binding, either individually or in combination with each other.
+* `outboundSecurity`: This configuration is applied to the SOAP envelope when a request is made. It includes various ws security policies such as Username Token, Timestamp Token, X509 Token, Symmetric Binding, Asymmetric Binding, and Transport Binding, either individually or in combination with each other.
-* `outboundSecurity`: This configuration is applied to the SOAP envelope when a response is received. Its purpose is to decrypt the data within the envelope and verify the digital signature for security validation.
+* `inboundSecurity`: This configuration is applied to the SOAP envelope when a response is received. Its purpose is to decrypt the data within the envelope and verify the digital signature for security validation.
### 3.1 Policies
@@ -299,7 +299,7 @@ These policies empower SOAP clients to enhance the security of their web service
This subsection introduces the configuration types for inbound and outbound security, providing detailed information on each type.
-#### 3.2.1 Inbound Security Configurations
+#### 3.2.1 Outbound Security Configurations
* `TimestampTokenConfig`: Represents the record for Timestamp Token policy.
* Fields:
@@ -319,17 +319,15 @@ This subsection introduces the configuration types for inbound and outbound secu
* `EncryptionAlgorithm` encryptionAlgorithm : The algorithm to encrypt the SOAP envelope
* `string` x509Token : The path or token of the X509 certificate
-* `AsymmetricBindingConfig`: Represents the record for Username Token with Asymmetric Binding policy.
- * Fields:
- * `crypto:PrivateKey` signatureKey : The private key to sign the SOAP envelope
- * `crypto:PublicKey` encryptionKey : The public key to encrypt the SOAP body
- * `SignatureAlgorithm` signatureAlgorithm : The algorithm to sign the SOAP envelope
- * `EncryptionAlgorithm` encryptionAlgorithm : The algorithm to encrypt the SOAP body
- * `string` x509Token : field description
+- `AsymmetricBindingConfig`: Represents the record for Asymmetric Binding policy.
+ - Fields:
+ - `SignatureConfig` signatureConfig : Configuration for applying digital signatures
+ - `EncryptionConfig` encryptionConfig : Configuration for applying encryption
+ - `string` x509Token : The path or token of the X509 certificate
-#### 3.2.2 Outbound Security Configurations
+#### 3.2.2 Inbound Security Configurations
-* `OutboundSecurityConfig`: Represents the record for outbound security configurations to verify and decrypt SOAP envelopes.
+* `InboundSecurityConfig`: Represents the record for outbound security configurations to verify and decrypt SOAP envelopes.
* Fields:
* `crypto:PublicKey` verificationKey : The public key to verify the signature of the SOAP envelope
* `crypto:PrivateKey`|`crypto:PublicKey` decryptionKey : The private key to decrypt the SOAP envelope
@@ -350,7 +348,7 @@ import ballerina/soap.soap11;
public function main() returns error? {
soap11:Client soapClient = check new ("https://www.secured-soap-endpoint.com",
{
- inboundSecurity: [
+ outboundSecurity: [
{
username: "username",
password: "password",
@@ -387,17 +385,32 @@ public function main() returns error? {
soap12:Client soapClient = check new ("https://www.secured-soap-endpoint.com",
{
- inboundSecurity: {
- signatureAlgorithm: soap:RSA_SHA256,
- encryptionAlgorithm: soap:RSA_ECB,
- signatureKey: clientPrivateKey,
- encryptionKey: serverPublicKey,
- },
outboundSecurity: {
- verificationKey: serverPublicKey,
- signatureAlgorithm: soap:RSA_SHA256,
- decryptionKey: clientPrivateKey,
- decryptionAlgorithm: soap:RSA_ECB
+ signatureConfig: {
+ keystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ privateKeyAlias: ALIAS,
+ privateKeyPassword: PASSWORD,
+ canonicalizationAlgorithm: wssec:C14N_EXCL_OMIT_COMMENTS,
+ digestAlgorithm: wssec:SHA1
+ },
+ encryptionConfig: {
+ keystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ publicKeyAlias: ALIAS,
+ encryptionAlgorithm: wssec:AES_128
+ }
+ },
+ inboundSecurity: {
+ keystore: {
+ path: KEY_STORE_PATH_2,
+ password: PASSWORD
+ },
+ decryptionAlgorithm: wssec:AES_128
}
});
xml envelope = xml ` signatureConfig) {
+ Document document = (Document) documentBuilder.getNativeData(NATIVE_DOCUMENT);
+ BMap keyStore = (BMap) signatureConfig
+ .getMapValue(StringUtils.fromString(KEYSTORE));
+ String path = keyStore.get(StringUtils.fromString(PATH)).toString();
+ String password = keyStore.get(StringUtils.fromString(PASSWORD)).toString();
+ String digestAlgorithm = signatureConfig.get(StringUtils.fromString(DIGEST_ALGORITHM)).toString();
+ String canonicalizationAlgorithm = signatureConfig
+ .get(StringUtils.fromString(CANONICALIZATION_ALGORITHM)).toString();
+ String signatureAlgorithm = signatureConfig.get(StringUtils.fromString(SIGNATURE_ALGORITHM)).toString();
+ String privateKeyPassword = signatureConfig.get(StringUtils.fromString(PRIVATE_KEY_PASSWORD)).toString();
+ String privateKeyAlias = signatureConfig.get(StringUtils.fromString(PRIVATE_KEY_ALIAS)).toString();
+ try {
+ validateSoapHeader(soap12, document);
+ WSSecHeader secHeader = new WSSecHeader(document);
+ secHeader.insertSecurityHeader();
+ Crypto crypto = getCryptoInstance(path, password);
+ generateSignature(privateKeyPassword, privateKeyAlias, digestAlgorithm,
+ canonicalizationAlgorithm, signatureAlgorithm, crypto, secHeader);
+ return convertDocumentToString(document);
+ } catch (Exception e) {
+ return createError(e.getMessage());
+ }
+ }
+
+ private static Crypto getCryptoInstance(String path, String password) throws WSSecurityException {
+ Properties properties = new Properties();
+ properties.put(CRYPTO_PROVIDER_FIELD, CRYPTO_PROVIDER_VALUE);
+ properties.put(KEYSTORE_PATH_FIELD, path);
+ properties.put(KEYSTORE_PASSWORD_FIELD, password);
+ return CryptoFactory.getInstance(properties);
+ }
+
+ private static void validateSoapHeader(Boolean soap12, Document document) {
+ Init.init();
+ String namespace = soap12 ? WSConstants.URI_SOAP12_ENV : WSConstants.URI_SOAP11_ENV;
+ Element header = (Element) document.getElementsByTagNameNS(namespace, ELEM_HEADER).item(0);
+ if (header == null) {
+ throw new IllegalStateException("SOAP Envelope must have a Header");
+ }
+ }
+
+ public static Object verifySignature(BObject documentBuilder,
+ BMap config) {
+ Document document = (Document) documentBuilder.getNativeData(NATIVE_DOCUMENT);
+ BMap keyStore = (BMap) config
+ .getMapValue(StringUtils.fromString(SIGNATURE_KEYSTORE));
+ String path = keyStore.get(StringUtils.fromString(PATH)).toString();
+ String password = keyStore.get(StringUtils.fromString(PASSWORD)).toString();
+ try {
+ WSSecurityEngine secEngine = new WSSecurityEngine();
+ RequestData requestData = new RequestData();
+ Crypto crypto = getCryptoInstance(path, password);
+ requestData.setSigVerCrypto(crypto);
+ CallbackHandler passwordCallbackHandler = callbacks -> {
+ for (Callback callback: callbacks) {
+ ((WSPasswordCallback) callback).setPassword(PASSWORD);
+ }
+ };
+ requestData.setCallbackHandler(passwordCallbackHandler);
+ WSSConfig wssConfig = WSSConfig.getNewInstance();
+ secEngine.setWssConfig(wssConfig);
+ Processor processor = (elem, data) -> {
+ if (WSConstants.ENC_KEY_LN.equals(elem.getLocalName())) {
+ return new ArrayList<>();
+ }
+ return new EncryptedKeyProcessor().handleToken(elem, data);
+ };
+ wssConfig.setProcessor(new QName(WSConstants.ENC_NS, WSConstants.ENC_KEY_LN), processor);
+ secEngine.processSecurityHeader(document, requestData);
+ return true;
+ } catch (WSSecurityException e) {
+ return createError(e.getMessage());
+ }
+ }
+
+ public static Object decryptEnvelope(BObject documentBuilder, BMap config) {
+ Document encryptedDocument = (Document) documentBuilder.getNativeData(NATIVE_DOCUMENT);
+ BMap keyStore = (BMap) config
+ .getMapValue(StringUtils.fromString(DECRYPT_KEYSTORE));
+ String path = keyStore.get(StringUtils.fromString(PATH)).toString();
+ String password = keyStore.get(StringUtils.fromString(PASSWORD)).toString();
+ WSSecHeader secHeader = new WSSecHeader(encryptedDocument);
+ WSSecurityEngine secEngine = new WSSecurityEngine();
+ RequestData requestData = new RequestData();
+ try {
+ Crypto crypto = getCryptoInstance(path, password);
+ requestData.setSigVerCrypto(crypto);
+ requestData.setDecCrypto(crypto);
+ requestData.setSecHeader(secHeader);
+ CallbackHandler passwordCallbackHandler = callbacks -> {
+ for (Callback callback: callbacks) {
+ ((WSPasswordCallback) callback).setPassword(password);
+ }
+ };
+ requestData.setCallbackHandler(passwordCallbackHandler);
+ secEngine.processSecurityHeader(encryptedDocument, requestData);
+ documentBuilder.addNativeData(NATIVE_DOCUMENT, encryptedDocument);
+ return documentBuilder;
+ } catch (Exception e) {
+ return createError(e.getMessage());
+ }
+ }
+
+ public static Object applyEncryptionOnly(BObject documentBuilder, Boolean soap12,
+ BMap config) {
+ try {
+ Document document = (Document) documentBuilder.getNativeData(NATIVE_DOCUMENT);
+ BMap keyStore = (BMap) config
+ .getMapValue(StringUtils.fromString(KEYSTORE));
+ String path = keyStore.get(StringUtils.fromString(PATH)).toString();
+ String password = keyStore.get(StringUtils.fromString(PASSWORD)).toString();
+ String publicKeyAlias = config.get(StringUtils.fromString(PUBLIC_KEY_ALIAS)).toString();
+ String encryptionAlgorithm = config.get(StringUtils.fromString(ENCRYPTION_ALGORITHM)).toString();
+ validateSoapHeader(soap12, document);
+ Crypto crypto = getCryptoInstance(path, password);
+ WSSecHeader secHeader = new WSSecHeader(document);
+ secHeader.insertSecurityHeader();
+ generateEncryption(publicKeyAlias, crypto, secHeader, encryptionAlgorithm);
+ return convertDocumentToString(document);
+ } catch (Exception e) {
+ return createError(e.getMessage());
+ }
+ }
+
+ public static Object applySignatureAndEncryption(BObject documentBuilder, Boolean soap12,
+ BMap signatureConfig,
+ BMap encryptionConfig) {
+ try {
+ Document document = (Document) documentBuilder.getNativeData(NATIVE_DOCUMENT);
+ BMap keyStore = (BMap) signatureConfig
+ .getMapValue(StringUtils.fromString(KEYSTORE));
+ String path = keyStore.get(StringUtils.fromString(PATH)).toString();
+ String password = keyStore.get(StringUtils.fromString(PASSWORD)).toString();
+ String publicKeyAlias = encryptionConfig.get(StringUtils.fromString(PUBLIC_KEY_ALIAS)).toString();
+ String privateKeyPassword = signatureConfig.get(StringUtils.fromString(PRIVATE_KEY_PASSWORD)).toString();
+ String privateKeyAlias = signatureConfig.get(StringUtils.fromString(PRIVATE_KEY_ALIAS)).toString();
+ String digestAlgorithm = signatureConfig.get(StringUtils.fromString(DIGEST_ALGORITHM)).toString();
+ String canonicalizationAlgorithm = signatureConfig
+ .get(StringUtils.fromString(CANONICALIZATION_ALGORITHM)).toString();
+ String signatureAlgorithm = signatureConfig.get(StringUtils.fromString(SIGNATURE_ALGORITHM)).toString();
+ String encryptionAlgorithm = encryptionConfig.get(StringUtils.fromString(ENCRYPTION_ALGORITHM)).toString();
+ validateSoapHeader(soap12, document);
+ Crypto crypto = getCryptoInstance(path, password);
+ WSSecHeader secHeader = new WSSecHeader(document);
+ secHeader.insertSecurityHeader();
+ generateSignature(privateKeyPassword, privateKeyAlias, digestAlgorithm,
+ canonicalizationAlgorithm, signatureAlgorithm, crypto, secHeader);
+ generateEncryption(publicKeyAlias, crypto, secHeader, encryptionAlgorithm);
+ return convertDocumentToString(document);
+ } catch (Exception e) {
+ return createError(e.getMessage());
+ }
+ }
+
+ private static void generateEncryption(String publicKeyAlias, Crypto crypto,
+ WSSecHeader secHeader, String encryptionAlgorithm) throws Exception {
+ WSSecEncrypt encrypt = new WSSecEncrypt(secHeader);
+ encrypt.setUserInfo(publicKeyAlias);
+ encrypt.setKeyIdentifierType(WSConstants.X509_KEY_IDENTIFIER);
+ encrypt.setSymmetricEncAlgorithm(encryptionAlgorithm);
+ encrypt.setKeyEncAlgo(WSConstants.KEYTRANSPORT_RSAOAEP);
+ SecretKey symmetricKey = generateSymmetricKey();
+ encrypt.build(crypto, symmetricKey);
+ }
+
+ private static void generateSignature(String privateKeyPassword, String privateKeyAlias, String digestAlgorithm,
+ String canonicalizationAlgorithm, String signatureAlgorithm, Crypto crypto,
+ WSSecHeader secHeader) throws WSSecurityException {
+ WSSecSignature signature = new WSSecSignature(secHeader);
+ signature.setUserInfo(privateKeyAlias, privateKeyPassword);
+ signature.setKeyIdentifierType(WSConstants.X509_KEY_IDENTIFIER);
+ signature.setSigCanonicalization(canonicalizationAlgorithm);
+ signature.setDigestAlgo(digestAlgorithm);
+ signature.setSignatureAlgorithm(signatureAlgorithm);
+ signature.build(crypto);
+ }
+
+ public static SecretKey generateSymmetricKey() throws Exception {
+ KeyGenerator keyGen = KeyGenerator.getInstance(AES);
+ keyGen.init(128);
+ return keyGen.generateKey();
+ }
}
diff --git a/native/src/main/resources/META-INF/native-image/io.ballerina.stdlib/soap-native/reflect-config.json b/native/src/main/resources/META-INF/native-image/io.ballerina.stdlib/soap-native/reflect-config.json
index 3cfa8bd..bb037e1 100644
--- a/native/src/main/resources/META-INF/native-image/io.ballerina.stdlib/soap-native/reflect-config.json
+++ b/native/src/main/resources/META-INF/native-image/io.ballerina.stdlib/soap-native/reflect-config.json
@@ -1,17 +1,602 @@
[
-{
- "name":"org.apache.commons.pool.impl.EvictionTimer"
-},
-{
- "name":"org.apache.wss4j.dom.transform.AttachmentCiphertextTransform",
- "methods":[{"name":"","parameterTypes":[] }]
-},
-{
- "name":"org.apache.xml.security.c14n.implementations.CanonicalizerPhysical",
- "methods":[{"name":"","parameterTypes":[] }]
-},
-{
- "name":"org.apache.xml.security.utils.XMLUtils",
- "fields":[{"name":"ignoreLineBreaks"}]
-}
-]
+ {
+ "name":"[B"
+ },
+ {
+ "name":"[Lio.ballerina.runtime.api.types.ResourceMethodType;"
+ },
+ {
+ "name":"[Lio.ballerina.runtime.internal.types.BMethodType;"
+ },
+ {
+ "name":"[Ljava.lang.String;"
+ },
+ {
+ "name":"[Lsun.security.pkcs.SignerInfo;"
+ },
+ {
+ "name":"apple.security.AppleProvider",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"ballerina.soap&0046soap11$test.1.$_init",
+ "methods":[{"name":"$getTestExecutionState","parameterTypes":[] }, {"name":"main","parameterTypes":["java.lang.String[]"] }]
+ },
+ {
+ "name":"ballerina.soap&0046soap12$test.1.$_init",
+ "methods":[{"name":"$getTestExecutionState","parameterTypes":[] }, {"name":"main","parameterTypes":["java.lang.String[]"] }]
+ },
+ {
+ "name":"ballerina.soap&0046wssec$test.1.$_init",
+ "methods":[{"name":"$getTestExecutionState","parameterTypes":[] }, {"name":"main","parameterTypes":["java.lang.String[]"] }]
+ },
+ {
+ "name":"com.aayushatharva.brotli4j.Brotli4jLoader"
+ },
+ {
+ "name":"com.sun.crypto.provider.AESCipher$General",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"com.sun.crypto.provider.AESKeyGenerator",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"com.sun.crypto.provider.GaloisCounterMode$AESGCM",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"com.sun.crypto.provider.HmacCore$HmacSHA256",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"com.sun.crypto.provider.HmacPKCS12PBECore$HmacPKCS12PBE_SHA1",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"com.sun.crypto.provider.HmacPKCS12PBECore$HmacPKCS12PBE_SHA256",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"com.sun.crypto.provider.HmacSHA1",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"com.sun.crypto.provider.PBEKeyFactory$PBEWithMD5AndDES",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"com.sun.crypto.provider.PBEParameters",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"com.sun.crypto.provider.PBES2Core$HmacSHA256AndAES_256",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"com.sun.crypto.provider.PBES2Parameters$General",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"com.sun.crypto.provider.PKCS12PBECipherCore$PBEWithSHA1AndDESede",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"com.sun.crypto.provider.PKCS12PBECipherCore$PBEWithSHA1AndRC2_40",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"com.sun.crypto.provider.RSACipher",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"com.sun.org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"io.ballerina.stdlib.http.transport.contractimpl.DefaultHttpClientUpgradeHandler"
+ },
+ {
+ "name":"io.ballerina.stdlib.http.transport.contractimpl.common.http2.Http2ExceptionHandler",
+ "methods":[{"name":"exceptionCaught","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Throwable"] }]
+ },
+ {
+ "name":"io.ballerina.stdlib.http.transport.contractimpl.listener.CustomHttpContentCompressor"
+ },
+ {
+ "name":"io.ballerina.stdlib.http.transport.contractimpl.listener.HttpServerChannelInitializer"
+ },
+ {
+ "name":"io.ballerina.stdlib.http.transport.contractimpl.listener.http2.Http2SourceConnectionHandler",
+ "methods":[{"name":"channelInactive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }]
+ },
+ {
+ "name":"io.ballerina.stdlib.http.transport.contractimpl.listener.http2.Http2SourceHandler",
+ "methods":[{"name":"channelActive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelInactive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }, {"name":"channelUnregistered","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"userEventTriggered","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }]
+ },
+ {
+ "name":"io.ballerina.stdlib.http.transport.contractimpl.listener.http2.Http2ToHttpFallbackHandler",
+ "methods":[{"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }]
+ },
+ {
+ "name":"io.ballerina.stdlib.http.transport.contractimpl.listener.http2.Http2WithPriorKnowledgeHandler",
+ "methods":[{"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }]
+ },
+ {
+ "name":"io.ballerina.stdlib.http.transport.contractimpl.sender.HttpClientChannelInitializer",
+ "methods":[{"name":"exceptionCaught","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Throwable"] }]
+ },
+ {
+ "name":"io.ballerina.stdlib.http.transport.contractimpl.sender.StatusLineAndHeaderLengthValidator",
+ "methods":[{"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }]
+ },
+ {
+ "name":"io.ballerina.stdlib.http.transport.contractimpl.sender.TargetHandler",
+ "methods":[{"name":"channelActive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelInactive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }, {"name":"exceptionCaught","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Throwable"] }, {"name":"userEventTriggered","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }]
+ },
+ {
+ "name":"io.ballerina.stdlib.http.transport.contractimpl.sender.http2.Http2TargetHandler",
+ "methods":[{"name":"channelInactive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }, {"name":"write","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object","io.netty.channel.ChannelPromise"] }]
+ },
+ {
+ "name":"io.netty.bootstrap.ServerBootstrap$1"
+ },
+ {
+ "name":"io.netty.bootstrap.ServerBootstrap$ServerBootstrapAcceptor",
+ "methods":[{"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }, {"name":"exceptionCaught","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Throwable"] }]
+ },
+ {
+ "name":"io.netty.buffer.AbstractByteBufAllocator",
+ "queryAllDeclaredMethods":true
+ },
+ {
+ "name":"io.netty.buffer.AbstractReferenceCountedByteBuf",
+ "fields":[{"name":"refCnt"}]
+ },
+ {
+ "name":"io.netty.channel.AbstractChannelHandlerContext",
+ "fields":[{"name":"handlerState"}]
+ },
+ {
+ "name":"io.netty.channel.ChannelDuplexHandler",
+ "methods":[{"name":"bind","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.net.SocketAddress","io.netty.channel.ChannelPromise"] }, {"name":"close","parameterTypes":["io.netty.channel.ChannelHandlerContext","io.netty.channel.ChannelPromise"] }, {"name":"connect","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.net.SocketAddress","java.net.SocketAddress","io.netty.channel.ChannelPromise"] }, {"name":"deregister","parameterTypes":["io.netty.channel.ChannelHandlerContext","io.netty.channel.ChannelPromise"] }, {"name":"disconnect","parameterTypes":["io.netty.channel.ChannelHandlerContext","io.netty.channel.ChannelPromise"] }, {"name":"flush","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"read","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }]
+ },
+ {
+ "name":"io.netty.channel.ChannelInboundHandlerAdapter",
+ "methods":[{"name":"channelActive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelInactive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }, {"name":"channelReadComplete","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelRegistered","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelUnregistered","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelWritabilityChanged","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"exceptionCaught","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Throwable"] }, {"name":"userEventTriggered","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }]
+ },
+ {
+ "name":"io.netty.channel.ChannelInitializer",
+ "methods":[{"name":"channelRegistered","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"exceptionCaught","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Throwable"] }]
+ },
+ {
+ "name":"io.netty.channel.ChannelOutboundBuffer",
+ "fields":[{"name":"totalPendingSize"}, {"name":"unwritable"}]
+ },
+ {
+ "name":"io.netty.channel.CombinedChannelDuplexHandler",
+ "methods":[{"name":"bind","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.net.SocketAddress","io.netty.channel.ChannelPromise"] }, {"name":"channelActive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelInactive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }, {"name":"channelReadComplete","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelRegistered","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelUnregistered","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelWritabilityChanged","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"close","parameterTypes":["io.netty.channel.ChannelHandlerContext","io.netty.channel.ChannelPromise"] }, {"name":"connect","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.net.SocketAddress","java.net.SocketAddress","io.netty.channel.ChannelPromise"] }, {"name":"deregister","parameterTypes":["io.netty.channel.ChannelHandlerContext","io.netty.channel.ChannelPromise"] }, {"name":"disconnect","parameterTypes":["io.netty.channel.ChannelHandlerContext","io.netty.channel.ChannelPromise"] }, {"name":"exceptionCaught","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Throwable"] }, {"name":"flush","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"read","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"userEventTriggered","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }, {"name":"write","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object","io.netty.channel.ChannelPromise"] }]
+ },
+ {
+ "name":"io.netty.channel.DefaultChannelConfig",
+ "fields":[{"name":"autoRead"}, {"name":"writeBufferWaterMark"}]
+ },
+ {
+ "name":"io.netty.channel.DefaultChannelPipeline",
+ "fields":[{"name":"estimatorHandle"}]
+ },
+ {
+ "name":"io.netty.channel.DefaultChannelPipeline$HeadContext",
+ "methods":[{"name":"bind","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.net.SocketAddress","io.netty.channel.ChannelPromise"] }, {"name":"channelActive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelInactive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }, {"name":"channelReadComplete","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelRegistered","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelUnregistered","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelWritabilityChanged","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"close","parameterTypes":["io.netty.channel.ChannelHandlerContext","io.netty.channel.ChannelPromise"] }, {"name":"connect","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.net.SocketAddress","java.net.SocketAddress","io.netty.channel.ChannelPromise"] }, {"name":"deregister","parameterTypes":["io.netty.channel.ChannelHandlerContext","io.netty.channel.ChannelPromise"] }, {"name":"disconnect","parameterTypes":["io.netty.channel.ChannelHandlerContext","io.netty.channel.ChannelPromise"] }, {"name":"exceptionCaught","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Throwable"] }, {"name":"flush","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"read","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"userEventTriggered","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }, {"name":"write","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object","io.netty.channel.ChannelPromise"] }]
+ },
+ {
+ "name":"io.netty.channel.DefaultChannelPipeline$TailContext",
+ "methods":[{"name":"channelActive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelInactive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }, {"name":"channelReadComplete","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelRegistered","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelUnregistered","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelWritabilityChanged","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"exceptionCaught","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Throwable"] }, {"name":"userEventTriggered","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }]
+ },
+ {
+ "name":"io.netty.channel.socket.nio.NioServerSocketChannel",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"io.netty.channel.socket.nio.NioSocketChannel",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"io.netty.handler.codec.ByteToMessageDecoder",
+ "methods":[{"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }, {"name":"userEventTriggered","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }]
+ },
+ {
+ "name":"io.netty.handler.codec.MessageAggregator",
+ "methods":[{"name":"channelInactive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelReadComplete","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }]
+ },
+ {
+ "name":"io.netty.handler.codec.MessageToMessageCodec",
+ "methods":[{"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }, {"name":"write","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object","io.netty.channel.ChannelPromise"] }]
+ },
+ {
+ "name":"io.netty.handler.codec.MessageToMessageDecoder",
+ "methods":[{"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }]
+ },
+ {
+ "name":"io.netty.handler.codec.http.HttpClientCodec"
+ },
+ {
+ "name":"io.netty.handler.codec.http.HttpClientUpgradeHandler",
+ "methods":[{"name":"bind","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.net.SocketAddress","io.netty.channel.ChannelPromise"] }, {"name":"close","parameterTypes":["io.netty.channel.ChannelHandlerContext","io.netty.channel.ChannelPromise"] }, {"name":"connect","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.net.SocketAddress","java.net.SocketAddress","io.netty.channel.ChannelPromise"] }, {"name":"deregister","parameterTypes":["io.netty.channel.ChannelHandlerContext","io.netty.channel.ChannelPromise"] }, {"name":"disconnect","parameterTypes":["io.netty.channel.ChannelHandlerContext","io.netty.channel.ChannelPromise"] }, {"name":"flush","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"read","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"write","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object","io.netty.channel.ChannelPromise"] }]
+ },
+ {
+ "name":"io.netty.handler.codec.http.HttpContentDecoder",
+ "methods":[{"name":"channelInactive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelReadComplete","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }]
+ },
+ {
+ "name":"io.netty.handler.codec.http.HttpContentDecompressor"
+ },
+ {
+ "name":"io.netty.handler.codec.http.HttpContentEncoder",
+ "methods":[{"name":"channelInactive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }]
+ },
+ {
+ "name":"io.netty.handler.codec.http.HttpServerCodec"
+ },
+ {
+ "name":"io.netty.handler.codec.http.HttpServerUpgradeHandler"
+ },
+ {
+ "name":"io.netty.handler.codec.http2.Http2ConnectionHandler",
+ "methods":[{"name":"bind","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.net.SocketAddress","io.netty.channel.ChannelPromise"] }, {"name":"channelActive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelInactive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelReadComplete","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelWritabilityChanged","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"close","parameterTypes":["io.netty.channel.ChannelHandlerContext","io.netty.channel.ChannelPromise"] }, {"name":"connect","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.net.SocketAddress","java.net.SocketAddress","io.netty.channel.ChannelPromise"] }, {"name":"deregister","parameterTypes":["io.netty.channel.ChannelHandlerContext","io.netty.channel.ChannelPromise"] }, {"name":"disconnect","parameterTypes":["io.netty.channel.ChannelHandlerContext","io.netty.channel.ChannelPromise"] }, {"name":"exceptionCaught","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Throwable"] }, {"name":"flush","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"read","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"write","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object","io.netty.channel.ChannelPromise"] }]
+ },
+ {
+ "name":"io.netty.handler.timeout.IdleStateHandler",
+ "methods":[{"name":"channelActive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelInactive","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelRead","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object"] }, {"name":"channelReadComplete","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"channelRegistered","parameterTypes":["io.netty.channel.ChannelHandlerContext"] }, {"name":"write","parameterTypes":["io.netty.channel.ChannelHandlerContext","java.lang.Object","io.netty.channel.ChannelPromise"] }]
+ },
+ {
+ "name":"io.netty.util.DefaultAttributeMap",
+ "fields":[{"name":"attributes"}]
+ },
+ {
+ "name":"io.netty.util.DefaultAttributeMap$DefaultAttribute",
+ "fields":[{"name":"attributeMap"}]
+ },
+ {
+ "name":"io.netty.util.Recycler$DefaultHandle",
+ "fields":[{"name":"state"}]
+ },
+ {
+ "name":"io.netty.util.ReferenceCountUtil",
+ "queryAllDeclaredMethods":true
+ },
+ {
+ "name":"io.netty.util.ResourceLeakDetector$DefaultResourceLeak",
+ "fields":[{"name":"droppedRecords"}, {"name":"head"}]
+ },
+ {
+ "name":"io.netty.util.concurrent.DefaultPromise",
+ "fields":[{"name":"result"}]
+ },
+ {
+ "name":"io.netty.util.concurrent.SingleThreadEventExecutor",
+ "fields":[{"name":"state"}, {"name":"threadProperties"}]
+ },
+ {
+ "name":"io.netty.util.internal.shaded.org.jctools.queues.BaseMpscLinkedArrayQueueColdProducerFields",
+ "fields":[{"name":"producerLimit"}]
+ },
+ {
+ "name":"io.netty.util.internal.shaded.org.jctools.queues.BaseMpscLinkedArrayQueueConsumerFields",
+ "fields":[{"name":"consumerIndex"}]
+ },
+ {
+ "name":"io.netty.util.internal.shaded.org.jctools.queues.BaseMpscLinkedArrayQueueProducerFields",
+ "fields":[{"name":"producerIndex"}]
+ },
+ {
+ "name":"io.netty.util.internal.shaded.org.jctools.queues.MpscArrayQueueConsumerIndexField",
+ "fields":[{"name":"consumerIndex"}]
+ },
+ {
+ "name":"io.netty.util.internal.shaded.org.jctools.queues.MpscArrayQueueProducerIndexField",
+ "fields":[{"name":"producerIndex"}]
+ },
+ {
+ "name":"io.netty.util.internal.shaded.org.jctools.queues.MpscArrayQueueProducerLimitField",
+ "fields":[{"name":"producerLimit"}]
+ },
+ {
+ "name":"java.lang.Class",
+ "methods":[{"name":"getRecordComponents","parameterTypes":[] }, {"name":"isRecord","parameterTypes":[] }]
+ },
+ {
+ "name":"java.lang.ProcessHandle",
+ "methods":[{"name":"current","parameterTypes":[] }, {"name":"pid","parameterTypes":[] }]
+ },
+ {
+ "name":"java.lang.String"
+ },
+ {
+ "name":"java.lang.Thread",
+ "fields":[{"name":"threadLocalRandomProbe"}],
+ "methods":[{"name":"getContextClassLoader","parameterTypes":[] }]
+ },
+ {
+ "name":"java.lang.reflect.RecordComponent",
+ "methods":[{"name":"getName","parameterTypes":[] }, {"name":"getType","parameterTypes":[] }]
+ },
+ {
+ "name":"java.nio.Bits",
+ "fields":[{"name":"MAX_MEMORY"}, {"name":"UNALIGNED"}]
+ },
+ {
+ "name":"java.nio.Buffer",
+ "fields":[{"name":"address"}]
+ },
+ {
+ "name":"java.nio.ByteBuffer",
+ "methods":[{"name":"alignedSlice","parameterTypes":["int"] }]
+ },
+ {
+ "name":"java.nio.DirectByteBuffer",
+ "methods":[{"name":"","parameterTypes":["long","int"] }]
+ },
+ {
+ "name":"java.nio.channels.spi.SelectorProvider",
+ "methods":[{"name":"openServerSocketChannel","parameterTypes":["java.net.ProtocolFamily"] }, {"name":"openSocketChannel","parameterTypes":["java.net.ProtocolFamily"] }]
+ },
+ {
+ "name":"java.security.AlgorithmParametersSpi"
+ },
+ {
+ "name":"java.security.KeyStoreSpi"
+ },
+ {
+ "name":"java.security.MessageDigestSpi"
+ },
+ {
+ "name":"java.security.SecureRandomParameters"
+ },
+ {
+ "name":"java.security.interfaces.DSAPrivateKey"
+ },
+ {
+ "name":"java.security.interfaces.DSAPublicKey"
+ },
+ {
+ "name":"java.security.interfaces.RSAPrivateKey"
+ },
+ {
+ "name":"java.security.interfaces.RSAPublicKey"
+ },
+ {
+ "name":"java.security.spec.DSAParameterSpec"
+ },
+ {
+ "name":"java.sql.Date"
+ },
+ {
+ "name":"java.util.Date"
+ },
+ {
+ "name":"java.util.concurrent.atomic.AtomicBoolean",
+ "fields":[{"name":"value"}]
+ },
+ {
+ "name":"java.util.concurrent.atomic.AtomicReference",
+ "fields":[{"name":"value"}]
+ },
+ {
+ "name":"java.util.concurrent.atomic.Striped64",
+ "fields":[{"name":"base"}, {"name":"cellsBusy"}]
+ },
+ {
+ "name":"javax.security.auth.x500.X500Principal",
+ "fields":[{"name":"thisX500Name"}],
+ "methods":[{"name":"","parameterTypes":["sun.security.x509.X500Name"] }]
+ },
+ {
+ "name":"jdk.internal.misc.Unsafe",
+ "methods":[{"name":"getUnsafe","parameterTypes":[] }]
+ },
+ {
+ "name":"org.apache.axiom.locator.DefaultOMMetaFactoryLocator",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"org.apache.axiom.om.impl.llom.factory.AxiomNodeFactoryImpl",
+ "fields":[{"name":"INSTANCE"}]
+ },
+ {
+ "name":"org.apache.axiom.om.impl.llom.factory.OMLinkedListMetaFactoryLoader",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"org.apache.commons.logging.LogFactory"
+ },
+ {
+ "name":"org.apache.commons.logging.impl.Jdk14Logger",
+ "methods":[{"name":"","parameterTypes":["java.lang.String"] }, {"name":"setLogFactory","parameterTypes":["org.apache.commons.logging.LogFactory"] }]
+ },
+ {
+ "name":"org.apache.commons.logging.impl.Log4JLogger"
+ },
+ {
+ "name":"org.apache.commons.logging.impl.LogFactoryImpl",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"org.apache.commons.logging.impl.WeakHashtable",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"org.apache.commons.pool.impl.EvictionTimer"
+ },
+ {
+ "name":"org.apache.wss4j.dom.processor.EncryptedKeyProcessor",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"org.apache.wss4j.dom.processor.SignatureProcessor",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"org.apache.wss4j.dom.processor.TimestampProcessor",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"org.apache.wss4j.dom.processor.UsernameTokenProcessor",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"org.apache.wss4j.dom.transform.AttachmentCiphertextTransform",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"org.apache.wss4j.dom.validate.SignatureTrustValidator",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"org.apache.wss4j.dom.validate.TimestampValidator",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"org.apache.wss4j.dom.validate.UsernameTokenValidator",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"org.apache.xml.security.c14n.implementations.CanonicalizerPhysical",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"org.apache.xml.security.utils.XMLUtils",
+ "fields":[{"name":"ignoreLineBreaks"}]
+ },
+ {
+ "name":"org.ballerinalang.test.runtime.entity.Test",
+ "allDeclaredFields":true,
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"org.ballerinalang.test.runtime.entity.TestGroup",
+ "allDeclaredFields":true,
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"org.ballerinalang.test.runtime.entity.TestSuite",
+ "allDeclaredFields":true,
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"org.bouncycastle.asn1.x500.X500Name",
+ "methods":[{"name":"","parameterTypes":["java.lang.String"] }]
+ },
+ {
+ "name":"sun.misc.Unsafe",
+ "fields":[{"name":"theUnsafe"}],
+ "methods":[{"name":"allocateInstance","parameterTypes":["java.lang.Class"] }, {"name":"copyMemory","parameterTypes":["java.lang.Object","long","java.lang.Object","long","long"] }, {"name":"getAndAddLong","parameterTypes":["java.lang.Object","long","long"] }, {"name":"getAndSetObject","parameterTypes":["java.lang.Object","long","java.lang.Object"] }, {"name":"invokeCleaner","parameterTypes":["java.nio.ByteBuffer"] }, {"name":"storeFence","parameterTypes":[] }]
+ },
+ {
+ "name":"sun.nio.ch.SelectorImpl",
+ "fields":[{"name":"publicSelectedKeys"}, {"name":"selectedKeys"}]
+ },
+ {
+ "name":"sun.security.pkcs12.PKCS12KeyStore",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"sun.security.pkcs12.PKCS12KeyStore$DualFormatPKCS12",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"sun.security.provider.DSA$SHA256withDSA",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"sun.security.provider.DSAKeyFactory",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"sun.security.provider.DSAParameters",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"sun.security.provider.NativePRNG",
+ "methods":[{"name":"","parameterTypes":[] }, {"name":"","parameterTypes":["java.security.SecureRandomParameters"] }]
+ },
+ {
+ "name":"sun.security.provider.SHA",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"sun.security.provider.SHA2$SHA256",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"sun.security.provider.SHA5$SHA512",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"sun.security.provider.X509Factory",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"sun.security.rsa.RSAKeyFactory$Legacy",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"sun.security.rsa.RSASignature$SHA1withRSA",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"sun.security.rsa.RSASignature$SHA256withRSA",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"sun.security.rsa.RSASignature$SHA512withRSA",
+ "methods":[{"name":"","parameterTypes":[] }]
+ },
+ {
+ "name":"sun.security.util.ObjectIdentifier"
+ },
+ {
+ "name":"sun.security.x509.AuthorityInfoAccessExtension",
+ "methods":[{"name":"","parameterTypes":["java.lang.Boolean","java.lang.Object"] }]
+ },
+ {
+ "name":"sun.security.x509.AuthorityKeyIdentifierExtension",
+ "methods":[{"name":"","parameterTypes":["java.lang.Boolean","java.lang.Object"] }]
+ },
+ {
+ "name":"sun.security.x509.BasicConstraintsExtension",
+ "methods":[{"name":"","parameterTypes":["java.lang.Boolean","java.lang.Object"] }]
+ },
+ {
+ "name":"sun.security.x509.CRLDistributionPointsExtension",
+ "methods":[{"name":"","parameterTypes":["java.lang.Boolean","java.lang.Object"] }]
+ },
+ {
+ "name":"sun.security.x509.CertificateExtensions"
+ },
+ {
+ "name":"sun.security.x509.CertificatePoliciesExtension",
+ "methods":[{"name":"","parameterTypes":["java.lang.Boolean","java.lang.Object"] }]
+ },
+ {
+ "name":"sun.security.x509.ExtendedKeyUsageExtension",
+ "methods":[{"name":"","parameterTypes":["java.lang.Boolean","java.lang.Object"] }]
+ },
+ {
+ "name":"sun.security.x509.KeyUsageExtension",
+ "methods":[{"name":"","parameterTypes":["java.lang.Boolean","java.lang.Object"] }]
+ },
+ {
+ "name":"sun.security.x509.SubjectKeyIdentifierExtension",
+ "methods":[{"name":"","parameterTypes":["java.lang.Boolean","java.lang.Object"] }]
+ }
+ ]
+
\ No newline at end of file
diff --git a/native/src/main/resources/META-INF/native-image/io.ballerina.stdlib/soap-native/resource-config.json b/native/src/main/resources/META-INF/native-image/io.ballerina.stdlib/soap-native/resource-config.json
index f9fda78..ee39d35 100644
--- a/native/src/main/resources/META-INF/native-image/io.ballerina.stdlib/soap-native/resource-config.json
+++ b/native/src/main/resources/META-INF/native-image/io.ballerina.stdlib/soap-native/resource-config.json
@@ -1,9 +1,26 @@
{
"resources":{
"includes":[{
+ "pattern":"\\QMETA-INF/axiom.xml\\E"
+ }, {
+ "pattern":"\\QMETA-INF/services/javax.xml.stream.XMLInputFactory\\E"
+ }, {
+ "pattern":"\\QMETA-INF/services/javax.xml.stream.XMLOutputFactory\\E"
+ }, {
"pattern":"\\QMETA-INF/services/org.slf4j.spi.SLF4JServiceProvider\\E"
+ }, {
+ "pattern":"\\Qlogging.properties\\E"
+ }, {
+ "pattern":"java.base:\\Qjdk/internal/icu/impl/data/icudt67b/nfc.nrm\\E"
+ }, {
+ "pattern":"java.base:\\Qjdk/internal/icu/impl/data/icudt67b/nfkc.nrm\\E"
+ }, {
+ "pattern":"java.xml:\\Qcom/sun/org/apache/xml/internal/serializer/Encodings.properties\\E"
}]},
"bundles":[{
+ "name":"com.sun.org.apache.xml.internal.serializer.XMLEntities",
+ "locales":[""]
+ }, {
"name":"messages.wss4j_errors",
"locales":[""]
}, {