/** * 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.dom.message; import java.io.IOException; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import javax.xml.namespace.QName; import javax.xml.transform.TransformerException; import org.apache.wss4j.common.util.XMLUtils; import org.apache.wss4j.dom.common.SecurityTestUtil; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * Applies message transformations to the tests in * org.apache.wss4j.dom.message.RequireSignedEncryptedDataElementsTest */ public class TestMessageTransformer extends org.junit.Assert { private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(TestMessageTransformer.class); @org.junit.AfterClass public static void cleanup() throws Exception { SecurityTestUtil.cleanup(); } public static Element duplicateEncryptedDataInWsseHeader(Element saaj, boolean moveReferenceList) throws TransformerException, IOException { if (moveReferenceList) { moveReferenceList(saaj); } Element body = getFirstChildElement(saaj, new QName("http://schemas.xmlsoap.org/soap/envelope/", "Body"), true); Element encData = getFirstChildElement(body, new QName("http://www.w3.org/2001/04/xmlenc#", "EncryptedData"), true); Element newEncData = createNewEncryptedData(encData); Element sh = getFirstChildElement(saaj, new QName("http://schemas.xmlsoap.org/soap/envelope/", "Header"), true); Element wsseHeader = getFirstChildElement(sh, new QName( "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "Security"), true); Node newWsseHeader = wsseHeader.cloneNode(false); Node cur = wsseHeader.getFirstChild(); String newId = newEncData.getAttributeNS(null, "Id"); while (cur != null) { cur = copyHeadersAndUpdateRefList(cur, newWsseHeader, newId); } newWsseHeader.appendChild(newEncData); if (!moveReferenceList) { updateEncryptedKeyRefList(newWsseHeader, newId); } Node parent = wsseHeader.getParentNode(); parent.removeChild(wsseHeader); parent.appendChild(newWsseHeader); print(saaj.getOwnerDocument()); return newEncData; } public static Element duplicateEncryptedDataInWsseWrapperHeader(Element saaj, boolean moveReferenceList) throws TransformerException, IOException { if (moveReferenceList) { moveReferenceList(saaj); } Element body = getFirstChildElement(saaj, new QName("http://schemas.xmlsoap.org/soap/envelope/", "Body"), true); Element encData = getFirstChildElement(body, new QName("http://www.w3.org/2001/04/xmlenc#", "EncryptedData"), true); Element newEncData = createNewEncryptedData(encData); Element sh = getFirstChildElement(saaj, new QName("http://schemas.xmlsoap.org/soap/envelope/", "Header"), true); Element signature = getFirstChildElement(sh, new QName("http://www.w3.org/2000/09/xmldsig#", "Signature"), true); Node wsseHeader = signature.getParentNode(); Node newWsseHeader = wsseHeader.cloneNode(false); Node cur = wsseHeader.getFirstChild(); String newId = newEncData.getAttributeNS(null, "Id"); while (!cur.isSameNode(signature)) { cur = copyHeadersAndUpdateRefList(cur, newWsseHeader, newId); } Element wrapper = encData.getOwnerDocument().createElementNS(null, "a"); wrapper.appendChild(newEncData); newWsseHeader.appendChild(wrapper); while (cur != null) { cur = copyHeadersAndUpdateRefList(cur, newWsseHeader, newId); } if (!moveReferenceList) { updateEncryptedKeyRefList(newWsseHeader, newId); } Node parent = wsseHeader.getParentNode(); parent.removeChild(wsseHeader); parent.appendChild(newWsseHeader); print(saaj.getOwnerDocument()); return newEncData; } public static Element duplicateEncryptedDataInWrapperBody(Element saaj) throws TransformerException, IOException { Element body = getFirstChildElement(saaj, new QName("http://schemas.xmlsoap.org/soap/envelope/", "Body"), true); Element encData = getFirstChildElement(body, new QName("http://www.w3.org/2001/04/xmlenc#", "EncryptedData"), true); Element newEncData = createNewEncryptedData(encData); Element sh = getFirstChildElement(saaj, new QName("http://schemas.xmlsoap.org/soap/envelope/", "Header"), true); Element signature = getFirstChildElement(sh, new QName("http://www.w3.org/2000/09/xmldsig#", "Signature"), true); Node wsseHeader = signature.getParentNode(); Node newWsseHeader = wsseHeader.cloneNode(false); Node cur = wsseHeader.getFirstChild(); String newId = newEncData.getAttributeNS(null, "Id"); while (!cur.isSameNode(signature)) { cur = copyHeadersAndUpdateRefList(cur, newWsseHeader, newId); } Element wrapper = encData.getOwnerDocument().createElementNS(null, "a"); wrapper.appendChild(newEncData); body.appendChild(wrapper); while (cur != null) { cur = copyHeadersAndUpdateRefList(cur, newWsseHeader, newId); } updateEncryptedKeyRefList(newWsseHeader, newId); Node parent = wsseHeader.getParentNode(); parent.removeChild(wsseHeader); parent.appendChild(newWsseHeader); print(saaj.getOwnerDocument()); return newEncData; } public static Element duplicateEncryptedDataAfterWrapperBody(Element saaj) throws TransformerException, IOException { Element body = getFirstChildElement(saaj, new QName("http://schemas.xmlsoap.org/soap/envelope/", "Body"), true); Element encData = getFirstChildElement(body, new QName("http://www.w3.org/2001/04/xmlenc#", "EncryptedData"), true); Element newEncData = createNewEncryptedData(encData); Element sh = getFirstChildElement(saaj, new QName("http://schemas.xmlsoap.org/soap/envelope/", "Header"), true); Element signature = getFirstChildElement(sh, new QName("http://www.w3.org/2000/09/xmldsig#", "Signature"), true); Node wsseHeader = signature.getParentNode(); Node newWsseHeader = wsseHeader.cloneNode(false); Node cur = wsseHeader.getFirstChild(); String newId = newEncData.getAttributeNS(null, "Id"); while (!cur.isSameNode(signature)) { cur = copyHeadersAndUpdateRefList(cur, newWsseHeader, newId); } Element wrapper = encData.getOwnerDocument().createElementNS(null, "a"); Node clonedBody = body.cloneNode(false); clonedBody.appendChild(newEncData); wrapper.appendChild(clonedBody); body.getParentNode().appendChild(wrapper); while (cur != null) { cur = copyHeadersAndUpdateRefList(cur, newWsseHeader, newId); } updateEncryptedKeyRefList(newWsseHeader, newId); Node parent = wsseHeader.getParentNode(); parent.removeChild(wsseHeader); parent.appendChild(newWsseHeader); print(saaj.getOwnerDocument()); return newEncData; } public static Element duplicateEncryptedDataInExternalWrapperElement(Element saaj, boolean moveReferenceList) throws TransformerException, IOException { if (moveReferenceList) { moveReferenceList(saaj); } Element body = getFirstChildElement(saaj, new QName("http://schemas.xmlsoap.org/soap/envelope/", "Body"), true); Element encData = getFirstChildElement(body, new QName("http://www.w3.org/2001/04/xmlenc#", "EncryptedData"), true); Element newEncData = createNewEncryptedData(encData); Element sh = getFirstChildElement(saaj, new QName("http://schemas.xmlsoap.org/soap/envelope/", "Header"), true); Element wsseHeader = getFirstChildElement(sh, new QName( "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "Security"), true); Node newWsseHeader = wsseHeader.cloneNode(false); Node cur = wsseHeader.getFirstChild(); String newId = newEncData.getAttributeNS(null, "Id"); while (cur != null) { cur = copyHeadersAndUpdateRefList(cur, newWsseHeader, newId); } sh.removeChild(wsseHeader); sh.appendChild(newWsseHeader); if (!moveReferenceList) { updateEncryptedKeyRefList(newWsseHeader, newId); } Element wrapper = encData.getOwnerDocument().createElementNS(null, "a"); wrapper.setAttributeNS("http://schemas.xmlsoap.org/soap/envelope/", "mustUnderstand", "0"); wrapper.setAttributeNS("http://schemas.xmlsoap.org/soap/envelope/", "actor", "foo"); wrapper.appendChild(newEncData); sh.appendChild(wrapper); print(saaj.getOwnerDocument()); return newEncData; } public static Element addEncryptedDataWithEmbeddedEncryptedKeyInWsseHeader(Element saaj) throws TransformerException, IOException { moveReferenceList(saaj); Element body = getFirstChildElement(saaj, new QName("http://schemas.xmlsoap.org/soap/envelope/", "Body"), true); Element encData = getFirstChildElement(body, new QName("http://www.w3.org/2001/04/xmlenc#", "EncryptedData"), true); Element newEncData = (Element)encData.cloneNode(true); String newId = newEncData.getAttributeNS(null, "Id") + "b"; newEncData.setAttributeNS(null, "Id", newId); Element encKey = getFirstChildElement(saaj, new QName("http://www.w3.org/2001/04/xmlenc#", "EncryptedKey"), true); Element newEncKey = (Element)encKey.cloneNode(true); String newEcId = newEncKey.getAttributeNS(null, "Id") + "b"; newEncKey.setAttributeNS(null, "Id", newEcId); Element keyInfo = getFirstChildElement(newEncData, new QName("http://www.w3.org/2000/09/xmldsig#", "KeyInfo"), true); Element str = getFirstChildElement(newEncData, new QName( "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "SecurityTokenReference"), true); keyInfo.replaceChild(newEncKey, str); Element wsseHeader = getFirstChildElement(saaj, new QName( "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "Security"), true); Node newWsseHeader = wsseHeader.cloneNode(false); Node cur = wsseHeader.getFirstChild(); while (cur != null) { cur = copyHeadersAndUpdateRefList(cur, newWsseHeader, newId); } newWsseHeader.appendChild(newEncData); Node parent = wsseHeader.getParentNode(); parent.removeChild(wsseHeader); parent.appendChild(newWsseHeader); print(saaj.getOwnerDocument()); return newEncData; } private static void moveReferenceList(Element saaj) { Element sh = getFirstChildElement(saaj, new QName("http://schemas.xmlsoap.org/soap/envelope/", "Header"), true); Element encKey = getFirstChildElement(sh, new QName("http://www.w3.org/2001/04/xmlenc#", "EncryptedKey"), true); Element refList = getFirstChildElement(encKey, new QName("http://www.w3.org/2001/04/xmlenc#", "ReferenceList"), true); Node wsseHeader = encKey.getParentNode(); encKey.removeChild(refList); wsseHeader.appendChild(refList); } private static void updateEncryptedKeyRefList(Node wsseHeader, String newId) { Element encryptedKey = getFirstChildElement(wsseHeader, new QName("http://www.w3.org/2001/04/xmlenc#", "EncryptedKey"), true); Element ref = getFirstChildElement(encryptedKey, new QName("http://www.w3.org/2001/04/xmlenc#", "DataReference"), true); Element newRef = (Element)ref.cloneNode(true); newRef.setAttributeNS(null, "URI", "#" + newId); ref.getParentNode().appendChild(newRef); } private static void print(Document doc) throws TransformerException, IOException { if (LOG.isDebugEnabled()) { LOG.debug("After transformation...."); String outputString = XMLUtils.prettyDocumentToString(doc); LOG.debug(outputString); } } private static Element createNewEncryptedData(Element encData) { Element newEncData = (Element)encData.cloneNode(true); String id = newEncData.getAttributeNS(null, "Id"); String newId = id + "b"; newEncData.setAttributeNS(null, "Id", newId); return newEncData; } private static Node copyHeadersAndUpdateRefList(Node cur, Node dest, String newId) { Node temp = cur.cloneNode(true); dest.appendChild(temp); if (newId != null && temp.getNodeType() == Node.ELEMENT_NODE) { Element t = (Element)temp; if (t.getLocalName().equals("ReferenceList")) { Element ref = getFirstChildElement(t, new QName("http://www.w3.org/2001/04/xmlenc#", "DataReference"), true); Element newRef = (Element)ref.cloneNode(true); newRef.setAttributeNS(null, "URI", "#" + newId); t.appendChild(newRef); } } return cur.getNextSibling(); } private static Element getFirstChildElement(Node node, QName nodeName, boolean recursive) { Element childElement = null; Iterator<Element> it = getChildElements(node, nodeName, recursive).iterator(); if (it.hasNext()) { childElement = it.next(); } return childElement; } private static List<Element> getChildElements(Node node, QName nodeName, boolean recursive) { List<Element> list = new LinkedList<>(); NodeList nlist = node.getChildNodes(); int len = nlist.getLength(); for (int i = 0; i < len; i++) { Node child = nlist.item(i); if (child.getNodeType() == Node.ELEMENT_NODE) { search(list, (Element)child, nodeName, recursive); } } return list; } private static void search(List<Element> list, Element baseElement, QName nodeName, boolean recursive) { if (nodeName == null) { list.add(baseElement); } else { QName qname; if (nodeName.getNamespaceURI().length() > 0) { qname = new QName(baseElement.getNamespaceURI(), baseElement.getLocalName()); } else { qname = new QName(baseElement.getLocalName()); } if (qname.equals(nodeName)) { list.add(baseElement); } } if (recursive) { NodeList nlist = baseElement.getChildNodes(); int len = nlist.getLength(); for (int i = 0; i < len; i++) { Node child = nlist.item(i); if (child.getNodeType() == Node.ELEMENT_NODE) { search(list, (Element)child, nodeName, recursive); } } } } }