diff --git a/ballerina/configs.bal b/ballerina/configs.bal index 8242714..3a46f4a 100644 --- a/ballerina/configs.bal +++ b/ballerina/configs.bal @@ -15,6 +15,7 @@ // under the License. import ballerina/http; +import soap.wssec; # SOAP client configurations. # @@ -24,5 +25,5 @@ import ballerina/http; public type ClientConfig record {| http:ClientConfiguration httpConfig = {}; OutboundSecurityConfig|OutboundSecurityConfig[] outboundSecurity = NO_POLICY; - InboundSecurityConfig inboundSecurity = {}; + wssec:InboundConfig inboundSecurity = {}; |}; diff --git a/ballerina/modules/soap11/soap11.bal b/ballerina/modules/soap11/soap11.bal index c33e59a..f567f02 100644 --- a/ballerina/modules/soap11/soap11.bal +++ b/ballerina/modules/soap11/soap11.bal @@ -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 { @@ -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(inboundSecurity.clone(), response.clone(), false); } else { - return check soap:applyOutboundConfig(inboundSecurity.clone(), + return check soap:applyOutboundConfig(inboundSecurity.clone(), check response[0].getXml().clone(), false); } } diff --git a/ballerina/modules/soap11/tests/http_soap_service.bal b/ballerina/modules/soap11/tests/http_soap_service.bal index 2e9b356..e5067e4 100644 --- a/ballerina/modules/soap11/tests/http_soap_service.bal +++ b/ballerina/modules/soap11/tests/http_soap_service.bal @@ -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, @@ -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, diff --git a/ballerina/modules/soap11/tests/soap11_client_test.bal b/ballerina/modules/soap11/tests/soap11_client_test.bal index 49f3b3e..ec0278d 100644 --- a/ballerina/modules/soap11/tests/soap11_client_test.bal +++ b/ballerina/modules/soap11/tests/soap11_client_test.bal @@ -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 `23`; xml response = check soapClient->sendReceive(body, "http://tempuri.org/Add", path = "/getSamePayload"); - return soap:assertSymmetricBinding(response.toString(), string `23`); + test:assertEquals((response/).toString(), (body/).toString()); } diff --git a/ballerina/modules/soap12/soap12.bal b/ballerina/modules/soap12/soap12.bal index 4bfc77f..da83b83 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:OutboundSecurityConfig|soap:OutboundSecurityConfig[] outboundSecurity; - private final readonly & soap:InboundSecurityConfig inboundSecurity; + private final readonly & wssec:InboundConfig inboundSecurity; # Gets invoked during object initialization. # @@ -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 { diff --git a/ballerina/modules/soap12/tests/http_soap_service.bal b/ballerina/modules/soap12/tests/http_soap_service.bal index ece4b76..576ea46 100644 --- a/ballerina/modules/soap12/tests/http_soap_service.bal +++ b/ballerina/modules/soap12/tests/http_soap_service.bal @@ -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, @@ -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 @@ -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 diff --git a/ballerina/modules/soap12/tests/soap12_client_test.bal b/ballerina/modules/soap12/tests/soap12_client_test.bal index fddfeb4..81e09e2 100644 --- a/ballerina/modules/soap12/tests/soap12_client_test.bal +++ b/ballerina/modules/soap12/tests/soap12_client_test.bal @@ -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 `23`; - xml response = check soapClient->sendReceive(body, "http://tempuri.org/Add", path = "/getSamePayload"); - return soap:assertSymmetricBinding(response.toString(), string `23`); + xml response = check soapClient->sendReceive(body, "http://tempuri.org/Add"); + test:assertEquals((response/).toString(), (body/).toString()); } diff --git a/ballerina/modules/wssec/records.bal b/ballerina/modules/wssec/records.bal index ad91a26..8889401 100644 --- a/ballerina/modules/wssec/records.bal +++ b/ballerina/modules/wssec/records.bal @@ -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?; @@ -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. @@ -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?; diff --git a/ballerina/modules/wssec/tests/ws_security_tests.bal b/ballerina/modules/wssec/tests/ws_security_tests.bal index 8973f66..9a1b860 100644 --- a/ballerina/modules/wssec/tests/ws_security_tests.bal +++ b/ballerina/modules/wssec/tests/ws_security_tests.bal @@ -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 }; @@ -263,7 +263,7 @@ function testSymmetricBindingWithSignatureAndEncryption() returns error? { SymmetricBindingConfig symmetricBinding = { signatureAlgorithm: RSA_SHA256, - encryptionAlgorithm: RSA_ECB, + encryptionAlgorithm: AES_128, symmetricKey: symmetricKey, servicePublicKey: serverPublicKey }; @@ -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 @@ -341,7 +341,7 @@ function testUsernameTokenWithSymmetricBinding() returns error? { SymmetricBindingConfig symmetricBinding = { signatureAlgorithm: RSA_SHA256, - encryptionAlgorithm: RSA_ECB, + encryptionAlgorithm: AES_128, symmetricKey: symmetricKey, servicePublicKey: serverPublicKey }; @@ -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 @@ -448,7 +448,7 @@ function testSymmetricBindingWithOutboundConfig() returns error? { SymmetricBindingConfig symmetricBinding = { signatureAlgorithm: RSA_SHA256, - encryptionAlgorithm: RSA_ECB, + encryptionAlgorithm: AES_128, symmetricKey: symmetricKey, servicePublicKey: serverPublicKey }; @@ -459,7 +459,7 @@ function testSymmetricBindingWithOutboundConfig() returns error? { InboundSecurityConfig outboundConfig = { verificationKey: publicKey, signatureAlgorithm: RSA_SHA256, - decryptionAlgorithm: RSA_ECB, + decryptionAlgorithm: AES_128, decryptionKey: publicKey }; @@ -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); @@ -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); @@ -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); @@ -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); diff --git a/ballerina/modules/wssec/types.bal b/ballerina/modules/wssec/types.bal index 2b113f1..2990f24 100644 --- a/ballerina/modules/wssec/types.bal +++ b/ballerina/modules/wssec/types.bal @@ -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" } diff --git a/ballerina/soap_utils.bal b/ballerina/soap_utils.bal index 4d61194..f184a84 100644 --- a/ballerina/soap_utils.bal +++ b/ballerina/soap_utils.bal @@ -56,15 +56,15 @@ 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; @@ -72,29 +72,14 @@ public isolated function applyOutboundConfig(InboundSecurityConfig inboundSecuri 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 = "" + check string:fromBytes(decryptDataResult) + ""; - string decryptedEnv = regexp:replace(re `.*`, 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//*).toString().toBytes(), - signatureData, serverPublicKey, signatureAlgorithm); - } else { - check wssec:verifyData((soapEnvelope//*).toString().toBytes(), - signatureData, serverPublicKey, signatureAlgorithm); - } - + 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 73c4eee..dc0044c 100644 --- a/ballerina/types.bal +++ b/ballerina/types.bal @@ -47,7 +47,7 @@ public enum EncryptionAlgorithm { # + signatureAlgorithm - The algorithm to verify the SOAP envelope # + decryptionAlgorithm - The algorithm to decrypt the SOAP body public type InboundSecurityConfig record { - *wssec:InboundSecurityConfig; + *wssec:InboundConfig; }; # Union type of all the inbound web service security configurations. diff --git a/native/src/main/java/org/wssec/Constants.java b/native/src/main/java/org/wssec/Constants.java index 84b60f2..b1f90a2 100644 --- a/native/src/main/java/org/wssec/Constants.java +++ b/native/src/main/java/org/wssec/Constants.java @@ -42,5 +42,19 @@ private Constants() { public static final String NAMESPACE_URI_ENC = "http://www.w3.org/2001/04/xmlenc#"; public static final String CIPHER_VALUE_TAG = "CipherValue"; public static final String X509 = "X.509"; + public static final String AES = "AES"; public static final String EMPTY_XML_DOCUMENT_ERROR = "XML Document is empty"; + public static final String CRYPTO_PROVIDER_FIELD = "org.apache.ws.security.crypto.provider"; + public static final String CRYPTO_PROVIDER_VALUE = "org.apache.wss4j.common.crypto.Merlin"; + public static final String KEYSTORE = "keystore"; + public static final String PATH = "path"; + public static final String DIGEST_ALGORITHM = "digestAlgorithm"; + public static final String CANONICALIZATION_ALGORITHM = "canonicalizationAlgorithm"; + public static final String SIGNATURE_ALGORITHM = "signatureAlgorithm"; + public static final String PRIVATE_KEY_PASSWORD = "privateKeyPassword"; + public static final String PRIVATE_KEY_ALIAS = "privateKeyAlias"; + public static final String PUBLIC_KEY_ALIAS = "publicKeyAlias"; + public static final String ENCRYPTION_ALGORITHM = "encryptionAlgorithm"; + public static final String KEYSTORE_PATH_FIELD = "org.apache.ws.security.crypto.merlin.keystore.file"; + public static final String KEYSTORE_PASSWORD_FIELD = "org.apache.ws.security.crypto.merlin.keystore.password"; } diff --git a/native/src/main/java/org/wssec/WsSecurity.java b/native/src/main/java/org/wssec/WsSecurity.java index 32a28f3..22e6c63 100644 --- a/native/src/main/java/org/wssec/WsSecurity.java +++ b/native/src/main/java/org/wssec/WsSecurity.java @@ -30,7 +30,6 @@ import org.apache.wss4j.dom.WSDocInfo; import org.apache.wss4j.dom.engine.WSSConfig; import org.apache.wss4j.dom.engine.WSSecurityEngine; -import org.apache.wss4j.dom.engine.WSSecurityEngineResult; import org.apache.wss4j.dom.handler.RequestData; import org.apache.wss4j.dom.message.WSSecDKEncrypt; import org.apache.wss4j.dom.message.WSSecEncrypt; @@ -51,7 +50,6 @@ import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.ArrayList; -import java.util.List; import java.util.Properties; import javax.crypto.KeyGenerator; @@ -61,17 +59,32 @@ import javax.xml.namespace.QName; import static org.apache.wss4j.common.WSS4JConstants.AES_128_GCM; +import static org.apache.wss4j.common.WSS4JConstants.ELEM_HEADER; import static org.apache.wss4j.common.WSS4JConstants.HMAC_SHA1; import static org.apache.wss4j.dom.WSConstants.CUSTOM_KEY_IDENTIFIER; import static org.apache.wss4j.dom.WSConstants.X509_KEY_IDENTIFIER; +import static org.wssec.Constants.AES; +import static org.wssec.Constants.CANONICALIZATION_ALGORITHM; +import static org.wssec.Constants.CRYPTO_PROVIDER_FIELD; +import static org.wssec.Constants.CRYPTO_PROVIDER_VALUE; import static org.wssec.Constants.DERIVED_KEY_DIGEST; import static org.wssec.Constants.DERIVED_KEY_TEXT; +import static org.wssec.Constants.DIGEST_ALGORITHM; +import static org.wssec.Constants.ENCRYPTION_ALGORITHM; import static org.wssec.Constants.ITERATION; +import static org.wssec.Constants.KEYSTORE; +import static org.wssec.Constants.KEYSTORE_PASSWORD_FIELD; +import static org.wssec.Constants.KEYSTORE_PATH_FIELD; import static org.wssec.Constants.NATIVE_DOCUMENT; import static org.wssec.Constants.NATIVE_ENCRYPTION; import static org.wssec.Constants.NATIVE_SEC_HEADER; import static org.wssec.Constants.NATIVE_SIGNATURE; import static org.wssec.Constants.PASSWORD; +import static org.wssec.Constants.PATH; +import static org.wssec.Constants.PRIVATE_KEY_ALIAS; +import static org.wssec.Constants.PRIVATE_KEY_PASSWORD; +import static org.wssec.Constants.PUBLIC_KEY_ALIAS; +import static org.wssec.Constants.SIGNATURE_ALGORITHM; import static org.wssec.Constants.X509; import static org.wssec.Utils.createError; import static org.wssec.WsSecurityUtils.convertDocumentToString; @@ -199,42 +212,40 @@ public static Object applySignatureOnly(BObject documentBuilder, Boolean soap12, Object> signatureConfig) { Document document = (Document) documentBuilder.getNativeData(NATIVE_DOCUMENT); BMap keyStore = (BMap) signatureConfig - .getMapValue(StringUtils.fromString("keystore")); - BString path = keyStore.get(StringUtils.fromString("path")); - BString password = keyStore.get(StringUtils.fromString("password")); - String digestAlgorithm = signatureConfig.get(StringUtils.fromString("digestAlgorithm")).toString(); + .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("canonicalizationAlgorithm")).toString(); - String signatureAlgorithm = signatureConfig.get(StringUtils.fromString("signatureAlgorithm")).toString(); - String privateKeyPassword = signatureConfig.get(StringUtils.fromString("privateKeyPassword")).toString(); - String privateKeyAlias = signatureConfig.get(StringUtils.fromString("privateKeyAlias")).toString(); + .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(); - WSSecSignature wsSecSignature = new WSSecSignature(secHeader); - wsSecSignature.setUserInfo(privateKeyAlias, privateKeyPassword); - wsSecSignature.setKeyIdentifierType(WSConstants.X509_KEY_IDENTIFIER); - wsSecSignature.setDigestAlgo(digestAlgorithm); - wsSecSignature.setSignatureAlgorithm(signatureAlgorithm); - wsSecSignature.setSigCanonicalization(canonicalizationAlgorithm); - Properties properties = new Properties(); - properties.put("org.apache.ws.security.crypto.provider", "org.apache.wss4j.common.crypto.Merlin"); - properties.put("org.apache.ws.security.crypto.merlin.keystore.file", path.getValue()); - properties.put("org.apache.ws.security.crypto.merlin.keystore.password", password.getValue()); - Crypto crypto = CryptoFactory.getInstance(properties); - wsSecSignature.build(crypto); + 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) ? "http://www.w3.org/2003/05/soap-envelope" : "http://schemas.xmlsoap" + - ".org/soap/envelope/"; - Element header = (Element) document.getElementsByTagNameNS(namespace, "Header").item(0); + 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"); } @@ -244,39 +255,27 @@ public static Object verifySignature(BObject documentBuilder, BMap config) { Document document = (Document) documentBuilder.getNativeData(NATIVE_DOCUMENT); BMap keyStore = (BMap) config - .getMapValue(StringUtils.fromString("keystore")); - BString path = keyStore.get(StringUtils.fromString("path")); - BString password = keyStore.get(StringUtils.fromString("password")); + .getMapValue(StringUtils.fromString(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(); - Properties properties = new Properties(); - properties.put("org.apache.ws.security.crypto.provider", "org.apache.wss4j.common.crypto.Merlin"); - properties.put("org.apache.ws.security.crypto.merlin.keystore.file", path.getValue()); - properties.put("org.apache.ws.security.crypto.merlin.keystore.password", password.getValue()); - Crypto crypto = CryptoFactory.getInstance(properties); + Crypto crypto = getCryptoInstance(path, password); requestData.setSigVerCrypto(crypto); - CallbackHandler passwordCallbackHandler = new CallbackHandler() { - @Override - public void handle(Callback[] callbacks) { - for (Callback callback: callbacks) { - ((WSPasswordCallback) callback).setPassword("password"); - } + CallbackHandler passwordCallbackHandler = callbacks -> { + for (Callback callback: callbacks) { + ((WSPasswordCallback) callback).setPassword(PASSWORD); } }; requestData.setCallbackHandler(passwordCallbackHandler); WSSConfig wssConfig = WSSConfig.getNewInstance(); secEngine.setWssConfig(wssConfig); - Processor processor = new Processor() { - @Override - public List handleToken(Element elem, RequestData data) - throws WSSecurityException { - if (WSConstants.ENC_KEY_LN.equals(elem.getLocalName())) { - List list = new ArrayList<>(); - return list; - } - return new EncryptedKeyProcessor().handleToken(elem, data); + 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); @@ -289,18 +288,14 @@ public List handleToken(Element elem, RequestData data) public static Object decryptEnvelope(BObject documentBuilder, BMap config) { Document encryptedDocument = (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(); + .getMapValue(StringUtils.fromString(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(); - Properties properties = new Properties(); - properties.put("org.apache.ws.security.crypto.provider", "org.apache.wss4j.common.crypto.Merlin"); - properties.put("org.apache.ws.security.crypto.merlin.keystore.file", path); - properties.put("org.apache.ws.security.crypto.merlin.keystore.password", password); try { - Crypto crypto = CryptoFactory.getInstance(properties); + Crypto crypto = getCryptoInstance(path, password); requestData.setSigVerCrypto(crypto); requestData.setDecCrypto(crypto); requestData.setSecHeader(secHeader); @@ -323,25 +318,16 @@ public static Object applyEncryptionOnly(BObject documentBuilder, Boolean soap12 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("publicKeyAlias")).toString(); + .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(); - WSSecEncrypt encrypt = new WSSecEncrypt(secHeader); - encrypt.setUserInfo(publicKeyAlias); - encrypt.setKeyIdentifierType(WSConstants.X509_KEY_IDENTIFIER); - encrypt.setSymmetricEncAlgorithm(WSConstants.AES_128); - encrypt.setKeyEncAlgo(WSConstants.KEYTRANSPORT_RSAOAEP); - Properties properties = new Properties(); - properties.put("org.apache.ws.security.crypto.provider", "org.apache.wss4j.common.crypto.Merlin"); - properties.put("org.apache.ws.security.crypto.merlin.keystore.file", path); - properties.put("org.apache.ws.security.crypto.merlin.keystore.password", password); - Crypto crypto = CryptoFactory.getInstance(properties); - SecretKey symmetricKey = generateSymmetricKey(); - encrypt.build(crypto, symmetricKey); + generateEncryption(publicKeyAlias, crypto, secHeader, encryptionAlgorithm); return convertDocumentToString(document); } catch (Exception e) { return createError(e.getMessage()); @@ -354,50 +340,55 @@ public static Object applySignatureAndEncryption(BObject documentBuilder, Boolea 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("publicKeyAlias")).toString(); - String privateKeyPassword = signatureConfig.get(StringUtils.fromString("privateKeyPassword")).toString(); - String privateKeyAlias = signatureConfig.get(StringUtils.fromString("privateKeyAlias")).toString(); - String digestAlgorithm = signatureConfig.get(StringUtils.fromString("digestAlgorithm")).toString(); + .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("canonicalizationAlgorithm")).toString(); - String signatureAlgorithm = signatureConfig.get(StringUtils.fromString("signatureAlgorithm")).toString(); + .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); - - Properties properties = new Properties(); - properties.put("org.apache.ws.security.crypto.provider", "org.apache.wss4j.common.crypto.Merlin"); - properties.put("org.apache.ws.security.crypto.merlin.keystore.file", path); - properties.put("org.apache.ws.security.crypto.merlin.keystore.password", password); - Crypto crypto = CryptoFactory.getInstance(properties); - + Crypto crypto = getCryptoInstance(path, password); WSSecHeader secHeader = new WSSecHeader(document); secHeader.insertSecurityHeader(); - - 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); - - WSSecEncrypt encrypt = new WSSecEncrypt(secHeader); - encrypt.setUserInfo(publicKeyAlias); - encrypt.setKeyIdentifierType(WSConstants.X509_KEY_IDENTIFIER); - encrypt.setSymmetricEncAlgorithm(WSConstants.AES_128); - encrypt.setKeyEncAlgo(WSConstants.KEYTRANSPORT_RSAOAEP); - SecretKey symmetricKey = generateSymmetricKey(); - encrypt.build(crypto, symmetricKey); + 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"); + KeyGenerator keyGen = KeyGenerator.getInstance(AES); keyGen.init(128); return keyGen.generateKey(); }