/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.wss4j.stax.test; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.EnumSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import javax.xml.namespace.QName; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamWriter; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import org.apache.wss4j.common.bsp.BSPRule; import org.apache.wss4j.common.ext.WSSecurityException; import org.apache.wss4j.dom.handler.WSHandlerConstants; import org.apache.wss4j.stax.ext.WSSConstants; import org.apache.wss4j.stax.ext.WSSSecurityProperties; import org.apache.wss4j.stax.securityEvent.EncryptedPartSecurityEvent; import org.apache.wss4j.stax.securityEvent.OperationSecurityEvent; import org.apache.wss4j.stax.securityEvent.SignedPartSecurityEvent; import org.apache.wss4j.stax.securityEvent.WSSecurityEventConstants; import org.apache.wss4j.stax.setup.InboundWSSec; import org.apache.wss4j.stax.setup.OutboundWSSec; import org.apache.wss4j.stax.setup.WSSec; import org.apache.wss4j.stax.test.utils.StAX2DOM; import org.apache.wss4j.stax.test.utils.XmlReaderToWriter; import org.apache.xml.security.stax.ext.SecurePart; import org.apache.xml.security.stax.securityEvent.EncryptedElementSecurityEvent; import org.apache.xml.security.stax.securityEvent.SecurityEvent; import org.apache.xml.security.stax.securityEvent.SecurityEventListener; import org.apache.xml.security.stax.securityEvent.SignatureValueSecurityEvent; import org.apache.xml.security.stax.securityEvent.SignedElementSecurityEvent; import org.junit.Assert; import org.junit.Test; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class InteroperabilityTest extends AbstractTestBase { @Test public void testInteroperabilityInbound() throws Exception { InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"); String action = WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT; Properties properties = new Properties(); properties.setProperty(WSHandlerConstants.SIGNATURE_PARTS, "{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;{Element}{http://schemas.xmlsoap.org/soap/envelope/}Body;"); Document securedDocument = doOutboundSecurityWithWSS4J(sourceDocument, action, properties); ByteArrayOutputStream baos = new ByteArrayOutputStream(); javax.xml.transform.Transformer transformer = TRANSFORMER_FACTORY.newTransformer(); transformer.transform(new DOMSource(securedDocument), new StreamResult(baos)); WSSSecurityProperties securityProperties = new WSSSecurityProperties(); securityProperties.setCallbackHandler(new CallbackHandlerImpl()); securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); WSSecurityEventConstants.Event[] expectedSecurityEvents = new WSSecurityEventConstants.Event[]{ WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.X509Token, WSSecurityEventConstants.X509Token, WSSecurityEventConstants.SignatureValue, WSSecurityEventConstants.TIMESTAMP, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.SIGNED_PART, WSSecurityEventConstants.ENCRYPTED_PART, WSSecurityEventConstants.OPERATION, }; final TestSecurityEventListener securityEventListener = new TestSecurityEventListener(expectedSecurityEvents); Document document = doInboundSecurity(securityProperties, xmlInputFactory.createXMLStreamReader( new ByteArrayInputStream(baos.toByteArray())), securityEventListener); //read the whole stream: transformer = TRANSFORMER_FACTORY.newTransformer(); transformer.transform(new DOMSource(document), new StreamResult( new OutputStream() { @Override public void write(int b) throws IOException { // > /dev/null } } )); securityEventListener.compare(); EncryptedPartSecurityEvent encryptedPartSecurityEvent = securityEventListener.getSecurityEvent(WSSecurityEventConstants.ENCRYPTED_PART); List<SignedElementSecurityEvent> signedElementSecurityEventList = securityEventListener.getSecurityEvents(WSSecurityEventConstants.SignedElement); List<SignedPartSecurityEvent> signedPartSecurityEventList = securityEventListener.getSecurityEvents(WSSecurityEventConstants.SIGNED_PART); SignatureValueSecurityEvent signatureValueSecurityEvent = securityEventListener.getSecurityEvent(WSSecurityEventConstants.SignatureValue); OperationSecurityEvent operationSecurityEvent = securityEventListener.getSecurityEvent(WSSecurityEventConstants.OPERATION); String encryptedPartCorrelationID = encryptedPartSecurityEvent.getCorrelationID(); String signedElementCorrelationID1 = signedElementSecurityEventList.get(0).getCorrelationID(); String signedElementCorrelationID2 = signedPartSecurityEventList.get(0).getCorrelationID(); String signatureValueCorrelationID = signatureValueSecurityEvent.getCorrelationID(); String operationCorrelationID = operationSecurityEvent.getCorrelationID(); List<SecurityEvent> operationSecurityEvents = new ArrayList<>(); List<SecurityEvent> encryptedPartSecurityEvents = new ArrayList<>(); List<SecurityEvent> signedElementSecurityEvents1 = new ArrayList<>(); List<SecurityEvent> signedElementSecurityEvents2 = new ArrayList<>(); List<SecurityEvent> signatureValueSecurityEvents = new ArrayList<>(); List<SecurityEvent> securityEvents = securityEventListener.getReceivedSecurityEvents(); for (int i = 0; i < securityEvents.size(); i++) { SecurityEvent securityEvent = securityEvents.get(i); if (securityEvent.getCorrelationID().equals(encryptedPartCorrelationID)) { encryptedPartSecurityEvents.add(securityEvent); } else if (securityEvent.getCorrelationID().equals(signedElementCorrelationID1)) { signedElementSecurityEvents1.add(securityEvent); } else if (securityEvent.getCorrelationID().equals(signedElementCorrelationID2)) { signedElementSecurityEvents2.add(securityEvent); } else if (securityEvent.getCorrelationID().equals(signatureValueCorrelationID)) { signatureValueSecurityEvents.add(securityEvent); } else if (securityEvent.getCorrelationID().equals(operationCorrelationID)) { operationSecurityEvents.add(securityEvent); } } Assert.assertEquals(4, encryptedPartSecurityEvents.size()); Assert.assertEquals(3, signedElementSecurityEvents1.size()); Assert.assertEquals(3, signedElementSecurityEvents2.size()); Assert.assertEquals(4, signatureValueSecurityEvents.size()); Assert.assertEquals(securityEventListener.getReceivedSecurityEvents().size(), operationSecurityEvents.size() + encryptedPartSecurityEvents.size() + signedElementSecurityEvents1.size() + signedElementSecurityEvents2.size() + signatureValueSecurityEvents.size() + 1 //the timestamp ); } @Test public void testInteroperabilityInboundSOAP12() throws Exception { InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.2.xml"); String action = WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT; Properties properties = new Properties(); properties.setProperty(WSHandlerConstants.SIGNATURE_PARTS, "{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;{Element}{http://www.w3.org/2003/05/soap-envelope}Body;"); Document securedDocument = doOutboundSecurityWithWSS4J(sourceDocument, action, properties); ByteArrayOutputStream baos = new ByteArrayOutputStream(); javax.xml.transform.Transformer transformer = TRANSFORMER_FACTORY.newTransformer(); transformer.transform(new DOMSource(securedDocument), new StreamResult(baos)); WSSSecurityProperties securityProperties = new WSSSecurityProperties(); securityProperties.setCallbackHandler(new CallbackHandlerImpl()); securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); WSSecurityEventConstants.Event[] expectedSecurityEvents = new WSSecurityEventConstants.Event[]{ WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.X509Token, WSSecurityEventConstants.X509Token, WSSecurityEventConstants.SignatureValue, WSSecurityEventConstants.TIMESTAMP, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.SIGNED_PART, WSSecurityEventConstants.ENCRYPTED_PART, WSSecurityEventConstants.OPERATION, }; final TestSecurityEventListener securityEventListener = new TestSecurityEventListener(expectedSecurityEvents); Document document = doInboundSecurity( securityProperties, xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())), securityEventListener); //read the whole stream: transformer = TRANSFORMER_FACTORY.newTransformer(); transformer.transform(new DOMSource(document), new StreamResult( new OutputStream() { @Override public void write(int b) throws IOException { // > /dev/null } } )); securityEventListener.compare(); } @Test public void testInteroperabilityEncryptedSignatureInbound() throws Exception { InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"); String action = WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT; Properties properties = new Properties(); properties.setProperty(WSHandlerConstants.SIGNATURE_PARTS, "{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;{Element}{http://schemas.xmlsoap.org/soap/envelope/}Body;"); properties.setProperty(WSHandlerConstants.ENCRYPTION_PARTS, "{Element}{http://www.w3.org/2000/09/xmldsig#}Signature;{Content}{http://schemas.xmlsoap.org/soap/envelope/}Body;"); Document securedDocument = doOutboundSecurityWithWSS4J(sourceDocument, action, properties); ByteArrayOutputStream baos = new ByteArrayOutputStream(); javax.xml.transform.Transformer transformer = TRANSFORMER_FACTORY.newTransformer(); transformer.transform(new DOMSource(securedDocument), new StreamResult(baos)); WSSSecurityProperties securityProperties = new WSSSecurityProperties(); securityProperties.setCallbackHandler(new CallbackHandlerImpl()); securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); WSSecurityEventConstants.Event[] expectedSecurityEvents = new WSSecurityEventConstants.Event[]{ WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.X509Token, WSSecurityEventConstants.X509Token, WSSecurityEventConstants.EncryptedElement, WSSecurityEventConstants.SignatureValue, WSSecurityEventConstants.TIMESTAMP, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.SIGNED_PART, WSSecurityEventConstants.ENCRYPTED_PART, WSSecurityEventConstants.OPERATION, }; final TestSecurityEventListener securityEventListener = new TestSecurityEventListener(expectedSecurityEvents); Document document = doInboundSecurity( securityProperties, xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())), securityEventListener); //read the whole stream: transformer = TRANSFORMER_FACTORY.newTransformer(); transformer.transform(new DOMSource(document), new StreamResult( new OutputStream() { @Override public void write(int b) throws IOException { // > /dev/null } } )); securityEventListener.compare(); EncryptedElementSecurityEvent encryptedElementSecurityEvent = securityEventListener.getSecurityEvent(WSSecurityEventConstants.EncryptedElement); EncryptedPartSecurityEvent encryptedPartSecurityEvent = securityEventListener.getSecurityEvent(WSSecurityEventConstants.ENCRYPTED_PART); List<SignedElementSecurityEvent> signedElementSecurityEventList = securityEventListener.getSecurityEvents(WSSecurityEventConstants.SignedElement); List<SignedPartSecurityEvent> signedPartSecurityEventList = securityEventListener.getSecurityEvents(WSSecurityEventConstants.SIGNED_PART); SignatureValueSecurityEvent signatureValueSecurityEvent = securityEventListener.getSecurityEvent(WSSecurityEventConstants.SignatureValue); OperationSecurityEvent operationSecurityEvent = securityEventListener.getSecurityEvent(WSSecurityEventConstants.OPERATION); String encryptedElementCorrelationID = encryptedElementSecurityEvent.getCorrelationID(); String encryptedPartCorrelationID = encryptedPartSecurityEvent.getCorrelationID(); String signedElementCorrelationID1 = signedElementSecurityEventList.get(0).getCorrelationID(); String signedElementCorrelationID2 = signedPartSecurityEventList.get(0).getCorrelationID(); String signatureValueCorrelationID = signatureValueSecurityEvent.getCorrelationID(); String operationCorrelationID = operationSecurityEvent.getCorrelationID(); List<SecurityEvent> operationSecurityEvents = new ArrayList<>(); List<SecurityEvent> encryptedPartSecurityEvents = new ArrayList<>(); List<SecurityEvent> encryptedElementSecurityEvents = new ArrayList<>(); List<SecurityEvent> signedElementSecurityEvents1 = new ArrayList<>(); List<SecurityEvent> signedElementSecurityEvents2 = new ArrayList<>(); List<SecurityEvent> signatureValueSecurityEvents = new ArrayList<>(); List<SecurityEvent> securityEvents = securityEventListener.getReceivedSecurityEvents(); for (int i = 0; i < securityEvents.size(); i++) { SecurityEvent securityEvent = securityEvents.get(i); if (securityEvent.getCorrelationID().equals(encryptedPartCorrelationID)) { encryptedPartSecurityEvents.add(securityEvent); } else if (securityEvent.getCorrelationID().equals(encryptedElementCorrelationID)) { encryptedElementSecurityEvents.add(securityEvent); } else if (securityEvent.getCorrelationID().equals(signedElementCorrelationID1)) { signedElementSecurityEvents1.add(securityEvent); } else if (securityEvent.getCorrelationID().equals(signedElementCorrelationID2)) { signedElementSecurityEvents2.add(securityEvent); } else if (securityEvent.getCorrelationID().equals(signatureValueCorrelationID)) { signatureValueSecurityEvents.add(securityEvent); } else if (securityEvent.getCorrelationID().equals(operationCorrelationID)) { operationSecurityEvents.add(securityEvent); } } Assert.assertEquals(3, encryptedPartSecurityEvents.size()); Assert.assertEquals(3, encryptedElementSecurityEvents.size()); Assert.assertEquals(3, signedElementSecurityEvents1.size()); Assert.assertEquals(3, signedElementSecurityEvents2.size()); Assert.assertEquals(4, signatureValueSecurityEvents.size()); Assert.assertEquals(securityEventListener.getReceivedSecurityEvents().size(), operationSecurityEvents.size() + encryptedPartSecurityEvents.size() + encryptedElementSecurityEvents.size() + signedElementSecurityEvents1.size() + signedElementSecurityEvents2.size() + signatureValueSecurityEvents.size() + 1 //the timestamp ); } //Not supported ATM: Timestamp encrypted and then Signed /* @Test(invocationCount = 1) public void testInteroperabilitySignedEncryptedTimestampInbound() throws Exception { InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"); String action = WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.ENCRYPT + " " + WSHandlerConstants.SIGNATURE; Properties properties = new Properties(); properties.setProperty(WSHandlerConstants.SIGNATURE_PARTS, "{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;{Element}{http://schemas.xmlsoap.org/soap/envelope/}Body;"); properties.setProperty(WSHandlerConstants.ENCRYPTION_PARTS, "{Content}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;{Content}{http://schemas.xmlsoap.org/soap/envelope/}Body;"); Document securedDocument = doOutboundSecurityWithWSS4J(sourceDocument, action, properties); ByteArrayOutputStream baos = new ByteArrayOutputStream(); javax.xml.transform.Transformer transformer = TRANSFORMER_FACTORY.newTransformer(); transformer.transform(new DOMSource(securedDocument), new StreamResult(baos)); WSSSecurityProperties securityProperties = new WSSSecurityProperties(); securityProperties.setCallbackHandler(new CallbackHandlerImpl()); securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); Document document = doInboundSecurity(securityProperties, xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray()))); //read the whole stream: transformer = TRANSFORMER_FACTORY.newTransformer(); //transformer.transform(new DOMSource(document), new StreamResult(System.out)); transformer.transform(new DOMSource(document), new StreamResult( new OutputStream() { @Override public void write(int b) throws IOException { // > /dev/null } } )); } */ @Test public void testInteroperabilityInboundReverseOrder() throws Exception { InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"); String action = WSHandlerConstants.ENCRYPT + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.TIMESTAMP; Document securedDocument = doOutboundSecurityWithWSS4J(sourceDocument, action, new Properties()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); javax.xml.transform.Transformer transformer = TRANSFORMER_FACTORY.newTransformer(); transformer.transform(new DOMSource(securedDocument), new StreamResult(baos)); WSSSecurityProperties securityProperties = new WSSSecurityProperties(); securityProperties.setCallbackHandler(new CallbackHandlerImpl()); securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); WSSecurityEventConstants.Event[] expectedSecurityEvents = new WSSecurityEventConstants.Event[]{ WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.X509Token, WSSecurityEventConstants.X509Token, WSSecurityEventConstants.TIMESTAMP, WSSecurityEventConstants.SignatureValue, WSSecurityEventConstants.SIGNED_PART, WSSecurityEventConstants.ENCRYPTED_PART, WSSecurityEventConstants.OPERATION, }; final TestSecurityEventListener securityEventListener = new TestSecurityEventListener(expectedSecurityEvents); Document document = doInboundSecurity( securityProperties, xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())), securityEventListener); //read the whole stream: transformer = TRANSFORMER_FACTORY.newTransformer(); transformer.transform(new DOMSource(document), new StreamResult( new OutputStream() { @Override public void write(int b) throws IOException { // > /dev/null } } )); securityEventListener.compare(); EncryptedPartSecurityEvent encryptedPartSecurityEvent = securityEventListener.getSecurityEvent(WSSecurityEventConstants.ENCRYPTED_PART); List<SignedPartSecurityEvent> signedPartSecurityEvents = securityEventListener.getSecurityEvents(WSSecurityEventConstants.SIGNED_PART); SignatureValueSecurityEvent signatureValueSecurityEvent = securityEventListener.getSecurityEvent(WSSecurityEventConstants.SignatureValue); OperationSecurityEvent operationSecurityEvent = securityEventListener.getSecurityEvent(WSSecurityEventConstants.OPERATION); String encryptedPartCorrelationID = encryptedPartSecurityEvent.getCorrelationID(); String signedElementCorrelationID1 = signedPartSecurityEvents.get(0).getCorrelationID(); String signatureValueCorrelationID = signatureValueSecurityEvent.getCorrelationID(); String operationCorrelationID = operationSecurityEvent.getCorrelationID(); List<SecurityEvent> operationSecurityEvents = new ArrayList<>(); List<SecurityEvent> encryptedPartSecurityEvents = new ArrayList<>(); List<SecurityEvent> signedElementSecurityEvents1 = new ArrayList<>(); List<SecurityEvent> signatureValueSecurityEvents = new ArrayList<>(); List<SecurityEvent> securityEvents = securityEventListener.getReceivedSecurityEvents(); for (int i = 0; i < securityEvents.size(); i++) { SecurityEvent securityEvent = securityEvents.get(i); if (securityEvent.getCorrelationID().equals(encryptedPartCorrelationID)) { encryptedPartSecurityEvents.add(securityEvent); } else if (securityEvent.getCorrelationID().equals(signedElementCorrelationID1)) { signedElementSecurityEvents1.add(securityEvent); } else if (securityEvent.getCorrelationID().equals(signatureValueCorrelationID)) { signatureValueSecurityEvents.add(securityEvent); } else if (securityEvent.getCorrelationID().equals(operationCorrelationID)) { operationSecurityEvents.add(securityEvent); } } Assert.assertEquals(4, encryptedPartSecurityEvents.size()); Assert.assertEquals(3, signedElementSecurityEvents1.size()); Assert.assertEquals(4, signatureValueSecurityEvents.size()); Assert.assertEquals(securityEventListener.getReceivedSecurityEvents().size(), operationSecurityEvents.size() + encryptedPartSecurityEvents.size() + signedElementSecurityEvents1.size() + signatureValueSecurityEvents.size() + 1 //the timestamp ); } @Test public void testInteroperabilityOutbound() throws Exception { WSSSecurityProperties securityProperties = new WSSSecurityProperties(); securityProperties.setCallbackHandler(new CallbackHandlerImpl()); securityProperties.setEncryptionUser("receiver"); securityProperties.loadEncryptionKeystore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray()); securityProperties.setSignatureUser("transmitter"); securityProperties.loadSignatureKeyStore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray()); List<WSSConstants.Action> actions = new ArrayList<WSSConstants.Action>(); actions.add(WSSConstants.TIMESTAMP); actions.add(WSSConstants.SIGNATURE); actions.add(WSSConstants.ENCRYPT); securityProperties.setActions(actions); InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"); ByteArrayOutputStream baos = doOutboundSecurity(securityProperties, sourceDocument); String action = WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT; doInboundSecurityWithWSS4J(documentBuilderFactory.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray())), action); } @Test public void testInteroperabilityOutboundReverseOrder() throws Exception { WSSSecurityProperties securityProperties = new WSSSecurityProperties(); securityProperties.setCallbackHandler(new CallbackHandlerImpl()); securityProperties.setEncryptionUser("receiver"); securityProperties.loadEncryptionKeystore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray()); securityProperties.setSignatureUser("transmitter"); securityProperties.loadSignatureKeyStore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray()); List<WSSConstants.Action> actions = new ArrayList<WSSConstants.Action>(); actions.add(WSSConstants.ENCRYPT); actions.add(WSSConstants.SIGNATURE); actions.add(WSSConstants.TIMESTAMP); securityProperties.setActions(actions); InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"); ByteArrayOutputStream baos = doOutboundSecurity(securityProperties, sourceDocument); String action = WSHandlerConstants.ENCRYPT + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.TIMESTAMP; doInboundSecurityWithWSS4J(documentBuilderFactory.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray())), action); } @Test public void testInteroperabilityOutboundSignature() throws Exception { WSSSecurityProperties securityProperties = new WSSSecurityProperties(); securityProperties.setCallbackHandler(new CallbackHandlerImpl()); securityProperties.setEncryptionUser("receiver"); securityProperties.loadEncryptionKeystore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray()); securityProperties.setSignatureUser("transmitter"); securityProperties.loadSignatureKeyStore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray()); List<WSSConstants.Action> actions = new ArrayList<WSSConstants.Action>(); actions.add(WSSConstants.SIGNATURE); securityProperties.setActions(actions); InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"); ByteArrayOutputStream baos = doOutboundSecurity(securityProperties, sourceDocument); String action = WSHandlerConstants.SIGNATURE; doInboundSecurityWithWSS4J(documentBuilderFactory.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray())), action); } @Test public void testInteroperabilityInboundSecurityHeaderTimestampOrder() throws Exception { InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"); String action = WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT; Properties properties = new Properties(); properties.setProperty(WSHandlerConstants.SIGNATURE_PARTS, "{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;{Element}{http://schemas.xmlsoap.org/soap/envelope/}Body;"); properties.setProperty(WSHandlerConstants.ENCRYPTION_PARTS, "{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;{Content}{http://schemas.xmlsoap.org/soap/envelope/}Body;"); Document securedDocument = doOutboundSecurityWithWSS4J(sourceDocument, action, properties); ByteArrayOutputStream baos = new ByteArrayOutputStream(); javax.xml.transform.Transformer transformer = TRANSFORMER_FACTORY.newTransformer(); transformer.transform(new DOMSource(securedDocument), new StreamResult(baos)); XPathExpression xPathExpression = getXPath("/soap:Envelope/soap:Header/wsse:Security/xenc:EncryptedData"); Element timeStamp = (Element) xPathExpression.evaluate(securedDocument, XPathConstants.NODE); Element securityHeaderNode = (Element) timeStamp.getParentNode(); securityHeaderNode.removeChild(timeStamp); xPathExpression = getXPath("/soap:Envelope/soap:Header/wsse:Security/dsig:Signature"); Element signature = (Element) xPathExpression.evaluate(securedDocument, XPathConstants.NODE); securityHeaderNode.insertBefore(timeStamp, signature); WSSSecurityProperties securityProperties = new WSSSecurityProperties(); securityProperties.setCallbackHandler(new CallbackHandlerImpl()); securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); WSSecurityEventConstants.Event[] expectedSecurityEvents = new WSSecurityEventConstants.Event[]{ WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.X509Token, WSSecurityEventConstants.X509Token, WSSecurityEventConstants.SignatureValue, WSSecurityEventConstants.EncryptedElement, WSSecurityEventConstants.TIMESTAMP, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.SIGNED_PART, WSSecurityEventConstants.ENCRYPTED_PART, WSSecurityEventConstants.OPERATION, }; final TestSecurityEventListener securityEventListener = new TestSecurityEventListener(expectedSecurityEvents); Document document = doInboundSecurity( securityProperties, xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())), securityEventListener); //read the whole stream: transformer = TRANSFORMER_FACTORY.newTransformer(); transformer.transform(new DOMSource(document), new StreamResult( new OutputStream() { @Override public void write(int b) throws IOException { // > /dev/null } } )); securityEventListener.compare(); EncryptedElementSecurityEvent encryptedElementSecurityEvent = securityEventListener.getSecurityEvent(WSSecurityEventConstants.EncryptedElement); EncryptedPartSecurityEvent encryptedPartSecurityEvent = securityEventListener.getSecurityEvent(WSSecurityEventConstants.ENCRYPTED_PART); List<SignedElementSecurityEvent> signedElementSecurityEvents = securityEventListener.getSecurityEvents(WSSecurityEventConstants.SignedElement); List<SignedPartSecurityEvent> signedPartSecurityEvents = securityEventListener.getSecurityEvents(WSSecurityEventConstants.SIGNED_PART); SignatureValueSecurityEvent signatureValueSecurityEvent = securityEventListener.getSecurityEvent(WSSecurityEventConstants.SignatureValue); OperationSecurityEvent operationSecurityEvent = securityEventListener.getSecurityEvent(WSSecurityEventConstants.OPERATION); String encryptedElementCorrelationID = encryptedElementSecurityEvent.getCorrelationID(); String encryptedPartCorrelationID = encryptedPartSecurityEvent.getCorrelationID(); String signedElementCorrelationID1 = signedElementSecurityEvents.get(0).getCorrelationID(); String signedElementCorrelationID2 = signedPartSecurityEvents.get(0).getCorrelationID(); String signatureValueCorrelationID = signatureValueSecurityEvent.getCorrelationID(); String operationCorrelationID = operationSecurityEvent.getCorrelationID(); List<SecurityEvent> operationSecurityEvents = new ArrayList<>(); List<SecurityEvent> encryptedPartSecurityEvents = new ArrayList<>(); List<SecurityEvent> encryptedElementSecurityEvents = new ArrayList<>(); List<SecurityEvent> signedElementSecurityEvents1 = new ArrayList<>(); List<SecurityEvent> signedElementSecurityEvents2 = new ArrayList<>(); List<SecurityEvent> signatureValueSecurityEvents = new ArrayList<>(); List<SecurityEvent> securityEvents = securityEventListener.getReceivedSecurityEvents(); for (int i = 0; i < securityEvents.size(); i++) { SecurityEvent securityEvent = securityEvents.get(i); if (securityEvent.getCorrelationID().equals(encryptedPartCorrelationID)) { encryptedPartSecurityEvents.add(securityEvent); } else if (securityEvent.getCorrelationID().equals(encryptedElementCorrelationID)) { encryptedElementSecurityEvents.add(securityEvent); } else if (securityEvent.getCorrelationID().equals(signedElementCorrelationID1)) { signedElementSecurityEvents1.add(securityEvent); } else if (securityEvent.getCorrelationID().equals(signedElementCorrelationID2)) { signedElementSecurityEvents2.add(securityEvent); } else if (securityEvent.getCorrelationID().equals(signatureValueCorrelationID)) { signatureValueSecurityEvents.add(securityEvent); } else if (securityEvent.getCorrelationID().equals(operationCorrelationID)) { operationSecurityEvents.add(securityEvent); } } Assert.assertEquals(3, encryptedPartSecurityEvents.size()); Assert.assertEquals(3, encryptedElementSecurityEvents.size()); Assert.assertEquals(3, signedElementSecurityEvents1.size()); Assert.assertEquals(3, signedElementSecurityEvents2.size()); Assert.assertEquals(4, signatureValueSecurityEvents.size()); Assert.assertEquals(securityEventListener.getReceivedSecurityEvents().size(), operationSecurityEvents.size() + encryptedPartSecurityEvents.size() + encryptedElementSecurityEvents.size() + signedElementSecurityEvents1.size() + signedElementSecurityEvents2.size() + signatureValueSecurityEvents.size() + 1 //the timestamp ); } @Test public void testEncDecryptionUseReqSigCert() throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); { InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"); String action = WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT; Properties properties = new Properties(); properties.setProperty(WSHandlerConstants.SIGNATURE_PARTS, "{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;{Element}{http://schemas.xmlsoap.org/soap/envelope/}Body;"); Map<String, Object> messageContext = doOutboundSecurityWithWSS4J_1(sourceDocument, action, properties); Document securedDocument = (Document) messageContext.get(SECURED_DOCUMENT); //some test that we can really sure we get what we want from WSS4J NodeList nodeList = securedDocument.getElementsByTagNameNS(WSSConstants.TAG_dsig_Signature.getNamespaceURI(), WSSConstants.TAG_dsig_Signature.getLocalPart()); Assert.assertEquals(nodeList.item(0).getParentNode().getLocalName(), WSSConstants.TAG_WSSE_SECURITY.getLocalPart()); javax.xml.transform.Transformer transformer = TRANSFORMER_FACTORY.newTransformer(); transformer.transform(new DOMSource(securedDocument), new StreamResult(baos)); } final List<SecurityEvent> securityEventList = new ArrayList<>(); //done signature; now test sig-verification: { WSSSecurityProperties securityProperties = new WSSSecurityProperties(); securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); securityProperties.setCallbackHandler(new org.apache.wss4j.stax.test.CallbackHandlerImpl()); InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties); SecurityEventListener securityEventListener = new SecurityEventListener() { @Override public void registerSecurityEvent(SecurityEvent securityEvent) throws WSSecurityException { securityEventList.add(securityEvent); } }; XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())), new ArrayList<SecurityEvent>(), securityEventListener); Document document = StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader); //header element must still be there NodeList nodeList = document.getElementsByTagNameNS(WSSConstants.TAG_dsig_Signature.getNamespaceURI(), WSSConstants.TAG_dsig_Signature.getLocalPart()); Assert.assertEquals(nodeList.getLength(), 1); Assert.assertEquals(nodeList.item(0).getParentNode().getLocalName(), WSSConstants.TAG_WSSE_SECURITY.getLocalPart()); } //so we have a request generated, now do the response: baos = new ByteArrayOutputStream(); { WSSSecurityProperties securityProperties = new WSSSecurityProperties(); List<WSSConstants.Action> actions = new ArrayList<WSSConstants.Action>(); actions.add(WSSConstants.TIMESTAMP); actions.add(WSSConstants.SIGNATURE); actions.add(WSSConstants.ENCRYPT); securityProperties.setActions(actions); securityProperties.loadSignatureKeyStore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); securityProperties.setSignatureUser("receiver"); securityProperties.setCallbackHandler(new CallbackHandlerImpl()); securityProperties.setUseReqSigCertForEncryption(true); OutboundWSSec wsSecOut = WSSec.getOutboundWSSec(securityProperties); XMLStreamWriter xmlStreamWriter = wsSecOut.processOutMessage(baos, StandardCharsets.UTF_8.name(), securityEventList); XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml")); XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter); xmlStreamWriter.close(); Document document = documentBuilderFactory.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray())); NodeList nodeList = document.getElementsByTagNameNS(WSSConstants.TAG_dsig_Signature.getNamespaceURI(), WSSConstants.TAG_dsig_Signature.getLocalPart()); Assert.assertEquals(nodeList.item(0).getParentNode().getLocalName(), WSSConstants.TAG_WSSE_SECURITY.getLocalPart()); nodeList = document.getElementsByTagNameNS(WSSConstants.TAG_dsig_Reference.getNamespaceURI(), WSSConstants.TAG_dsig_Reference.getLocalPart()); Assert.assertEquals(nodeList.getLength(), 1); nodeList = document.getElementsByTagNameNS(WSSConstants.NS_SOAP11, WSSConstants.TAG_SOAP_BODY_LN); Assert.assertEquals(nodeList.getLength(), 1); String idAttrValue = ((Element) nodeList.item(0)).getAttributeNS(WSSConstants.ATT_WSU_ID.getNamespaceURI(), WSSConstants.ATT_WSU_ID.getLocalPart()); Assert.assertNotNull(idAttrValue); Assert.assertTrue(idAttrValue.length() > 0); } //verify SigConf response: { String action = WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT; Properties properties = new Properties(); doInboundSecurityWithWSS4J_1(documentBuilderFactory.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray())), action, properties, true); } } @Test public void testEncryptedSignatureC14NInclusivePartsOutbound() throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); { WSSSecurityProperties securityProperties = new WSSSecurityProperties(); List<WSSConstants.Action> actions = new ArrayList<WSSConstants.Action>(); actions.add(WSSConstants.SIGNATURE); actions.add(WSSConstants.ENCRYPT); securityProperties.setActions(actions); securityProperties.loadSignatureKeyStore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray()); securityProperties.loadEncryptionKeystore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray()); securityProperties.setSignatureUser("transmitter"); securityProperties.setEncryptionUser("receiver"); securityProperties.addSignaturePart(new SecurePart(new QName("http://www.w3.org/1999/XMLSchema", "complexType"), SecurePart.Modifier.Element)); securityProperties.setSignatureCanonicalizationAlgorithm("http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"); securityProperties.setCallbackHandler(new CallbackHandlerImpl()); OutboundWSSec wsSecOut = WSSec.getOutboundWSSec(securityProperties); XMLStreamWriter xmlStreamWriter = wsSecOut.processOutMessage(baos, StandardCharsets.UTF_8.name(), new ArrayList<SecurityEvent>()); XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml")); XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter); xmlStreamWriter.close(); Document document = documentBuilderFactory.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray())); NodeList nodeList = document.getElementsByTagNameNS(WSSConstants.TAG_dsig_Signature.getNamespaceURI(), WSSConstants.TAG_dsig_Signature.getLocalPart()); Assert.assertEquals(nodeList.item(0).getParentNode().getLocalName(), WSSConstants.TAG_WSSE_SECURITY.getLocalPart()); nodeList = document.getElementsByTagNameNS(WSSConstants.TAG_dsig_Reference.getNamespaceURI(), WSSConstants.TAG_dsig_Reference.getLocalPart()); Assert.assertEquals(nodeList.getLength(), 25); nodeList = document.getElementsByTagNameNS("http://www.w3.org/1999/XMLSchema", "complexType"); Assert.assertEquals(nodeList.getLength(), 0); } //done signature; now test sig-verification: { String action = WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT; Properties properties = new Properties(); doInboundSecurityWithWSS4J_1(documentBuilderFactory.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray())), action, properties, false); } } /** * Inclusive Canonicalization with Encryption is problematic because xenc namespace "leaks" * WSS4J sets the xenc ns on the soap envelope which is not included in the signature on the sending * side. swsssf sets the ns where it belongs and so we don't have this problem. But if we * get an xenc ns on the envelope we will get a signature error. This case can't be handled correctly. * This is also one of the reasons why a exclusive canonicalisation is preferred for SOAP * * @throws Exception */ @Test public void testSignatureC14NInclusivePartsInbound() throws Exception { //retest 100 times to make sure we don't have a threading issue for (int i = 0; i < 100; i++) { Document securedDocument; ByteArrayOutputStream baos = new ByteArrayOutputStream(); { WSSSecurityProperties securityProperties = new WSSSecurityProperties(); List<WSSConstants.Action> actions = new ArrayList<WSSConstants.Action>(); actions.add(WSSConstants.SIGNATURE); actions.add(WSSConstants.ENCRYPT); securityProperties.setActions(actions); securityProperties.loadSignatureKeyStore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray()); securityProperties.loadEncryptionKeystore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray()); securityProperties.setSignatureUser("transmitter"); securityProperties.setEncryptionUser("receiver"); securityProperties.addSignaturePart(new SecurePart(new QName("http://www.w3.org/1999/XMLSchema", "complexType"), SecurePart.Modifier.Element)); securityProperties.setSignatureCanonicalizationAlgorithm("http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"); securityProperties.setCallbackHandler(new CallbackHandlerImpl()); OutboundWSSec wsSecOut = WSSec.getOutboundWSSec(securityProperties); XMLStreamWriter xmlStreamWriter = wsSecOut.processOutMessage(baos, StandardCharsets.UTF_8.name(), new ArrayList<SecurityEvent>()); XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml")); XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter); xmlStreamWriter.close(); securedDocument = documentBuilderFactory.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray())); NodeList nodeList = securedDocument.getElementsByTagNameNS(WSSConstants.TAG_dsig_Signature.getNamespaceURI(), WSSConstants.TAG_dsig_Signature.getLocalPart()); Assert.assertEquals(nodeList.item(0).getParentNode().getLocalName(), WSSConstants.TAG_WSSE_SECURITY.getLocalPart()); } { String action = WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT; Properties properties = new Properties(); doInboundSecurityWithWSS4J_1(documentBuilderFactory.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray())), action, properties, false); } //done signature; now test sig-verification: { WSSSecurityProperties securityProperties = new WSSSecurityProperties(); securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); securityProperties.setCallbackHandler(new CallbackHandlerImpl()); securityProperties.addIgnoreBSPRule(BSPRule.R5404); securityProperties.addIgnoreBSPRule(BSPRule.R5423); securityProperties.addIgnoreBSPRule(BSPRule.R5412); InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties); WSSecurityEventConstants.Event[] expectedSecurityEvents = new WSSecurityEventConstants.Event[]{ WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.X509Token, WSSecurityEventConstants.X509Token, WSSecurityEventConstants.SignatureValue, WSSecurityEventConstants.ENCRYPTED_PART, WSSecurityEventConstants.OPERATION, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.SignedElement, }; final TestSecurityEventListener securityEventListener = new TestSecurityEventListener(expectedSecurityEvents); XMLStreamReader xmlStreamReader = wsSecIn.processInMessage( xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())), null, securityEventListener); Document document = StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader); //header element must still be there NodeList nodeList = document.getElementsByTagNameNS(WSSConstants.TAG_dsig_Signature.getNamespaceURI(), WSSConstants.TAG_dsig_Signature.getLocalPart()); Assert.assertEquals(nodeList.getLength(), 1); Assert.assertEquals(nodeList.item(0).getParentNode().getLocalName(), WSSConstants.TAG_WSSE_SECURITY.getLocalPart()); securityEventListener.compare(); } } } @Test public void testInteroperabilitySOAPActionInbound() throws Exception { InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"); String action = WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT; Properties properties = new Properties(); properties.setProperty(WSHandlerConstants.SIGNATURE_PARTS, "{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;{Element}{http://schemas.xmlsoap.org/soap/envelope/}Body;"); properties.setProperty(WSHandlerConstants.ACTOR, "test"); Document securedDocument = doOutboundSecurityWithWSS4J(sourceDocument, action, properties); ByteArrayOutputStream baos = new ByteArrayOutputStream(); javax.xml.transform.Transformer transformer = TRANSFORMER_FACTORY.newTransformer(); transformer.transform(new DOMSource(securedDocument), new StreamResult(baos)); WSSSecurityProperties securityProperties = new WSSSecurityProperties(); securityProperties.setCallbackHandler(new CallbackHandlerImpl()); securityProperties.setActor("test"); securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); WSSecurityEventConstants.Event[] expectedSecurityEvents = new WSSecurityEventConstants.Event[]{ WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.X509Token, WSSecurityEventConstants.X509Token, WSSecurityEventConstants.SignatureValue, WSSecurityEventConstants.TIMESTAMP, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.SIGNED_PART, WSSecurityEventConstants.ENCRYPTED_PART, WSSecurityEventConstants.OPERATION, }; final TestSecurityEventListener securityEventListener = new TestSecurityEventListener(expectedSecurityEvents); Document document = doInboundSecurity( securityProperties, xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())), securityEventListener); //read the whole stream: transformer = TRANSFORMER_FACTORY.newTransformer(); transformer.transform(new DOMSource(document), new StreamResult( new OutputStream() { @Override public void write(int b) throws IOException { // > /dev/null } } )); securityEventListener.compare(); } @Test public void testInteroperabilityInvalidSOAPActionInbound() throws Exception { InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"); String action = WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT; Properties properties = new Properties(); properties.setProperty(WSHandlerConstants.SIGNATURE_PARTS, "{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;{Element}{http://schemas.xmlsoap.org/soap/envelope/}Body;"); properties.setProperty(WSHandlerConstants.ACTOR, "test"); Document securedDocument = doOutboundSecurityWithWSS4J(sourceDocument, action, properties); ByteArrayOutputStream baos = new ByteArrayOutputStream(); javax.xml.transform.Transformer transformer = TRANSFORMER_FACTORY.newTransformer(); transformer.transform(new DOMSource(securedDocument), new StreamResult(baos)); WSSSecurityProperties securityProperties = new WSSSecurityProperties(); securityProperties.setCallbackHandler(new CallbackHandlerImpl()); securityProperties.setActor("anotherTest"); securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); WSSecurityEventConstants.Event[] expectedSecurityEvents = new WSSecurityEventConstants.Event[]{ WSSecurityEventConstants.NO_SECURITY, WSSecurityEventConstants.OPERATION }; final TestSecurityEventListener securityEventListener = new TestSecurityEventListener(expectedSecurityEvents); Document document = doInboundSecurity( securityProperties, xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())), securityEventListener); //read the whole stream: transformer = TRANSFORMER_FACTORY.newTransformer(); transformer.transform(new DOMSource(document), new StreamResult( new OutputStream() { @Override public void write(int b) throws IOException { // > /dev/null } } )); securityEventListener.compare(); } @Test public void testInteroperabilitySOAPRoleInbound() throws Exception { InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.2.xml"); String action = WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT; Properties properties = new Properties(); properties.setProperty(WSHandlerConstants.ACTOR, "test"); properties.setProperty(WSHandlerConstants.SIGNATURE_PARTS, "{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;{Element}{http://www.w3.org/2003/05/soap-envelope}Body;"); Document securedDocument = doOutboundSecurityWithWSS4J(sourceDocument, action, properties); ByteArrayOutputStream baos = new ByteArrayOutputStream(); javax.xml.transform.Transformer transformer = TRANSFORMER_FACTORY.newTransformer(); transformer.transform(new DOMSource(securedDocument), new StreamResult(baos)); WSSSecurityProperties securityProperties = new WSSSecurityProperties(); securityProperties.setCallbackHandler(new CallbackHandlerImpl()); securityProperties.setActor("test"); securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); WSSecurityEventConstants.Event[] expectedSecurityEvents = new WSSecurityEventConstants.Event[]{ WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.AlgorithmSuite, WSSecurityEventConstants.X509Token, WSSecurityEventConstants.X509Token, WSSecurityEventConstants.SignatureValue, WSSecurityEventConstants.TIMESTAMP, WSSecurityEventConstants.SignedElement, WSSecurityEventConstants.SIGNED_PART, WSSecurityEventConstants.ENCRYPTED_PART, WSSecurityEventConstants.OPERATION, }; final TestSecurityEventListener securityEventListener = new TestSecurityEventListener(expectedSecurityEvents); Document document = doInboundSecurity( securityProperties, xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())), securityEventListener); //read the whole stream: transformer = TRANSFORMER_FACTORY.newTransformer(); transformer.transform(new DOMSource(document), new StreamResult( new OutputStream() { @Override public void write(int b) throws IOException { // > /dev/null } } )); securityEventListener.compare(); } @Test public void testInteroperabilityTwoSecurityHeadersSOAPRoleInbound() throws Exception { InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.2.xml"); String action = WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT; Properties properties = new Properties(); properties.setProperty(WSHandlerConstants.SIGNATURE_PARTS, "{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;{Element}{http://www.w3.org/2003/05/soap-envelope}Body;"); Document securedDocument = doOutboundSecurityWithWSS4J(sourceDocument, action, properties); ByteArrayOutputStream baos = new ByteArrayOutputStream(); javax.xml.transform.Transformer transformer = TRANSFORMER_FACTORY.newTransformer(); transformer.transform(new DOMSource(securedDocument), new StreamResult(baos)); properties.setProperty(WSHandlerConstants.ACTOR, "test"); securedDocument = doOutboundSecurityWithWSS4J(new ByteArrayInputStream(baos.toByteArray()), action, properties); transformer = TRANSFORMER_FACTORY.newTransformer(); baos.reset(); transformer.transform(new DOMSource(securedDocument), new StreamResult(baos)); WSSSecurityProperties securityProperties = new WSSSecurityProperties(); securityProperties.setCallbackHandler(new CallbackHandlerImpl()); securityProperties.setActor("test"); securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); Document document = doInboundSecurity(securityProperties, xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray()))); //read the whole stream: transformer = TRANSFORMER_FACTORY.newTransformer(); transformer.transform(new DOMSource(document), new StreamResult( new OutputStream() { @Override public void write(int b) throws IOException { // > /dev/null } } )); } @Test public void testInteroperabilitySOAPActionOutbound() throws Exception { WSSSecurityProperties securityProperties = new WSSSecurityProperties(); securityProperties.setCallbackHandler(new CallbackHandlerImpl()); securityProperties.setActor("test"); securityProperties.setEncryptionUser("receiver"); securityProperties.loadEncryptionKeystore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray()); securityProperties.setSignatureUser("transmitter"); securityProperties.loadSignatureKeyStore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray()); List<WSSConstants.Action> actions = new ArrayList<WSSConstants.Action>(); actions.add(WSSConstants.TIMESTAMP); actions.add(WSSConstants.SIGNATURE); actions.add(WSSConstants.ENCRYPT); securityProperties.setActions(actions); InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"); ByteArrayOutputStream baos = doOutboundSecurity(securityProperties, sourceDocument); String action = WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT; Properties properties = new Properties(); properties.setProperty(WSHandlerConstants.ACTOR, "test"); doInboundSecurityWithWSS4J_1(documentBuilderFactory.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray())), action, properties, false); } @Test public void testInteroperabilityInvalidSOAPActionOutbound() throws Exception { WSSSecurityProperties securityProperties = new WSSSecurityProperties(); securityProperties.setCallbackHandler(new CallbackHandlerImpl()); securityProperties.setActor("test"); securityProperties.setEncryptionUser("receiver"); securityProperties.loadEncryptionKeystore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray()); securityProperties.setSignatureUser("transmitter"); securityProperties.loadSignatureKeyStore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray()); List<WSSConstants.Action> actions = new ArrayList<WSSConstants.Action>(); actions.add(WSSConstants.TIMESTAMP); actions.add(WSSConstants.SIGNATURE); actions.add(WSSConstants.ENCRYPT); securityProperties.setActions(actions); InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"); ByteArrayOutputStream baos = doOutboundSecurity(securityProperties, sourceDocument); String action = WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT; Properties properties = new Properties(); properties.setProperty(WSHandlerConstants.ACTOR, "anotherTest"); try { doInboundSecurityWithWSS4J_1(documentBuilderFactory.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray())), action, properties, false); Assert.fail("Expected WSSecurityException"); } catch (WSSecurityException e) { Assert.assertEquals(e.getMessage(), "WSS4JHandler: Request does not contain required Security header"); } } @Test public void testInteroperabilitySOAPRoleOutbound() throws Exception { WSSSecurityProperties securityProperties = new WSSSecurityProperties(); securityProperties.setCallbackHandler(new CallbackHandlerImpl()); securityProperties.setActor("test"); securityProperties.setEncryptionUser("receiver"); securityProperties.loadEncryptionKeystore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray()); securityProperties.setSignatureUser("transmitter"); securityProperties.loadSignatureKeyStore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray()); List<WSSConstants.Action> actions = new ArrayList<WSSConstants.Action>(); actions.add(WSSConstants.TIMESTAMP); actions.add(WSSConstants.SIGNATURE); actions.add(WSSConstants.ENCRYPT); securityProperties.setActions(actions); InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.2.xml"); ByteArrayOutputStream baos = doOutboundSecurity(securityProperties, sourceDocument); String action = WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT; Properties properties = new Properties(); properties.setProperty(WSHandlerConstants.ACTOR, "test"); doInboundSecurityWithWSS4J_1(documentBuilderFactory.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray())), action, properties, false); } @Test public void testInteroperabilityTwoSecurityHeadersSOAPRoleOutbound() throws Exception { WSSSecurityProperties securityProperties = new WSSSecurityProperties(); securityProperties.setCallbackHandler(new CallbackHandlerImpl()); securityProperties.setEncryptionUser("receiver"); securityProperties.loadEncryptionKeystore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray()); securityProperties.setSignatureUser("transmitter"); securityProperties.loadSignatureKeyStore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray()); List<WSSConstants.Action> actions = new ArrayList<WSSConstants.Action>(); actions.add(WSSConstants.TIMESTAMP); actions.add(WSSConstants.SIGNATURE); actions.add(WSSConstants.ENCRYPT); securityProperties.setActions(actions); InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.2.xml"); ByteArrayOutputStream baos = doOutboundSecurity(securityProperties, sourceDocument); securityProperties.setActor("test"); baos = doOutboundSecurity(securityProperties, new ByteArrayInputStream(baos.toByteArray())); String action = WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT; Properties properties = new Properties(); properties.setProperty(WSHandlerConstants.ACTOR, "test"); doInboundSecurityWithWSS4J_1(documentBuilderFactory.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray())), action, properties, false); } @Test public void testInvalidXML() throws Exception { int i = 0; int e = 10000; while (i < e) { String action = WSHandlerConstants.USERNAME_TOKEN + " " + WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT; Properties properties = new Properties(); InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"); Document securedDocument = doOutboundSecurityWithWSS4J(sourceDocument, action, properties); ByteArrayOutputStream baos = new ByteArrayOutputStream(); if (i == 0) { i = indexOfNode(securedDocument.getDocumentElement(), new NodeIndex(), WSSConstants.TAG_WSSE_SECURITY.getLocalPart()).index; e = indexOfNode(securedDocument.getDocumentElement(), new NodeIndex(), "definitions").index; } i++; Node nodeToRemove = nodeOnIndex(securedDocument.getDocumentElement(), new NodeIndex(), i).node; if (nodeToRemove.getNodeType() == Node.ATTRIBUTE_NODE) { ((Attr) nodeToRemove).getOwnerElement().removeAttributeNode((Attr) nodeToRemove); } else { Node parentNode = nodeToRemove.getParentNode(); parentNode.removeChild(nodeToRemove); } javax.xml.transform.Transformer transformer = TRANSFORMER_FACTORY.newTransformer(); transformer.transform(new DOMSource(securedDocument), new StreamResult(baos)); WSSSecurityProperties securityProperties = new WSSSecurityProperties(); securityProperties.setCallbackHandler(new CallbackHandlerImpl()); securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray()); Iterator<BSPRule> bspRules = EnumSet.allOf(BSPRule.class).iterator(); while (bspRules.hasNext()) { securityProperties.addIgnoreBSPRule(bspRules.next()); } try { Document document = doInboundSecurity(securityProperties, xmlInputFactory.createXMLStreamReader( new ByteArrayInputStream(baos.toByteArray()))); //read the whole stream: transformer = TRANSFORMER_FACTORY.newTransformer(); transformer.transform(new DOMSource(document), new StreamResult( new OutputStream() { @Override public void write(int b) throws IOException { // > /dev/null } } )); } catch (XMLStreamException ex) { int k = 0; Throwable t = ex.getCause(); while (t != null && k < 100) { StringWriter stringWriter = new StringWriter(); PrintWriter pw = new PrintWriter(stringWriter); ex.printStackTrace(pw); Assert.assertFalse(stringWriter.toString(), t instanceof NullPointerException); t = t.getCause(); } } } } private NodeIndex indexOfNode(Node node, NodeIndex index, String name) { if (node.getLocalName() != null && node.getLocalName().equals(name)) { return index; } index.index++; if (node.getNodeType() == Node.ELEMENT_NODE) { NamedNodeMap namedNodeMap = node.getAttributes(); for (int i = 0; i < namedNodeMap.getLength(); i++) { NodeIndex n = indexOfNode(namedNodeMap.item(i), index, name); if (n != null) { return n; } } } NodeList nodeList = node.getChildNodes(); for (int i = 0; i < nodeList.getLength(); i++) { NodeIndex n = indexOfNode(nodeList.item(i), index, name); if (n != null) { return n; } } return null; } private NodeIndex nodeOnIndex(Node node, NodeIndex index, int indexToFind) { if (index.index == indexToFind) { index.node = node; return index; } index.index++; if (node.getNodeType() == Node.ELEMENT_NODE) { NamedNodeMap namedNodeMap = node.getAttributes(); for (int i = 0; i < namedNodeMap.getLength(); i++) { NodeIndex n = nodeOnIndex(namedNodeMap.item(i), index, indexToFind); if (n != null) { return n; } } } NodeList nodeList = node.getChildNodes(); for (int i = 0; i < nodeList.getLength(); i++) { NodeIndex n = nodeOnIndex(nodeList.item(i), index, indexToFind); if (n != null) { return n; } } return null; } class NodeIndex { Node node; int index; } }