View Javadoc
1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied. See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.wss4j.dom.message;
21  
22  import java.io.IOException;
23  import java.util.Iterator;
24  import java.util.LinkedList;
25  import java.util.List;
26  
27  import javax.xml.namespace.QName;
28  import javax.xml.transform.TransformerException;
29  
30  import org.apache.wss4j.common.util.XMLUtils;
31  
32  
33  import org.w3c.dom.Document;
34  import org.w3c.dom.Element;
35  import org.w3c.dom.Node;
36  import org.w3c.dom.NodeList;
37  
38  /**
39   * Applies message transformations to the tests in
40   * org.apache.wss4j.dom.message.RequireSignedEncryptedDataElementsTest
41   */
42  public class TestMessageTransformer {
43      private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(TestMessageTransformer.class);
44  
45      public static Element duplicateEncryptedDataInWsseHeader(Element saaj, boolean moveReferenceList) throws TransformerException, IOException {
46          if (moveReferenceList) {
47              moveReferenceList(saaj);
48          }
49          Element body = getFirstChildElement(saaj, new QName("http://schemas.xmlsoap.org/soap/envelope/",
50                                                              "Body"), true);
51          Element encData = getFirstChildElement(body, new QName("http://www.w3.org/2001/04/xmlenc#",
52                                                                 "EncryptedData"), true);
53          Element newEncData = createNewEncryptedData(encData);
54          Element sh = getFirstChildElement(saaj, new QName("http://schemas.xmlsoap.org/soap/envelope/",
55                                                            "Header"), true);
56          Element wsseHeader = getFirstChildElement(sh,
57                                                    new QName(
58                                                              "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
59                                                              "Security"), true);
60  
61          Node newWsseHeader = wsseHeader.cloneNode(false);
62          Node cur = wsseHeader.getFirstChild();
63  
64          String newId = newEncData.getAttributeNS(null, "Id");
65          while (cur != null) {
66              cur = copyHeadersAndUpdateRefList(cur, newWsseHeader, newId);
67          }
68          newWsseHeader.appendChild(newEncData);
69  
70          if (!moveReferenceList) {
71              updateEncryptedKeyRefList(newWsseHeader, newId);
72          }
73  
74          Node parent = wsseHeader.getParentNode();
75          parent.removeChild(wsseHeader);
76          parent.appendChild(newWsseHeader);
77          print(saaj.getOwnerDocument());
78          return newEncData;
79      }
80  
81      public static Element duplicateEncryptedDataInWsseWrapperHeader(Element saaj, boolean moveReferenceList) throws TransformerException, IOException {
82          if (moveReferenceList) {
83              moveReferenceList(saaj);
84          }
85          Element body = getFirstChildElement(saaj, new QName("http://schemas.xmlsoap.org/soap/envelope/",
86                                                              "Body"), true);
87          Element encData = getFirstChildElement(body, new QName("http://www.w3.org/2001/04/xmlenc#",
88                                                                 "EncryptedData"), true);
89          Element newEncData = createNewEncryptedData(encData);
90          Element sh = getFirstChildElement(saaj, new QName("http://schemas.xmlsoap.org/soap/envelope/",
91                                                            "Header"), true);
92          Element signature = getFirstChildElement(sh, new QName("http://www.w3.org/2000/09/xmldsig#",
93                                                                 "Signature"), true);
94  
95          Node wsseHeader = signature.getParentNode();
96          Node newWsseHeader = wsseHeader.cloneNode(false);
97          Node cur = wsseHeader.getFirstChild();
98          String newId = newEncData.getAttributeNS(null, "Id");
99          while (!cur.isSameNode(signature)) {
100             cur = copyHeadersAndUpdateRefList(cur, newWsseHeader, newId);
101         }
102         Element wrapper = encData.getOwnerDocument().createElementNS(null, "a");
103         wrapper.appendChild(newEncData);
104         newWsseHeader.appendChild(wrapper);
105         while (cur != null) {
106             cur = copyHeadersAndUpdateRefList(cur, newWsseHeader, newId);
107         }
108 
109         if (!moveReferenceList) {
110             updateEncryptedKeyRefList(newWsseHeader, newId);
111         }
112 
113         Node parent = wsseHeader.getParentNode();
114         parent.removeChild(wsseHeader);
115         parent.appendChild(newWsseHeader);
116         print(saaj.getOwnerDocument());
117         return newEncData;
118     }
119 
120     public static Element duplicateEncryptedDataInWrapperBody(Element saaj) throws TransformerException, IOException {
121         Element body = getFirstChildElement(saaj, new QName("http://schemas.xmlsoap.org/soap/envelope/",
122                                                             "Body"), true);
123         Element encData = getFirstChildElement(body, new QName("http://www.w3.org/2001/04/xmlenc#",
124                                                                "EncryptedData"), true);
125         Element newEncData = createNewEncryptedData(encData);
126         Element sh = getFirstChildElement(saaj, new QName("http://schemas.xmlsoap.org/soap/envelope/",
127                                                           "Header"), true);
128         Element signature = getFirstChildElement(sh, new QName("http://www.w3.org/2000/09/xmldsig#",
129                                                                "Signature"), true);
130 
131         Node wsseHeader = signature.getParentNode();
132         Node newWsseHeader = wsseHeader.cloneNode(false);
133         Node cur = wsseHeader.getFirstChild();
134         String newId = newEncData.getAttributeNS(null, "Id");
135         while (!cur.isSameNode(signature)) {
136             cur = copyHeadersAndUpdateRefList(cur, newWsseHeader, newId);
137         }
138         Element wrapper = encData.getOwnerDocument().createElementNS(null, "a");
139         wrapper.appendChild(newEncData);
140 
141         body.appendChild(wrapper);
142         while (cur != null) {
143             cur = copyHeadersAndUpdateRefList(cur, newWsseHeader, newId);
144         }
145 
146         updateEncryptedKeyRefList(newWsseHeader, newId);
147 
148         Node parent = wsseHeader.getParentNode();
149         parent.removeChild(wsseHeader);
150         parent.appendChild(newWsseHeader);
151         print(saaj.getOwnerDocument());
152         return newEncData;
153     }
154 
155     public static Element duplicateEncryptedDataAfterWrapperBody(Element saaj) throws TransformerException, IOException {
156         Element body = getFirstChildElement(saaj, new QName("http://schemas.xmlsoap.org/soap/envelope/",
157                                                             "Body"), true);
158         Element encData = getFirstChildElement(body, new QName("http://www.w3.org/2001/04/xmlenc#",
159                                                                "EncryptedData"), true);
160         Element newEncData = createNewEncryptedData(encData);
161         Element sh = getFirstChildElement(saaj, new QName("http://schemas.xmlsoap.org/soap/envelope/",
162                                                           "Header"), true);
163         Element signature = getFirstChildElement(sh, new QName("http://www.w3.org/2000/09/xmldsig#",
164                                                                "Signature"), true);
165 
166         Node wsseHeader = signature.getParentNode();
167         Node newWsseHeader = wsseHeader.cloneNode(false);
168         Node cur = wsseHeader.getFirstChild();
169         String newId = newEncData.getAttributeNS(null, "Id");
170         while (!cur.isSameNode(signature)) {
171             cur = copyHeadersAndUpdateRefList(cur, newWsseHeader, newId);
172         }
173         Element wrapper = encData.getOwnerDocument().createElementNS(null, "a");
174         Node clonedBody = body.cloneNode(false);
175         clonedBody.appendChild(newEncData);
176         wrapper.appendChild(clonedBody);
177 
178         body.getParentNode().appendChild(wrapper);
179         while (cur != null) {
180             cur = copyHeadersAndUpdateRefList(cur, newWsseHeader, newId);
181         }
182 
183         updateEncryptedKeyRefList(newWsseHeader, newId);
184 
185         Node parent = wsseHeader.getParentNode();
186         parent.removeChild(wsseHeader);
187         parent.appendChild(newWsseHeader);
188         print(saaj.getOwnerDocument());
189         return newEncData;
190     }
191 
192     public static Element duplicateEncryptedDataInExternalWrapperElement(Element saaj,
193                                                                          boolean moveReferenceList) throws TransformerException, IOException {
194         if (moveReferenceList) {
195             moveReferenceList(saaj);
196         }
197         Element body = getFirstChildElement(saaj, new QName("http://schemas.xmlsoap.org/soap/envelope/",
198                                                             "Body"), true);
199         Element encData = getFirstChildElement(body, new QName("http://www.w3.org/2001/04/xmlenc#",
200                                                                "EncryptedData"), true);
201         Element newEncData = createNewEncryptedData(encData);
202         Element sh = getFirstChildElement(saaj, new QName("http://schemas.xmlsoap.org/soap/envelope/",
203                                                           "Header"), true);
204         Element wsseHeader = getFirstChildElement(sh,
205                                                   new QName(
206                                                             "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
207                                                             "Security"), true);
208 
209         Node newWsseHeader = wsseHeader.cloneNode(false);
210         Node cur = wsseHeader.getFirstChild();
211         String newId = newEncData.getAttributeNS(null, "Id");
212         while (cur != null) {
213             cur = copyHeadersAndUpdateRefList(cur, newWsseHeader, newId);
214         }
215         sh.removeChild(wsseHeader);
216         sh.appendChild(newWsseHeader);
217 
218         if (!moveReferenceList) {
219             updateEncryptedKeyRefList(newWsseHeader, newId);
220         }
221 
222         Element wrapper = encData.getOwnerDocument().createElementNS(null, "a");
223         wrapper.setAttributeNS("http://schemas.xmlsoap.org/soap/envelope/", "mustUnderstand", "0");
224         wrapper.setAttributeNS("http://schemas.xmlsoap.org/soap/envelope/", "actor", "foo");
225         wrapper.appendChild(newEncData);
226         sh.appendChild(wrapper);
227         print(saaj.getOwnerDocument());
228         return newEncData;
229     }
230 
231     public static Element addEncryptedDataWithEmbeddedEncryptedKeyInWsseHeader(Element saaj) throws TransformerException, IOException {
232         moveReferenceList(saaj);
233         Element body = getFirstChildElement(saaj, new QName("http://schemas.xmlsoap.org/soap/envelope/",
234                                                             "Body"), true);
235         Element encData = getFirstChildElement(body, new QName("http://www.w3.org/2001/04/xmlenc#",
236                                                                "EncryptedData"), true);
237 
238         Element newEncData = (Element)encData.cloneNode(true);
239         String newId = newEncData.getAttributeNS(null, "Id") + "b";
240         newEncData.setAttributeNS(null, "Id", newId);
241 
242         Element encKey = getFirstChildElement(saaj, new QName("http://www.w3.org/2001/04/xmlenc#",
243                                                               "EncryptedKey"), true);
244         Element newEncKey = (Element)encKey.cloneNode(true);
245         String newEcId = newEncKey.getAttributeNS(null, "Id") + "b";
246         newEncKey.setAttributeNS(null, "Id", newEcId);
247 
248         Element keyInfo = getFirstChildElement(newEncData, new QName("http://www.w3.org/2000/09/xmldsig#",
249                                                                      "KeyInfo"), true);
250         Element str = getFirstChildElement(newEncData,
251                                            new QName(
252                                                      "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
253                                                      "SecurityTokenReference"), true);
254         keyInfo.replaceChild(newEncKey, str);
255 
256         Element wsseHeader = getFirstChildElement(saaj,
257                                                   new QName(
258                                                             "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
259                                                             "Security"), true);
260 
261         Node newWsseHeader = wsseHeader.cloneNode(false);
262         Node cur = wsseHeader.getFirstChild();
263 
264         while (cur != null) {
265             cur = copyHeadersAndUpdateRefList(cur, newWsseHeader, newId);
266         }
267         newWsseHeader.appendChild(newEncData);
268 
269         Node parent = wsseHeader.getParentNode();
270         parent.removeChild(wsseHeader);
271         parent.appendChild(newWsseHeader);
272         print(saaj.getOwnerDocument());
273         return newEncData;
274 
275     }
276 
277     private static void moveReferenceList(Element saaj) {
278         Element sh = getFirstChildElement(saaj, new QName("http://schemas.xmlsoap.org/soap/envelope/",
279                                                           "Header"), true);
280         Element encKey = getFirstChildElement(sh, new QName("http://www.w3.org/2001/04/xmlenc#",
281                                                             "EncryptedKey"), true);
282         Element refList = getFirstChildElement(encKey, new QName("http://www.w3.org/2001/04/xmlenc#",
283                                                                  "ReferenceList"), true);
284 
285         Node wsseHeader = encKey.getParentNode();
286         encKey.removeChild(refList);
287         wsseHeader.appendChild(refList);
288     }
289 
290     private static void updateEncryptedKeyRefList(Node wsseHeader, String newId) {
291         Element encryptedKey = getFirstChildElement(wsseHeader,
292                                                     new QName("http://www.w3.org/2001/04/xmlenc#",
293                                                               "EncryptedKey"), true);
294         Element ref = getFirstChildElement(encryptedKey, new QName("http://www.w3.org/2001/04/xmlenc#",
295                                                                    "DataReference"), true);
296         Element newRef = (Element)ref.cloneNode(true);
297         newRef.setAttributeNS(null, "URI", "#" + newId);
298         ref.getParentNode().appendChild(newRef);
299     }
300 
301     private static void print(Document doc) throws TransformerException, IOException {
302         if (LOG.isDebugEnabled()) {
303             LOG.debug("After transformation....");
304             String outputString = XMLUtils.prettyDocumentToString(doc);
305             LOG.debug(outputString);
306         }
307     }
308 
309     private static Element createNewEncryptedData(Element encData) {
310         Element newEncData = (Element)encData.cloneNode(true);
311         String id = newEncData.getAttributeNS(null, "Id");
312         String newId = id + "b";
313         newEncData.setAttributeNS(null, "Id", newId);
314         return newEncData;
315     }
316 
317     private static Node copyHeadersAndUpdateRefList(Node cur, Node dest, String newId) {
318         Node temp = cur.cloneNode(true);
319         dest.appendChild(temp);
320         if (newId != null && temp.getNodeType() == Node.ELEMENT_NODE) {
321             Element t = (Element)temp;
322             if (t.getLocalName().equals("ReferenceList")) {
323                 Element ref = getFirstChildElement(t, new QName("http://www.w3.org/2001/04/xmlenc#",
324                                                                 "DataReference"), true);
325                 Element newRef = (Element)ref.cloneNode(true);
326                 newRef.setAttributeNS(null, "URI", "#" + newId);
327                 t.appendChild(newRef);
328             }
329         }
330         return cur.getNextSibling();
331     }
332 
333     private static Element getFirstChildElement(Node node, QName nodeName, boolean recursive) {
334         Element childElement = null;
335         Iterator<Element> it = getChildElements(node, nodeName, recursive).iterator();
336         if (it.hasNext()) {
337             childElement = it.next();
338         }
339         return childElement;
340     }
341 
342     private static List<Element> getChildElements(Node node, QName nodeName, boolean recursive) {
343         List<Element> list = new LinkedList<>();
344 
345         NodeList nlist = node.getChildNodes();
346         int len = nlist.getLength();
347         for (int i = 0; i < len; i++) {
348             Node child = nlist.item(i);
349             if (child.getNodeType() == Node.ELEMENT_NODE) {
350                 search(list, (Element)child, nodeName, recursive);
351             }
352         }
353         return list;
354     }
355 
356     private static void search(List<Element> list, Element baseElement, QName nodeName, boolean recursive) {
357         if (nodeName == null) {
358             list.add(baseElement);
359         } else {
360             QName qname;
361             if (nodeName.getNamespaceURI().length() > 0) {
362                 qname = new QName(baseElement.getNamespaceURI(), baseElement.getLocalName());
363             } else {
364                 qname = new QName(baseElement.getLocalName());
365             }
366             if (qname.equals(nodeName)) {
367                 list.add(baseElement);
368             }
369         }
370         if (recursive) {
371             NodeList nlist = baseElement.getChildNodes();
372             int len = nlist.getLength();
373             for (int i = 0; i < len; i++) {
374                 Node child = nlist.item(i);
375                 if (child.getNodeType() == Node.ELEMENT_NODE) {
376                     search(list, (Element)child, nodeName, recursive);
377                 }
378             }
379         }
380     }
381 
382 }