Skip to content

Commit

Permalink
Add necessary configuration fixes to verify and decrypt envelopes
Browse files Browse the repository at this point in the history
  • Loading branch information
Nuvindu committed Oct 14, 2024
1 parent 4b1fb24 commit d12c15e
Show file tree
Hide file tree
Showing 14 changed files with 181 additions and 193 deletions.
3 changes: 2 additions & 1 deletion ballerina/configs.bal
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
// under the License.

import ballerina/http;
import soap.wssec;

# SOAP client configurations.
#
Expand All @@ -24,5 +25,5 @@ import ballerina/http;
public type ClientConfig record {|
http:ClientConfiguration httpConfig = {};
OutboundSecurityConfig|OutboundSecurityConfig[] outboundSecurity = NO_POLICY;
InboundSecurityConfig inboundSecurity = {};
wssec:InboundConfig inboundSecurity = {};
|};
5 changes: 3 additions & 2 deletions ballerina/modules/soap11/soap11.bal
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ 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 {
Expand Down Expand Up @@ -85,9 +86,9 @@ public isolated client class Client {
do {
if inboundSecurity is soap:InboundSecurityConfig && inboundSecurity != {} {
if response is xml {
return check soap:applyOutboundConfig(inboundSecurity.clone(), response.clone(), false);
return check soap:applyOutboundConfig(<wssec:InboundConfig>inboundSecurity.clone(), response.clone(), false);
} else {
return check soap:applyOutboundConfig(inboundSecurity.clone(),
return check soap:applyOutboundConfig(<wssec:InboundConfig>inboundSecurity.clone(),
check response[0].getXml().clone(), false);
}
}
Expand Down
3 changes: 2 additions & 1 deletion ballerina/modules/soap11/tests/http_soap_service.bal
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import ballerina/crypto;
import ballerina/http;
import ballerina/mime;
import ballerina/soap;
import soap.wssec;

const crypto:KeyStore serverKeyStore = {
path: X509_KEY_STORE_PATH,
Expand Down Expand Up @@ -83,7 +84,7 @@ service / on new http:Listener(9090) {
{
verificationKey: clientPublicKey,
signatureAlgorithm: soap:RSA_SHA256,
decryptionAlgorithm: soap:RSA_ECB,
decryptionAlgorithm: wssec:AES_128,
decryptionKey: serverPrivateKey
},
payload,
Expand Down
21 changes: 13 additions & 8 deletions ballerina/modules/soap11/tests/soap11_client_test.bal
Original file line number Diff line number Diff line change
Expand Up @@ -383,24 +383,29 @@ function testSoapEndpoint() returns error? {
@test:Config {
groups: ["soap11", "send_receive"]
}
function testSoapReceiveWithSymmetricBindingAndOutboundConfig() returns error? {
function testSoapReceiveWithAsymmetricBindingAndInboundConfig() returns error? {
xmlns "http://schemas.xmlsoap.org/soap/envelope/" as soap11;
Client soapClient = check new ("http://localhost:9090",
{
outboundSecurity: {
signatureAlgorithm: wssec:RSA_SHA256,
encryptionAlgorithm: wssec:RSA_ECB,
symmetricKey: symmetricKey,
servicePublicKey: serverPublicKey
encryptionConfig: {
keystore: {
path: KEY_STORE_PATH_2,
password: PASSWORD
},
publicKeyAlias: ALIAS,
encryptionAlgorithm: wssec:AES_128
}
},
inboundSecurity: {
keystore: {path: KEY_STORE_PATH_2, password: PASSWORD},
verificationKey: publicKey,
signatureAlgorithm: wssec:RSA_SHA256,
decryptionAlgorithm: wssec:RSA_ECB,
decryptionKey: publicKey
decryptionAlgorithm: wssec:AES_128
}
}
);
xml body = xml `<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><soap:Body><quer:Add xmlns:quer="http://tempuri.org/"><quer:intA>2</quer:intA><quer:intB>3</quer:intB></quer:Add></soap:Body></soap:Envelope>`;
xml response = check soapClient->sendReceive(body, "http://tempuri.org/Add", path = "/getSamePayload");
return soap:assertSymmetricBinding(response.toString(), string `<soap:Body><quer:Add xmlns:quer="http://tempuri.org/"><quer:intA>2</quer:intA><quer:intB>3</quer:intB></quer:Add></soap:Body>`);
test:assertEquals((response/<soap11:Body>).toString(), (body/<soap11:Body>).toString());
}
7 changes: 4 additions & 3 deletions ballerina/modules/soap12/soap12.bal
Original file line number Diff line number Diff line change
Expand Up @@ -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:OutboundSecurityConfig|soap:OutboundSecurityConfig[] outboundSecurity;
private final readonly & soap:InboundSecurityConfig inboundSecurity;
private final readonly & wssec:InboundConfig inboundSecurity;

# Gets invoked during object initialization.
#
Expand Down Expand Up @@ -81,9 +82,9 @@ public isolated client class Client {
response = check soap:sendReceive(securedBody, self.soapClient, action, headers, path);
}
lock {
soap:InboundSecurityConfig? inboundSecurity = self.inboundSecurity.clone();
wssec:InboundConfig? inboundSecurity = self.inboundSecurity.clone();
do {
if inboundSecurity is soap:InboundSecurityConfig && inboundSecurity != {} {
if inboundSecurity is wssec:InboundConfig && inboundSecurity != {} {
if response is xml {
return check soap:applyOutboundConfig(inboundSecurity.clone(), response.clone());
} else {
Expand Down
5 changes: 3 additions & 2 deletions ballerina/modules/soap12/tests/http_soap_service.bal
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import ballerina/crypto;
import ballerina/http;
import ballerina/mime;
import ballerina/soap;
import soap.wssec;

const crypto:KeyStore serverKeyStore = {
path: X509_KEY_STORE_PATH,
Expand Down Expand Up @@ -82,7 +83,7 @@ service / on new http:Listener(9090) {
{
verificationKey: clientPublicKey,
signatureAlgorithm: soap:RSA_SHA256,
decryptionAlgorithm: soap:RSA_ECB,
decryptionAlgorithm: wssec:AES_128,
decryptionKey: serverPrivateKey
},
payload
Expand All @@ -96,7 +97,7 @@ service / on new http:Listener(9090) {
{
verificationKey: clientPublicKey,
signatureAlgorithm: soap:RSA_SHA256,
decryptionAlgorithm: soap:RSA_ECB,
decryptionAlgorithm: wssec:AES_128,
decryptionKey: serverPrivateKey
},
payload
Expand Down
32 changes: 19 additions & 13 deletions ballerina/modules/soap12/tests/soap12_client_test.bal
Original file line number Diff line number Diff line change
Expand Up @@ -414,27 +414,33 @@ 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",
{
outboundSecurity: {
signatureAlgorithm: wssec:RSA_SHA256,
encryptionAlgorithm: wssec:RSA_ECB,
symmetricKey: symmetricKey,
servicePublicKey: serverPublicKey
encryptionConfig: {
keystore: {
path: KEY_STORE_PATH_2,
password: PASSWORD
},
publicKeyAlias: ALIAS,
encryptionAlgorithm: wssec:AES_128
}
},
inboundSecurity: {
verificationKey: publicKey,
signatureAlgorithm: wssec:RSA_SHA256,
decryptionAlgorithm: wssec:RSA_ECB,
decryptionKey: publicKey
keystore: {
path: KEY_STORE_PATH_2,
password: PASSWORD
},
decryptionAlgorithm: wssec:AES_128
}
}
);
xml body = xml `<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" soap:encodingStyle="http://www.w3.org/2003/05/soap-encoding/"><soap:Body><quer:Add xmlns:quer="http://tempuri.org/"><quer:intA>2</quer:intA><quer:intB>3</quer:intB></quer:Add></soap:Body></soap:Envelope>`;
xml response = check soapClient->sendReceive(body, "http://tempuri.org/Add", path = "/getSamePayload");
return soap:assertSymmetricBinding(response.toString(), string `<soap:Body><quer:Add xmlns:quer="http://tempuri.org/"><quer:intA>2</quer:intA><quer:intB>3</quer:intB></quer:Add></soap:Body>`);
xml response = check soapClient->sendReceive(body, "http://tempuri.org/Add");
test:assertEquals((response/<soap11:Body>).toString(), (body/<soap11:Body>).toString());
}

19 changes: 2 additions & 17 deletions ballerina/modules/wssec/records.bal
Original file line number Diff line number Diff line change
Expand Up @@ -66,21 +66,6 @@ public type SymmetricBindingConfig record {|
string x509Token?;
|};

// # Represents the record for Username Token with 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
// public type AsymmetricBindingConfig record {|
// crypto:PrivateKey signatureKey?;
// crypto:PublicKey encryptionKey?;
// SignatureAlgorithm signatureAlgorithm?;
// EncryptionAlgorithm encryptionAlgorithm?;
// string x509Token?;
// |};

public type AsymmetricConfig record {|
SignatureConfig signatureConfig?;
EncryptionConfig encryptionConfig?;
Expand All @@ -99,7 +84,7 @@ public type SignatureConfig record {|
public type EncryptionConfig record {|
crypto:KeyStore keystore;
string publicKeyAlias;
SymmetricAlgorithm symmetricAlgorithm?;
EncryptionAlgorithm encryptionAlgorithm?;
|};

# Represents the record for Transport Binding policy.
Expand All @@ -116,7 +101,7 @@ public type NoPolicy "NoPolicy";
# + signatureAlgorithm - The algorithm to verify the SOAP envelope
# + decryptionAlgorithm - The algorithm to decrypt the SOAP body
public type InboundConfig record {|
crypto:KeyStore keystore;
crypto:KeyStore keystore?;
crypto:PublicKey verificationKey?;
SignatureAlgorithm signatureAlgorithm?;
crypto:PrivateKey|crypto:PublicKey decryptionKey?;
Expand Down
24 changes: 13 additions & 11 deletions ballerina/modules/wssec/tests/ws_security_tests.bal
Original file line number Diff line number Diff line change
Expand Up @@ -235,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
};
Expand Down Expand Up @@ -263,7 +263,7 @@ function testSymmetricBindingWithSignatureAndEncryption() returns error? {

SymmetricBindingConfig symmetricBinding = {
signatureAlgorithm: RSA_SHA256,
encryptionAlgorithm: RSA_ECB,
encryptionAlgorithm: AES_128,
symmetricKey: symmetricKey,
servicePublicKey: serverPublicKey
};
Expand Down Expand Up @@ -297,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
Expand Down Expand Up @@ -341,7 +341,7 @@ function testUsernameTokenWithSymmetricBinding() returns error? {

SymmetricBindingConfig symmetricBinding = {
signatureAlgorithm: RSA_SHA256,
encryptionAlgorithm: RSA_ECB,
encryptionAlgorithm: AES_128,
symmetricKey: symmetricKey,
servicePublicKey: serverPublicKey
};
Expand Down Expand Up @@ -398,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
Expand Down Expand Up @@ -448,7 +448,7 @@ function testSymmetricBindingWithOutboundConfig() returns error? {

SymmetricBindingConfig symmetricBinding = {
signatureAlgorithm: RSA_SHA256,
encryptionAlgorithm: RSA_ECB,
encryptionAlgorithm: AES_128,
symmetricKey: symmetricKey,
servicePublicKey: serverPublicKey
};
Expand All @@ -459,7 +459,7 @@ function testSymmetricBindingWithOutboundConfig() returns error? {
InboundSecurityConfig outboundConfig = {
verificationKey: publicKey,
signatureAlgorithm: RSA_SHA256,
decryptionAlgorithm: RSA_ECB,
decryptionAlgorithm: AES_128,
decryptionKey: publicKey
};

Expand Down Expand Up @@ -678,7 +678,7 @@ function testAsymmetricBindingWithSignatureWithRsaSha512() returns error? {
}

@test:Config {
groups: ["username_token", "signature", "symmetric_binding", "new"]
groups: ["username_token", "signature", "symmetric_binding", "new4"]
}
function testAsymmetricBindingPolicyWithSignatureAndEncryption() returns error? {
xml envelope = check io:fileReadXml(SOAP_ENVELOPE_PATH);
Expand All @@ -701,7 +701,8 @@ function testAsymmetricBindingPolicyWithSignatureAndEncryption() returns error?
path: KEY_STORE_PATH_2,
password: PASSWORD
},
publicKeyAlias: ALIAS
publicKeyAlias: ALIAS,
encryptionAlgorithm: AES_128
}
};
xml securedEnvelope = check applyAsymmetricConfigurations(envelope, false, asymmetricConfig);
Expand All @@ -720,7 +721,7 @@ function testAsymmetricBindingPolicyWithSignatureAndEncryption() returns error?
}

@test:Config {
groups: ["username_token", "signature", "symmetric_binding", "new"]
groups: ["username_token", "signature", "symmetric_binding", "new3"]
}
function testAsymmetricBindingPolicyWithEncryption() returns error? {
xml envelope = check io:fileReadXml(SOAP_ENVELOPE_PATH);
Expand All @@ -732,7 +733,8 @@ function testAsymmetricBindingPolicyWithEncryption() returns error? {
path: KEY_STORE_PATH_2,
password: PASSWORD
},
publicKeyAlias: ALIAS
publicKeyAlias: ALIAS,
encryptionAlgorithm: AES_256
}
};
xml securedEnvelope = check applyAsymmetricConfigurations(envelope, false, asymmetricConfig);
Expand Down
7 changes: 1 addition & 6 deletions ballerina/modules/wssec/types.bal
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,7 @@ public enum DigestAlgorithm {
}

public enum EncryptionAlgorithm {
RSA_ECB = "http://www.w3.org/2001/04/xmlenc#rsa-1_5"
}

public enum SymmetricAlgorithm {
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",
AES_192 = "http://www.w3.org/2001/04/xmlenc#aes192-cbc"
AES_256 = "http://www.w3.org/2001/04/xmlenc#aes256-cbc"
}
31 changes: 8 additions & 23 deletions ballerina/soap_utils.bal
Original file line number Diff line number Diff line change
Expand Up @@ -56,45 +56,30 @@ public isolated function applySecurityPolicies(wssec:OutboundSecurityConfig|wsse
} else if security is wssec:OutboundSecurityConfig {
return envelope;
} else {
xml securedEnvelope;
xml securedEnvelope = envelope.clone();
foreach wssec:OutboundSecurityConfig policy in security {
securedEnvelope = check applySecurityPolicies(policy, envelope);
securedEnvelope = check applySecurityPolicies(policy, securedEnvelope);
}
return securedEnvelope;
}
}

public isolated function applyOutboundConfig(InboundSecurityConfig inboundSecurity, xml envelope,
public isolated function applyOutboundConfig(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 = inboundSecurity.decryptionAlgorithm;
if encryptionAlgorithm is wssec:EncryptionAlgorithm {
crypto:PrivateKey|crypto:PublicKey? clientPrivateKey = inboundSecurity.decryptionKey;
if clientPrivateKey is crypto:PrivateKey|crypto:PublicKey {
byte[] encData = check wssec:getEncryptedData(soapEnvelope);
byte[] decryptDataResult = check crypto:decryptRsaEcb(encData, clientPrivateKey);
string decryptedBody = "<soap:Body >" + check string:fromBytes(decryptDataResult) + "</soap:Body>";
string decryptedEnv = regexp:replace(re `<soap:Body .*>.*</soap:Body>`, soapEnvelope.toString(),
decryptedBody);
soapEnvelope = check xml:fromString(decryptedEnv);
}
wssec:Document doc = check wssec:decryptEnvelope(envelope, inboundSecurity);
soapEnvelope = check doc.getEnvelope();
}
wssec:SignatureAlgorithm? signatureAlgorithm = inboundSecurity.signatureAlgorithm;
if signatureAlgorithm is wssec:SignatureAlgorithm {
crypto:PublicKey? serverPublicKey = inboundSecurity.verificationKey;
if serverPublicKey is crypto:PublicKey {
byte[] signatureData = check wssec:getSignatureData(soapEnvelope);
if soap12 {
check wssec:verifyData((soapEnvelope/<soap12:Body>/*).toString().toBytes(),
signatureData, serverPublicKey, signatureAlgorithm);
} else {
check wssec:verifyData((soapEnvelope/<soap11:Body>/*).toString().toBytes(),
signatureData, serverPublicKey, signatureAlgorithm);
}

boolean validity = check wssec:verifySignature(soapEnvelope, inboundSecurity);
if !validity {
return error Error("Signature verification failed");
}
}
return soapEnvelope;
Expand Down
Loading

0 comments on commit d12c15e

Please sign in to comment.