generated from quarkiverse/quarkiverse-template
-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
org.apache.wss4j.dom.transform.STRTransform broken in WSS4j 3.0.0 #939
- Loading branch information
Showing
11 changed files
with
277 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
171 changes: 171 additions & 0 deletions
171
...ity-client/src/main/java/io/quarkiverse/cxf/it/wss/client/SignatureValidatorResource.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
package io.quarkiverse.cxf.it.wss.client; | ||
|
||
import java.io.ByteArrayInputStream; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.nio.file.Files; | ||
import java.nio.file.StandardCopyOption; | ||
import java.security.cert.CertificateFactory; | ||
import java.security.cert.X509Certificate; | ||
import java.util.ArrayList; | ||
import java.util.Base64; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Properties; | ||
|
||
import javax.xml.crypto.dsig.XMLSignature; | ||
import javax.xml.crypto.dsig.XMLSignatureFactory; | ||
import javax.xml.crypto.dsig.dom.DOMValidateContext; | ||
import javax.xml.parsers.DocumentBuilder; | ||
import javax.xml.parsers.DocumentBuilderFactory; | ||
|
||
import jakarta.ws.rs.POST; | ||
import jakarta.ws.rs.Path; | ||
import jakarta.ws.rs.Produces; | ||
import jakarta.ws.rs.QueryParam; | ||
import jakarta.ws.rs.core.MediaType; | ||
|
||
import org.apache.wss4j.common.WSS4JConstants; | ||
import org.apache.wss4j.common.bsp.BSPEnforcer; | ||
import org.apache.wss4j.common.crypto.Crypto; | ||
import org.apache.wss4j.common.crypto.CryptoFactory; | ||
import org.apache.wss4j.common.ext.WSSecurityException; | ||
import org.apache.wss4j.dom.engine.WSSConfig; | ||
import org.w3c.dom.Document; | ||
import org.w3c.dom.Element; | ||
import org.w3c.dom.Node; | ||
import org.w3c.dom.NodeList; | ||
|
||
@Path("/cxf/signature-validator") | ||
public class SignatureValidatorResource { | ||
|
||
private static final String TRUSTSTORE_RESOURCE = "saml-keystore.jks"; | ||
|
||
public final BSPEnforcer enforcer; | ||
public final WSSConfig wssConfig; | ||
public final Crypto crypto; | ||
|
||
public SignatureValidatorResource() { | ||
java.nio.file.Path trustStoreFile = null; | ||
try (InputStream in = getClass().getClassLoader().getResourceAsStream(TRUSTSTORE_RESOURCE)) { | ||
trustStoreFile = Files.createTempFile("saml-keystore-", ".jks"); | ||
Files.createDirectories(trustStoreFile.getParent()); | ||
Files.copy(in, trustStoreFile, StandardCopyOption.REPLACE_EXISTING); | ||
} catch (IOException e) { | ||
throw new RuntimeException( | ||
"Could not copy the classpath resource " + TRUSTSTORE_RESOURCE + " to " + trustStoreFile, e); | ||
} | ||
|
||
Properties properties = new Properties(); | ||
properties.setProperty("org.apache.ws.security.crypto.provider", "org.apache.ws.security.components.crypto.Merlin"); | ||
properties.put("org.apache.ws.security.crypto.merlin.truststore.type", "JKS"); | ||
properties.put("org.apache.ws.security.crypto.merlin.truststore.password", "changeit"); | ||
properties.put("org.apache.ws.security.crypto.merlin.truststore.file", trustStoreFile.toString()); | ||
properties.put("org.apache.ws.security.crypto.merlin.load.cacerts", "false"); | ||
|
||
this.enforcer = new BSPEnforcer(); | ||
this.wssConfig = WSSConfig.getNewInstance(); | ||
try { | ||
this.crypto = CryptoFactory.getInstance(properties); | ||
} catch (WSSecurityException e) { | ||
throw new RuntimeException("Could not create Crypto", e); | ||
} | ||
} | ||
|
||
@POST | ||
@Path("/validate") | ||
@Produces(MediaType.TEXT_PLAIN) | ||
public boolean validate(@QueryParam("samlNamespace") String samlNamespace, InputStream body) throws Exception { | ||
|
||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); | ||
factory.setNamespaceAware(true); | ||
DocumentBuilder builder = factory.newDocumentBuilder(); | ||
Document bodyDocument = builder.parse(body); | ||
Check failure Code scanning / CodeQL Resolving XML external entity in user-controlled data Critical
XML parsing depends on a
user-provided value Error loading related location Loading |
||
|
||
Element element = bodyDocument.getDocumentElement(); | ||
NodeList nodes = element.getElementsByTagNameNS(WSS4JConstants.WSSE_NS, WSS4JConstants.WSSE_LN); | ||
Element wsseHeader = (Element) nodes.item(0); | ||
if (wsseHeader == null) { | ||
throw new SecurityException("Assertion missing in request!"); | ||
} | ||
|
||
NodeList timestampNodes = wsseHeader.getElementsByTagNameNS(WSS4JConstants.WSU_NS, | ||
WSS4JConstants.TIMESTAMP_TOKEN_LN); | ||
NodeList samlNodes = wsseHeader.getElementsByTagNameNS(samlNamespace, WSS4JConstants.ASSERTION_LN); | ||
NodeList binaryNodes = wsseHeader.getElementsByTagNameNS(WSS4JConstants.WSSE_NS, WSS4JConstants.BINARY_TOKEN_LN); | ||
NodeList signatureNodes = wsseHeader.getElementsByTagNameNS(XMLSignature.XMLNS, WSS4JConstants.SIG_LN); | ||
NodeList tokenRefs = wsseHeader.getElementsByTagNameNS(WSS4JConstants.WSSE_NS, "SecurityTokenReference"); | ||
if (isEmpty(timestampNodes, samlNodes, binaryNodes, signatureNodes)) { | ||
throw new SecurityException("Assertion missing in request!"); | ||
} | ||
|
||
return validateSecurityHeader( | ||
timestampNodes.item(0), | ||
samlNodes.item(0), | ||
binaryNodes.item(0), | ||
signatureNodes.item(0), | ||
toList(tokenRefs)); | ||
} | ||
|
||
private List<Node> toList(NodeList nodeList) { | ||
final int cnt = nodeList.getLength(); | ||
if (cnt == 0) { | ||
return Collections.emptyList(); | ||
} | ||
final List<Node> res = new ArrayList<>(cnt); | ||
for (int i = 0; i < cnt; i++) { | ||
res.add(nodeList.item(i)); | ||
} | ||
return res; | ||
} | ||
|
||
private boolean isEmpty(NodeList... nodeLists) { | ||
for (NodeList nl : nodeLists) { | ||
if (nl.getLength() == 0) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
private boolean validateSecurityHeader( | ||
Node timestampNode, | ||
Node samlNode, | ||
Node binaryNode, | ||
Node signatureNode, List<Node> additionalSignedNodes) throws Exception { | ||
|
||
InputStream in = new ByteArrayInputStream(Base64.getMimeDecoder().decode(binaryNode.getTextContent())); | ||
X509Certificate certificate = (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(in); | ||
|
||
List<Node> signedNodes = new ArrayList<>(); | ||
signedNodes.add(timestampNode); | ||
signedNodes.add(samlNode); | ||
signedNodes.addAll(additionalSignedNodes); | ||
|
||
return validateSignature(certificate, signatureNode, signedNodes); | ||
} | ||
|
||
private boolean validateSignature( | ||
X509Certificate certificate, | ||
Node signatureNode, | ||
List<Node> additionalNodes) throws Exception { | ||
|
||
DOMValidateContext valContext = new DOMValidateContext(certificate.getPublicKey(), signatureNode); | ||
|
||
// disable secure validation since we use SHA-1 algorithm for signature | ||
valContext.setProperty("org.jcp.xml.dsig.secureValidation", Boolean.FALSE); | ||
for (Node node : additionalNodes) { | ||
Element el = (Element) node; | ||
if (el.hasAttributeNS(WSS4JConstants.WSU_NS, "Id")) { | ||
valContext.setIdAttributeNS(el, WSS4JConstants.WSU_NS, "Id"); | ||
} else if (el.hasAttribute("ID")) { | ||
valContext.setIdAttributeNS(el, null, "ID"); | ||
} | ||
} | ||
|
||
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM"); | ||
XMLSignature signature = fac.unmarshalXMLSignature(valContext); | ||
return signature.validate(valContext); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file added
BIN
+6.46 KB
integration-tests/ws-security-client/src/main/resources/saml-keystore.jks
Binary file not shown.
7 changes: 7 additions & 0 deletions
7
...-security-client/src/test/java/io/quarkiverse/cxf/it/wss/client/SignatureValidatorIT.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package io.quarkiverse.cxf.it.wss.client; | ||
|
||
import io.quarkus.test.junit.QuarkusIntegrationTest; | ||
|
||
@QuarkusIntegrationTest | ||
public class SignatureValidatorIT extends SignatureValidatorTest { | ||
} |
38 changes: 38 additions & 0 deletions
38
...ecurity-client/src/test/java/io/quarkiverse/cxf/it/wss/client/SignatureValidatorTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package io.quarkiverse.cxf.it.wss.client; | ||
|
||
import java.io.IOException; | ||
import java.io.InputStream; | ||
|
||
import org.apache.wss4j.common.WSS4JConstants; | ||
import org.hamcrest.CoreMatchers; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import io.quarkus.test.junit.QuarkusTest; | ||
import io.restassured.RestAssured; | ||
|
||
@QuarkusTest | ||
public class SignatureValidatorTest { | ||
|
||
@Test | ||
public void saml1() throws Exception { | ||
assertSaml("data/saml1-request.xml", WSS4JConstants.SAML_NS); | ||
} | ||
|
||
@Test | ||
public void saml2() throws Exception { | ||
assertSaml("data/saml2-request.xml", WSS4JConstants.SAML2_NS); | ||
} | ||
|
||
static void assertSaml(String message, String samlNamespace) throws IOException { | ||
try (InputStream in = SignatureValidatorTest.class.getClassLoader().getResourceAsStream(message)) { | ||
RestAssured.given() | ||
.body(in) | ||
.queryParam("samlNamespace", samlNamespace) | ||
.post("/cxf/signature-validator/validate") | ||
.then() | ||
.statusCode(200) | ||
.body(CoreMatchers.is("true")); | ||
} | ||
} | ||
|
||
} |
5 changes: 5 additions & 0 deletions
5
integration-tests/ws-security-client/src/test/resources/data/saml1-request.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<?xml version="1.0" encoding="UTF-8"?><soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"><soap-env:Header xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><wsu:Timestamp wsu:Id="ts-005056867EF41EDBA0823B711B22C0F1"><wsu:Created>2021-03-08T13:26:20Z</wsu:Created><wsu:Expires>2021-03-08T13:27:50Z</wsu:Expires></wsu:Timestamp><wsse:BinarySecurityToken EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" wsu:Id="bst-005056867EF41EDBA0823B711B23">MIIEnzCCAoegAwIBAgICAZkwDQYJKoZIhvcNAQELBQAwgagxKDAmBgkqhkiG9w0BCQEWGWljYy5pbmZvcm1hdGlrQGhlbHNhbmEuY2gxFzAVBgNVBAMMDnNvYXBfZGV2ZWxvcGVyMQwwCgYDVQQLDANJWEkxIjAgBgNVBAoMGUhlbHNhbmEgVmVyc2ljaGVydW5nZW4gQUcxEzARBgNVBAcMCkR1ZWJlbmRvcmYxDzANBgNVBAgMBlp1cmljaDELMAkGA1UEBhMCQ0gwHhcNNzAwMTAxMDAwMDE5WhcNNDMwMzEwMDAwMDAwWjB8MSIwIAYDVQQDDBllbXBsb3llZTItYXNlbS5oZWwua2tvLmNoMRMwEQYDVQQLDApJVCBTZXJ2aWNlMSIwIAYDVQQKDBlIZWxzYW5hIFZlcnNpY2hlcnVuZ2VuIEFHMRAwDgYDVQQHDAdadWVyaWNoMQswCQYDVQQGEwJDSDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJpYavV1KEVUw7X507gDz9L1JeIqv0CZvkcodnr4dByD3DnWSqI7Af/jwsnmDGRbG0WdTmPt/5CP5UWY5CtnMvDZ4MbTEE88v1hZ4BjbS/ecCdHhZAe97SHXXAs+DPNvE5Q7fFtE70no+DsAhoY9cnvIJTuVwve7RgQY4ggQGCPvpHcIeRh8atE9FTZi64oHcK8Gsa/7ewj8gOGe2fosyLnoeUnyYJwNroTbOqDm8tLhxcDM4AbIxekbcemF2ENf8B1s8+QvOg//St6Dy0eUIWNw+vhNdCaidYk/ADTxLJ2Ps4BXjNK7/vifGkssQ+xNsYYr7+Mkx1tAOx2h9Pe7k28CAwEAATANBgkqhkiG9w0BAQsFAAOCAgEApIJSdLyVv8m4AozIDCtL0im5BO0eGyV8NI0WsETAlbdHMO0nzjtORzNaid+SWOtYHRzIkR4U+8Xk0/4wU3QmP4I6fJG65yugpxeAQhC5Txu2Wm/9dbJy3lU9cSQFEF4ne9V0rX75IwCZ5XJVYOrZlUkFj8JpFiVuV03DxvqLvDlE4CMcLhIo/AV7ACTnJU/a+XzMHh9ME0+QX8h+MWTaUqH3x9fLK69FOF+E2i0om50Ib9K8fxoTAzvzzSxZW9iF3XNAyKHDkBo1EfgmgjfK7ck/kqzMfml5RQXFaYVLBbMehr/CmYffsCjSpvB0LXkQznjmma7MhJMGepmztGDBkXC2YZjXqzu42E2GecEP5v3l6k5AEyekCcKQM0Mh/vWMb9BCgGe52i9ZegRV1l4MxkHdOc0yOKRHJSQsJCftmUllZDWr20pMZ2k485zBYa/BypJXNMh3CaQlztSEIEKr+ohY5KwemPRJhEDI1eCcd3IZz62p8AuVPRPrYXOlVz2F7mYY+qgS5CLBD3B/U40lHmxKbF4uIfYDfluHVyk8mtAqnGmYBBWchpCZUffYuW/1kExHsMBoDjK5jNtTlK/k64xk78aMksk/P5NnXpfjaJujXoFYJIWv3hdOS8lKCwLDg1mrpmQ3UmGOZqG9vVkM+lNQPl5PrDpYJ8t8XoX3sM8=</wsse:BinarySecurityToken><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="sig-005056867EF41EDBA0823B711B22E0F1"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><ds:Reference URI="#ts-005056867EF41EDBA0823B711B22C0F1"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>XEbLqMXooIX5KzNGxXuTSodawyE=</ds:DigestValue></ds:Reference><ds:Reference URI="#str-005056867EF41EDBA0823B711B2300F1"><ds:Transforms><ds:Transform Algorithm="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#STR-Transform"><wsse:TransformationParameters><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></wsse:TransformationParameters></ds:Transform></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>06wG7NolfMKiAQj8LFtYs+AYr28=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>PrTNKPN0ANd/rjrDr982VqHN023g7pElNoMjH7ueu1wwpGVIvbk4YnKz60SBlbvi6dhTL8kSqDPk | ||
M1gCZnf8Q4Py6j2mrstMr51rWr4p2aSASQIRRVO6/CwScM28SJuZAyZnuplvh+d5vBQt+sRhEiul | ||
cYtraaP/QbFlhKZtqY/CbKA91pzOunzwKVEwGvmEW1BWQUFxjA86ABZcQ1Obe2moSfPLQ3V+VKTA | ||
7/IonAOMPufNUEoy57V4abO0wzPldEySpT6Gxs///t60JOuJ+A2FAN+ZmTjEgN2a+uj++iDL0XEo | ||
yam6pukBuNgv9wjZgiKkpw3XTo3AqHvZwVc29Q==</ds:SignatureValue><ds:KeyInfo><wsse:SecurityTokenReference><wsse:Reference URI="#bst-005056867EF41EDBA0823B711B23" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/></wsse:SecurityTokenReference></ds:KeyInfo></ds:Signature><wsse:SecurityTokenReference wsu:Id="str-005056867EF41EDBA0823B711B2300F1"><wsse:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.0#SAMLAssertionID">saml-005056867EF41EDBA0823B711B22A0F1</wsse:KeyIdentifier></wsse:SecurityTokenReference><saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" AssertionID="saml-005056867EF41EDBA0823B711B22A0F1" IssueInstant="2021-03-08T13:26:20Z" Issuer="http://services.sap-t22.hel.kko.ch" MajorVersion="1" MinorVersion="1"><saml:Conditions NotBefore="2021-03-08T13:26:20Z" NotOnOrAfter="2021-03-08T13:31:20Z"/><saml:AuthenticationStatement AuthenticationInstant="2021-03-08T13:26:20Z" AuthenticationMethod="urn:oasis:names:tc:SAML:1.0:am:unspecified"><saml:Subject><saml:NameIdentifier Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified" NameQualifier="">HKE32</saml:NameIdentifier><saml:SubjectConfirmation><saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:sender-vouches</saml:ConfirmationMethod></saml:SubjectConfirmation></saml:Subject></saml:AuthenticationStatement></saml:Assertion></wsse:Security><sap:Trace xmlns:sap="http://www.sap.com/webas/630/soap/features/runtime/tracing/" wsu:Id="part-Trace-5"><sap:TraceLevel>Payload</sap:TraceLevel><sap:TraceContext><TRC_PATTERN>WSTEST</TRC_PATTERN><TRC_KEY>031180EB5E99F1A380F1005056867EF4</TRC_KEY><TRC_ROOT_CTX_ID/><TRC_SSID>T22_01</TRC_SSID><TRC_USER>HKE32</TRC_USER><TRC_TS>20210308132603</TRC_TS><TRC_COUNTER>98</TRC_COUNTER><TRC_EXTERN/><TRC_REQBASED/><TRC_PPVERS>3</TRC_PPVERS></sap:TraceContext></sap:Trace><m:CallerInformation xmlns:m="http://www.sap.com/webas/712/soap/features/runtime/metering/" wsu:Id="part-CallerInformation-6"><m:Type>SA</m:Type><m:Company>0020203013</m:Company><m:Sys>T22_010</m:Sys></m:CallerInformation></soap-env:Header><soap-env:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="part-Body-7"><nm:processPaymentInstrument xmlns:nm="http://www.adcubum.com/wsdl/syrius.modul_bl.payment.global.v04_1_0.rechtlichesinkasso.service/GlobalRIKMeldungImporter" xmlns:prx="urn:sap.com:proxy:P11:/1SAI/TAS4A079764B0183C3E95BD:731"><n0:data xmlns:n0="http://www.adcubum.com/wsdl/syrius.modul_bl.payment.global.v04_1_0.rechtlichesinkasso.service/GlobalRIKMeldungImporter"><?xml version="1.0" encoding="utf-8"?><envelopeType><meta><messageId>051MXdxq7jkWWZjn6o8WyG</messageId><origin>osytt22-T54-220</origin><time>2021-03-08T14:26:20.591000</time></meta><message><paymentInstrumentType><esrReferenceNumber>006839929000016503709010119</esrReferenceNumber><dossId>0006839929</dossId></paymentInstrumentType></message></envelopeType></n0:data></nm:processPaymentInstrument></soap-env:Body></soap-env:Envelope> |
Oops, something went wrong.