View Javadoc

1   
2   /*
3   * Copyright  2003-2004 The Apache Software Foundation.
4   *
5   *  Licensed under the Apache License, Version 2.0 (the "License");
6   *  you may not use this file except in compliance with the License.
7   *  You may obtain a copy of the License at
8   *
9   *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  */
18  
19  package org.apache.ws.security.util;
20  
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  import org.apache.ws.security.SOAP11Constants;
24  import org.apache.ws.security.SOAP12Constants;
25  import org.apache.ws.security.SOAPConstants;
26  import org.apache.ws.security.WSConstants;
27  import org.apache.ws.security.WSSConfig;
28  //import org.apache.ws.security.WSSecurityEngineResult;
29  import org.apache.ws.security.WSSecurityException;
30  import org.apache.ws.security.handler.WSHandlerConstants;
31  import org.apache.ws.security.message.token.BinarySecurity;
32  import org.apache.ws.security.message.token.X509Security;
33  import org.apache.xml.security.algorithms.JCEMapper;
34  import org.apache.xml.security.utils.Base64;
35  import org.apache.xpath.XPathAPI;
36  import org.w3c.dom.Attr;
37  import org.w3c.dom.Document;
38  import org.w3c.dom.Element;
39  import org.w3c.dom.NamedNodeMap;
40  import org.w3c.dom.Node;
41  import org.w3c.dom.NodeList;
42  import org.w3c.dom.Text;
43  
44  import javax.crypto.Cipher;
45  import javax.crypto.NoSuchPaddingException;
46  import javax.crypto.SecretKey;
47  import javax.crypto.spec.SecretKeySpec;
48  import javax.xml.namespace.QName;
49  import javax.xml.transform.TransformerException;
50  import java.security.NoSuchAlgorithmException;
51  import java.security.NoSuchProviderException;
52  import java.util.Vector;
53  
54  /***
55   * WS-Security Utility methods.
56   * <p/>
57   *
58   * @author Davanum Srinivas (dims@yahoo.com).
59   */
60  public class WSSecurityUtil {
61      private static Log log = LogFactory.getLog(WSSecurityUtil.class);
62      private static boolean doDebug = false;
63  
64      static {
65          doDebug = log.isDebugEnabled();
66      }
67  
68      /***
69       * Returns the first WS-Security header element for a given actor.
70       * Only one WS-Security header is allowed for an actor.
71       *
72       * @param doc
73       * @param actor
74       * @return the <code>wsse:Security</code> element or
75       *         <code>null</code> if not such element found
76       *	@deprecated
77       *	@see	getSecurityHeader(
78          WSSConfig wssConfig, Document doc, String actor, SOAPConstants sc)
79       */
80      public static Element getSecurityHeader(
81         Document doc, String actor, SOAPConstants sc) {
82  	return getSecurityHeader(WSSConfig.getDefaultWSConfig(), doc, actor, sc);
83      }
84  
85      /***
86       * Returns the first WS-Security header element for a given actor.
87       * Only one WS-Security header is allowed for an actor.
88       *
89       * @param doc
90       * @param actor
91       * @return the <code>wsse:Security</code> element or
92       *         <code>null</code> if not such element found
93       */
94      public static Element getSecurityHeader(
95          WSSConfig wssConfig, Document doc, String actor, SOAPConstants sc) {
96          // TODO skip non-element element, e.g. comments.
97          Element soapHeaderElement =
98              (Element) getDirectChild(doc.getFirstChild(),
99                                       sc.getHeaderQName().getLocalPart(),
100                                      sc.getEnvelopeURI());
101 
102         if (soapHeaderElement == null) { // no SOAP header at all
103             return null;
104         }
105 
106         // get all wsse:Security nodes
107         NodeList list = null;
108         int len = 0;
109         if (wssConfig.getProcessNonCompliantMessages()) {
110             for (int i = 0; len == 0 && i < WSConstants.WSSE_NS_ARRAY.length; ++i) {
111                 list = soapHeaderElement.getElementsByTagNameNS(WSConstants.WSSE_NS_ARRAY[i], WSConstants.WSSE_LN);
112                 len = list.getLength();
113             }
114         } else {
115             list = soapHeaderElement.getElementsByTagNameNS(wssConfig.getWsseNS(), WSConstants.WSSE_LN);
116         }
117         if (list == null) {
118             return null;
119         } else {
120             len = list.getLength();
121         }
122         Element elem;
123         Attr attr;
124         String hActor;
125         for (int i = 0; i < len; i++) {
126             elem = (Element) list.item(i);
127             attr = elem.getAttributeNodeNS(sc.getEnvelopeURI(), sc.getRoleAttributeQName().getLocalPart());
128             hActor = (attr != null) ? attr.getValue() : null;
129             if (WSSecurityUtil.isActorEqual(actor, hActor)) {
130                 return elem;
131             }
132         }
133         return null;
134     }
135 
136     /***
137      * Compares two actor strings and returns true if these are equal.
138      * Takes care of the null length strings and uses ignore case.
139      *
140      * @param actor
141      * @param hActor
142      * @return
143      */
144     public static boolean isActorEqual(String actor, String hActor) {
145         if ((((hActor == null) || (hActor.length() == 0))
146                 && ((actor == null) || (actor.length() == 0)))
147                 || ((hActor != null)
148                 && (actor != null)
149                 && hActor.equalsIgnoreCase(actor))) {
150             return true;
151         } else {
152             return false;
153         }
154     }
155 
156     /***
157      * Gets a direct child with specified localname and namespace.
158      * <p/>
159      *
160      * @param fNode     the node where to start the search
161      * @param localName local name of the child to get
162      * @param namespace the namespace of the child to get
163      * @return the node or <code>null</code> if not such node found
164      */
165     public static Node getDirectChild(Node fNode,
166                                       String localName,
167                                       String namespace) {
168         for (Node currentChild = fNode.getFirstChild();
169              currentChild != null;
170              currentChild = currentChild.getNextSibling()) {
171             if (localName.equals(currentChild.getLocalName()) &&
172                     namespace.equals(currentChild.getNamespaceURI())) {
173                 return currentChild;
174             }
175         }
176         return null;
177     }
178 
179     /***
180      * Gets a direct child with specified localname and one of the WSSE
181      * namespaces.
182      * <p/>
183      *
184      * @param fNode     the node where to start the search
185      * @param localName local name of the child to get
186      * @return the node or <code>null</code> if not such node found
187      */
188     public static Node getDirectChildWSSE(Node fNode, String localName) {
189         Node child = null;
190         for (int i = 0; child == null && i < WSConstants.WSSE_NS_ARRAY.length; ++i) {
191             child = getDirectChild(fNode, localName, WSConstants.WSSE_NS_ARRAY[i]);
192         }
193         return child;
194     }
195 
196     /***
197      * Gets a direct child with specified localname and one of the WSU namespaces.
198      * <p/>
199      *
200      * @param fNode     the node where to start the search
201      * @param localName local name of the child to get
202      * @return the node or <code>null</code> if not such node found
203      */
204     public static Node getDirectChildWSU(Node fNode, String localName) {
205         Node child = null;
206         for (int i = 0; child == null && i < WSConstants.WSU_NS_ARRAY.length; ++i) {
207             child = getDirectChild(fNode, localName, WSConstants.WSU_NS_ARRAY[i]);
208         }
209         return child;
210     }
211 
212     /***
213      * Gets the attribute value with specified localname and WSU namespace.
214      * <p/>
215      *
216      * @param element      the Element which contains the attribute
217      * @param attrName     local name of the attribute
218      * @param wsuNamespace the WSU namespace of the attribute to get.
219      *                     Pass null to try all WSU namespaces
220      */
221     public static String getAttributeValueWSU(Element element, String attrName, String wsuNamespace) {
222         if (wsuNamespace == null) {
223             String value = null;
224             for (int i = 0; (value == null || value.length() == 0) && i < WSConstants.WSU_NS_ARRAY.length; ++i) {
225                 value = element.getAttributeNS(WSConstants.WSU_NS_ARRAY[i], attrName);
226             }
227             return value;
228         } else {
229             return element.getAttributeNS(wsuNamespace, attrName);
230         }
231     }
232 
233     /***
234      * Gets the attribute value with specified localname and WSSE namespace.
235      * <p/>
236      *
237      * @param element       the Element which contains the attribute
238      * @param attrName      local name of the attribute
239      * @param wsseNamespace the WSSE namespace of the attribute to get.
240      *                      Pass null to try all WSSE namespaces
241      */
242     public static String getAttributeValueWSSE(Element element, String attrName, String wsseNamespace) {
243         if (wsseNamespace == null) {
244             String value = null;
245             for (int i = 0; (value == null || value.length() == 0) && i < WSConstants.WSSE_NS_ARRAY.length; ++i) {
246                 value = element.getAttributeNS(WSConstants.WSSE_NS_ARRAY[i], attrName);
247             }
248             return value;
249         } else {
250             return element.getAttributeNS(wsseNamespace, attrName);
251         }
252     }
253 
254     /***
255      * return the first soap "Body" element.
256      * <p/>
257      *
258      * @param doc
259      * @return the body element or <code>null</code> if document does not
260      *         contain a SOAP body
261      */
262     public static Element findBodyElement(Document doc, SOAPConstants sc) {
263         Element soapBodyElement =
264                 (Element) WSSecurityUtil.getDirectChild(doc.getFirstChild(),
265                         sc.getBodyQName().getLocalPart(),
266                         sc.getEnvelopeURI());
267         return soapBodyElement;
268     }
269 
270     /***
271      * Returns the first element that matches <code>name</code> and
272      * <code>namespace</code>.
273      * <p/>
274      * This is a replacement for a XPath lookup <code>//name</code> with
275      * the given namespace. It's somewhat faster than XPath, and we do
276      * not deal with prefixes, just with the real namespace URI
277      *
278      * @param startNode Where to start the search
279      * @param name      Local name of the element
280      * @param namespace Namespace URI of the element
281      * @return The found element or <code>null</code>
282      */
283     public static Node findElement(Node startNode,
284                                    String name,
285                                    String namespace) {
286 
287         /*
288         * Replace the formely recursive implementation
289         * with a depth-first-loop lookup
290         */
291         if (startNode == null) {
292             return null;
293         }
294         Node startParent = startNode.getParentNode();
295         Node processedNode = null;
296 
297         while (startNode != null) {
298             // start node processing at this point
299             if (startNode.getNodeType() == Node.ELEMENT_NODE
300                     && startNode.getLocalName().equals(name)) {
301                 String ns = startNode.getNamespaceURI();
302                 if (ns != null && ns.equals(namespace)) {
303                     return startNode;
304                 }
305 
306                 if ((namespace == null || namespace.length() == 0)
307                         && (ns == null || ns.length() == 0)) {
308                     return startNode;
309                 }
310             }
311             processedNode = startNode;
312             startNode = startNode.getFirstChild();
313 
314             // no child, this node is done.
315             if (startNode == null) {
316                 // close node processing, get sibling
317                 startNode = processedNode.getNextSibling();
318             }
319             // no more siblings, get parent, all children
320             // of parent are processed.
321             while (startNode == null) {
322                 processedNode = processedNode.getParentNode();
323                 if (processedNode == startParent) {
324                     return null;
325                 }
326                 // close parent node processing (processed node now)
327                 startNode = processedNode.getNextSibling();
328             }
329         }
330         return null;
331     }
332 
333     /***
334      * Returns the first element that containes an Id with value
335      * <code>uri</code> and <code>namespace</code>.
336      * <p/>
337      * This is a replacement for a XPath Id lookup with
338      * the given namespace. It's somewhat faster than XPath, and we do
339      * not deal with prefixes, just with the real namespace URI
340      *
341      * @param startNode Where to start the search
342      * @param value     Value of the Id attribute
343      * @param namespace Namespace URI of the Id
344      * @return The found element or <code>null</code>
345      */
346     public static Element findElementById(Node startNode,
347                                           String value,
348                                           String namespace) {
349 
350         /*
351         * Replace the formely recursive implementation with a depth-first-loop
352         * lookup
353         */
354         if (startNode == null) {
355             return null;
356         }
357         Node startParent = startNode.getParentNode();
358         Node processedNode = null;
359 
360         while (startNode != null) {
361             // start node processing at this point
362             if (startNode.getNodeType() == Node.ELEMENT_NODE) {
363                 Element se = (Element) startNode;
364                 if (se.hasAttributeNS(namespace, "Id") &&
365                         value.equals(se.getAttributeNS(namespace, "Id"))) {
366                     return se;
367                 }
368             }
369 
370             processedNode = startNode;
371             startNode = startNode.getFirstChild();
372 
373             // no child, this node is done.
374             if (startNode == null) {
375                 // close node processing, get sibling
376                 startNode = processedNode.getNextSibling();
377             }
378             // no more siblings, get parent, all children
379             // of parent are processed.
380             while (startNode == null) {
381                 processedNode = processedNode.getParentNode();
382                 if (processedNode == startParent) {
383                     return null;
384                 }
385                 // close parent node processing (processed node now)
386                 startNode = processedNode.getNextSibling();
387             }
388         }
389         return null;
390     }
391 
392     /***
393      * set the namespace if it is not set already.
394      * <p/>
395      *
396      * @param element
397      * @param namespace
398      * @param prefix
399      * @return
400      */
401     public static String setNamespace(Element element,
402                                       String namespace,
403                                       String prefix) {
404         String pre = getPrefixNS(namespace, element);
405         if (pre != null) {
406             return pre;
407         }
408         element.setAttributeNS(WSConstants.XMLNS_NS,
409                 "xmlns:" + prefix, namespace);
410         return prefix;
411     }
412 
413     /* ** The following methods were copied over from aixs.utils.XMLUtils and adapted */
414 
415     public static String getPrefixNS(String uri, Node e) {
416         while (e != null && (e.getNodeType() == Element.ELEMENT_NODE)) {
417             NamedNodeMap attrs = e.getAttributes();
418             for (int n = 0; n < attrs.getLength(); n++) {
419                 Attr a = (Attr) attrs.item(n);
420                 String name;
421                 if ((name = a.getName()).startsWith("xmlns:") &&
422                         a.getNodeValue().equals(uri)) {
423                     return name.substring(6);
424                 }
425             }
426             e = e.getParentNode();
427         }
428         return null;
429     }
430 
431     public static String getNamespace(String prefix, Node e) {
432         while (e != null && (e.getNodeType() == Node.ELEMENT_NODE)) {
433             Attr attr = null;
434             if (prefix == null) {
435                 attr = ((Element) e).getAttributeNode("xmlns");
436             } else {
437                 attr = ((Element) e).getAttributeNodeNS(WSConstants.XMLNS_NS,
438                         prefix);
439             }
440             if (attr != null) return attr.getValue();
441             e = e.getParentNode();
442         }
443         return null;
444     }
445 
446     /***
447      * Return a QName when passed a string like "foo:bar" by mapping
448      * the "foo" prefix to a namespace in the context of the given Node.
449      *
450      * @return a QName generated from the given string representation
451      */
452     public static QName getQNameFromString(String str, Node e) {
453         return getQNameFromString(str, e, false);
454     }
455 
456     /***
457      * Return a QName when passed a string like "foo:bar" by mapping
458      * the "foo" prefix to a namespace in the context of the given Node.
459      * If default namespace is found it is returned as part of the QName.
460      *
461      * @return a QName generated from the given string representation
462      */
463     public static QName getFullQNameFromString(String str, Node e) {
464         return getQNameFromString(str, e, true);
465     }
466 
467     private static QName getQNameFromString(String str,
468                                             Node e,
469                                             boolean defaultNS) {
470         if (str == null || e == null)
471             return null;
472         int idx = str.indexOf(':');
473         if (idx > -1) {
474             String prefix = str.substring(0, idx);
475             String ns = getNamespace(prefix, e);
476             if (ns == null)
477                 return null;
478             return new QName(ns, str.substring(idx + 1));
479         } else {
480             if (defaultNS) {
481                 String ns = getNamespace(null, e);
482                 if (ns != null)
483                     return new QName(ns, str);
484             }
485             return new QName("", str);
486         }
487     }
488 
489     /***
490      * Return a string for a particular QName, mapping a new prefix
491      * if necessary.
492      */
493     public static String getStringForQName(QName qname, Element e) {
494         String uri = qname.getNamespaceURI();
495         String prefix = getPrefixNS(uri, e);
496         if (prefix == null) {
497             int i = 1;
498             prefix = "ns" + i;
499             while (getNamespace(prefix, e) != null) {
500                 i++;
501                 prefix = "ns" + i;
502             }
503             e.setAttributeNS(WSConstants.XMLNS_NS,
504                     "xmlns:" + prefix, uri);
505         }
506         return prefix + ":" + qname.getLocalPart();
507     }
508     /* ** up to here */
509 
510     /***
511      * Search for an element given its wsu:id.
512      * <p/>
513      *
514      * @param wssConfig The WSS configuration data conating namesapce 
515      * 	definitions, etc.
516      * @param doc the DOM document (SOAP request) 
517      * @param id the Id of the element
518      * @return the found element or null if no element with the Id exists
519      * @deprecated
520      * @see getElementByWsuId(WSSConfig wssConfig, Document doc, String id)
521     */
522      public static Element getElementByWsuId(Document doc, String id) {
523 	return getElementByWsuId(WSSConfig.getDefaultWSConfig(), doc, id);
524     }
525     /***
526      * Search for an element given its wsu:id.
527      * <p/>
528      *
529      * @param wssConfig The WSS configuration data conating namesapce 
530      * 	definitions, etc.
531      * @param doc the DOM document (SOAP request) 
532      * @param id the Id of the element
533      * @return the found element or null if no element with the Id exists
534      */
535     public static Element getElementByWsuId(WSSConfig wssConfig, Document doc, String id) {
536 
537         if (id == null) {
538             return null;
539         }
540         id = id.trim();
541         if ((id.length() == 0) || (id.charAt(0) != '#')) {
542             return null;
543         }
544         id = id.substring(1);
545         if (wssConfig.getProcessNonCompliantMessages()) {
546             Element element = null;
547             for (int i = 0; element == null && i < WSConstants.WSU_NS_ARRAY.length; ++i) {
548                 element = WSSecurityUtil.findElementById(doc.getDocumentElement(), id, WSConstants.WSU_NS_ARRAY[i]);
549             }
550             return element;
551         } else {
552             return WSSecurityUtil.findElementById(doc.getDocumentElement(), id, wssConfig.getWsuNS());
553         }
554 
555     }
556 
557     /***
558      * Search for an element given its generic id.
559      * <p/>
560      *
561      * @param doc the DOM document (SOAP request) 
562      * @param id the Id of the element
563      * @return the found element or null if no element with the Id exists
564      */
565     public static Element getElementByGenId(Document doc, String id) {
566         if (id == null) {
567             return null;
568         }
569         id = id.trim();
570         if ((id.length() == 0) || (id.charAt(0) != '#')) {
571             return null;
572         }
573         id = id.substring(1);
574         return WSSecurityUtil.findElementById(doc.getDocumentElement(), id, null);
575     }
576 
577     /***
578      * Create a BinarySecurityToken element
579      * <p/>
580      *
581      * @param doc the DOM document (SOAP request) 
582      * @param wsuIdVal the value for the wsu:Id
583      * @param wssConfig The WSS configuration data conating namesapce 
584      * 	definitions, etc.
585      * @return then BST element (DOM element)
586      * @deprecated
587      * @see createBinarySecurityToken(Document doc,
588                                                     String wsuIdVal,
589                                                     WSSConfig wssConfig)
590      */
591     public static Element createBinarySecurityToken(Document doc,
592                                                     String wsuIdVal) {
593 	return createBinarySecurityToken(doc, wsuIdVal, 
594 					 WSSConfig.getDefaultWSConfig());
595     }
596 
597     /***
598      * Create a BinarySecurityToken element
599      * <p/>
600      *
601      * @param doc the DOM document (SOAP request) 
602      * @param wsuIdVal the value for the wsu:Id
603      * @param wssConfig The WSS configuration data conating namesapce 
604      * 	definitions, etc.
605      * @return then BST element (DOM element)
606      */
607     public static Element createBinarySecurityToken(Document doc,
608                                                     String wsuIdVal,
609                                                     WSSConfig wssConfig) {
610         Element retVal = doc.createElementNS(wssConfig.getWsseNS(),
611                 "wsse:BinarySecurityToken");
612         retVal.setAttributeNS(WSConstants.XMLNS_NS,
613                 "xmlns:wsu", wssConfig.getWsuNS());
614         retVal.setAttributeNS(WSConstants.WSU_NS, "wsu:Id", wsuIdVal);
615         retVal.setAttributeNS(null, "ValueType", X509Security.getType(wssConfig));
616         retVal.setAttributeNS(null, "EncodingType",
617                 BinarySecurity.getBase64EncodingValue(wssConfig));
618         return retVal;
619     }
620 
621     /***
622      * create a new element in the same namespace
623      * <p/>
624      *
625      * @param parent for the new element
626      * @param localName of the new element
627      * @return the new element
628      */
629     private static Element createElementInSameNamespace(Element parent,
630                                                         String localName) {
631         String prefix = parent.getPrefix();
632         if (prefix == null) {
633             prefix = "";
634         }
635         String qName = prefix + ":" + localName;
636         String nsUri = parent.getNamespaceURI();
637         return parent.getOwnerDocument().createElementNS(nsUri, qName);
638     }
639 
640     /***
641      * find a child element with given namespace and local name
642      * <p/>
643      *
644      * @param parent the node to start the search
645      * @param namespaceUri of the element
646      * @param localName of the eleme
647      * @return the found element or null if the element does not exist
648      */
649     private static Element findChildElement(Element parent,
650                                             String namespaceUri,
651                                             String localName) {
652         NodeList children = parent.getChildNodes();
653         int len = children.getLength();
654         for (int i = 0; i < len; i++) {
655             Node child = children.item(i);
656             if (child.getNodeType() == Node.ELEMENT_NODE) {
657                 Element elementChild = (Element) child;
658                 if (namespaceUri.equals(elementChild.getNamespaceURI()) &&
659                         localName.equals(elementChild.getLocalName())) {
660                     return elementChild;
661                 }
662             }
663         }
664         return null;
665     }
666 
667     /***
668      * append a child element
669      * <p/>
670      *
671      * @param doc the DOM document (SOAP request)
672      * @param parent element of this child element
673      * @param child the element to append
674      * @return the child element
675      */
676     public static Element appendChildElement(Document doc,
677                                              Element parent,
678                                              Element child) {
679         Node whitespaceText = doc.createTextNode("\n");
680         parent.appendChild(whitespaceText);
681         parent.appendChild(child);
682         return child;
683     }
684 
685     /***
686      * prepend a child element
687      * <p/>
688      *
689      * @param doc the DOM document (SOAP request)
690      * @param parent element of this child element
691      * @param child the element to append
692      * @param addWhitespace if true prepend a newline before child
693      * @return the child element
694      */
695     public static Element prependChildElement(Document doc,
696                                               Element parent,
697                                               Element child,
698                                               boolean addWhitespace) {
699         Node firstChild = parent.getFirstChild();
700         if (firstChild == null) {
701             parent.appendChild(child);
702         } else {
703             parent.insertBefore(child, firstChild);
704         }
705         if (addWhitespace) {
706             Node whitespaceText = doc.createTextNode("\n");
707             parent.insertBefore(whitespaceText, child);
708         }
709         return child;
710     }
711 
712     /***
713      * find the first ws-security header block
714      * <p/>
715      *
716      * @param doc the DOM document (SOAP request)
717      * @param envelope the SOAP envelope
718      * @param doCreate if true create a new WSS header block if none exists
719      * @return the WSS header or null if none found and doCreate is false
720      * @deprecated
721      * @see	findWsseSecurityHeaderBlock(WSSConfig wssConfig, Document doc, Element envelope, boolean doCreate)
722      */
723     public static Element findWsseSecurityHeaderBlock(Document doc, Element envelope, boolean doCreate) {
724         return findWsseSecurityHeaderBlock(WSSConfig.getDefaultWSConfig(), doc, envelope, doCreate);
725     }
726 
727     /***
728      * find the first ws-security header block
729      * <p/>
730      *
731      * @param doc the DOM document (SOAP request)
732      * @param envelope the SOAP envelope
733      * @param doCreate if true create a new WSS header block if none exists
734      * @return the WSS header or null if none found and doCreate is false
735      */
736     public static Element findWsseSecurityHeaderBlock(WSSConfig wssConfig, Document doc, Element envelope, boolean doCreate) {
737         return findWsseSecurityHeaderBlock(wssConfig, doc, envelope, null, doCreate);
738     }
739 
740     /***
741      * find the first ws-security header block
742      * <p/>
743      *
744      * @param doc the DOM document (SOAP request)
745      * @param envelope the SOAP envelope
746      * @param doCreate if true create a new WSS header block if none exists
747      * @return the WSS header or null if none found and doCreate is false
748      * @deprecated
749      * @see findWsseSecurityHeaderBlock(WSSConfig wssConfig,
750                                                       Document doc,
751                                                       Element envelope,
752                                                       String actor,
753                                                       boolean doCreate)
754      */
755     public static Element findWsseSecurityHeaderBlock(Document doc,
756                                                       Element envelope,
757                                                       String actor,
758                                                       boolean doCreate) {
759 	return findWsseSecurityHeaderBlock(WSSConfig.getDefaultWSConfig(),
760                                            doc,
761                                            envelope,
762                                            actor,
763 					   doCreate);
764     }
765     /***
766      * find a ws-security header block for a given actor
767      * <p/>
768      *
769      * @param doc the DOM document (SOAP request)
770      * @param envelope the SOAP envelope
771      * @param actor the acttoer (role) name of the WSS header
772      * @param doCreate if true create a new WSS header block if none exists
773      * @return the WSS header or null if none found and doCreate is false
774      */
775     public static Element findWsseSecurityHeaderBlock(WSSConfig wssConfig,
776                                                       Document doc,
777                                                       Element envelope,
778                                                       String actor,
779                                                       boolean doCreate) {
780         SOAPConstants sc = getSOAPConstants(envelope);
781         Element wsseSecurity = getSecurityHeader(wssConfig, doc, actor, sc);
782         if (wsseSecurity != null) {
783             return wsseSecurity;
784         }
785         Element header = findChildElement(envelope, sc.getEnvelopeURI(), sc.getHeaderQName().getLocalPart());
786         if (header == null) {
787             if (doCreate) {
788                 header = createElementInSameNamespace(envelope, sc.getHeaderQName().getLocalPart());
789                 header = prependChildElement(doc, envelope, header, true);
790             }
791         }
792         if (doCreate) {
793             wsseSecurity = header.getOwnerDocument().createElementNS(wssConfig.getWsseNS(), "wsse:Security");
794             wsseSecurity.setAttributeNS(WSConstants.XMLNS_NS, "xmlns:wsse", wssConfig.getWsseNS());
795             return prependChildElement(doc, header, wsseSecurity, true);
796         }
797         return null;
798     }
799 
800     /***
801      * create a base64 test node
802      * <p/>
803      *
804      * @param doc the DOM document (SOAP request)
805      * @param data to encode
806      * @return a Text node containing the base64 encoded data
807      */
808     public static Text createBase64EncodedTextNode(Document doc, byte data[]) {
809         return doc.createTextNode(Base64.encode(data));
810     }
811 
812     /***
813      * use xpath to find a node
814      * <p/>
815      *
816      * @param contextNode node to starte the select
817      * @param xpath the xpath expression
818      * @param nsContext the context element for xpath
819      * @return the select Node
820      * @throws Exception
821      */
822     public static Node selectSingleNode(Node contextNode,
823                                         String xpath,
824                                         Element nsContext) throws Exception {
825         try {
826             return XPathAPI.selectSingleNode(contextNode, xpath, nsContext);
827         } catch (TransformerException e) {
828             throw new Exception("Unable to resolve XPath");
829         }
830     }
831 
832     /***
833      * Create a namespace context with namespaces of interest
834      *
835      * @param doc the DOM document (SOAP request)
836      * @return a conext element usable for xpath requests
837      *	@deprecated
838      *	@see	createNamespaceContext(WSSConfig wssConfig, Document doc)
839      */
840     public static Element createNamespaceContext(Document doc) {
841 	return createNamespaceContext(WSSConfig.getDefaultWSConfig(), doc);
842     }
843 
844     /***
845      * Create a namespace context with namespaces of interest
846      *
847      * @param doc the DOM document (SOAP request)
848      * @return a conext element usable for xpath requests
849      */
850     public static Element createNamespaceContext(WSSConfig wssConfig, Document doc) {
851         SOAPConstants sc = getSOAPConstants(doc.getDocumentElement());
852         Element nsContext = doc.createElementNS(null, "namespaceContext");
853         nsContext.setAttributeNS(WSConstants.XMLNS_NS, "xmlns:env", sc.getEnvelopeURI());
854         nsContext.setAttributeNS(WSConstants.XMLNS_NS, "xmlns:wsse", wssConfig.getWsseNS());
855         nsContext.setAttributeNS(WSConstants.XMLNS_NS, "xmlns:wsu", wssConfig.getWsuNS());
856         nsContext.setAttributeNS(WSConstants.XMLNS_NS, "xmlns:ds", WSConstants.SIG_NS);
857         nsContext.setAttributeNS(WSConstants.XMLNS_NS, "xmlns:xenc", WSConstants.ENC_NS);
858         return nsContext;
859     }
860 
861     public static SecretKey prepareSecretKey(String symEncAlgo,
862                                              byte[] rawKey) {
863         SecretKeySpec keySpec = new SecretKeySpec(
864             rawKey, JCEMapper.getJCEKeyAlgorithmFromURI(symEncAlgo));
865         return (SecretKey) keySpec;
866     }
867 
868     public static SOAPConstants getSOAPConstants(Element startElement) {
869         Document doc = startElement.getOwnerDocument();
870         String ns = doc.getDocumentElement().getNamespaceURI();
871         if (WSConstants.URI_SOAP12_ENV.equals(ns)) {
872             return new SOAP12Constants();
873         } else {
874             return new SOAP11Constants();
875         }
876     }
877 
878     public static Cipher getCipherInstance(String cipherAlgo)
879             throws WSSecurityException {
880         Cipher cipher = null;
881         try {
882             if (cipherAlgo.equalsIgnoreCase(WSConstants.KEYTRANSPORT_RSA15)) {
883                 cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING", "BC");
884             } else if (
885                     cipherAlgo.equalsIgnoreCase(WSConstants.KEYTRANSPORT_RSAOEP)) {
886                 cipher = Cipher.getInstance("RSA/NONE/OAEPPADDING", "BC");
887             } else {
888                 throw new WSSecurityException(WSSecurityException.UNSUPPORTED_ALGORITHM,
889                         "unsupportedKeyTransp",
890                         new Object[]{cipherAlgo});
891             }
892         } catch (NoSuchPaddingException ex) {
893             throw new WSSecurityException(WSSecurityException.UNSUPPORTED_ALGORITHM,
894                     "unsupportedKeyTransp",
895                     new Object[]{"No such padding: " + cipherAlgo});
896         } catch (NoSuchProviderException ex) {
897             throw new WSSecurityException(WSSecurityException.UNSUPPORTED_ALGORITHM,
898                     "unsupportedKeyTransp",
899                     new Object[]{"no provider: " + cipherAlgo});
900         } catch (NoSuchAlgorithmException ex) {
901             throw new WSSecurityException(WSSecurityException.UNSUPPORTED_ALGORITHM,
902                     "unsupportedKeyTransp",
903                     new Object[]{"No such algorithm: " + cipherAlgo});
904         }
905         return cipher;
906     }
907 
908     /***
909      * Fetch the result of a given action from a given result vector
910      * <p/>
911      *
912      * @param wsResultVector The result vector to fetch an action from
913      * @param action         The action to fetch
914      * @return The result fetched from the result vector, null if the result
915      *         could not be found
916      */
917     /*
918     public static WSSecurityEngineResult fetchActionResult(Vector wsResultVector, int action) {
919         WSSecurityEngineResult wsResult = null;
920 
921         // Find the part of the security result that matches the given action
922 
923         for (int i = 0; i < wsResultVector.size(); i++) {
924             // Check the result of every action whether it matches the given action
925             if (((WSSecurityEngineResult) wsResultVector.get(i)).getAction() == action) {
926                 wsResult = (WSSecurityEngineResult) wsResultVector.get(i);
927             }
928         }
929 
930         return wsResult;
931     }
932      */
933 
934     static public int decodeAction(String action, Vector actions)
935             throws WSSecurityException {
936 
937         int doAction = 0;
938 
939         if (action == null) {
940             return doAction;
941         }
942         String single[] = StringUtil.split(action, ' ');
943         for (int i = 0; i < single.length; i++) {
944             if (single[i].equals(WSHandlerConstants.NO_SECURITY)) {
945                 doAction = WSConstants.NO_SECURITY;
946                 return doAction;
947             } else if (single[i].equals(WSHandlerConstants.USERNAME_TOKEN)) {
948                 doAction |= WSConstants.UT;
949                 actions.add(new Integer(WSConstants.UT));
950             } else if (single[i].equals(WSHandlerConstants.SIGNATURE)) {
951                 doAction |= WSConstants.SIGN;
952                 actions.add(new Integer(WSConstants.SIGN));
953             } else if (single[i].equals(WSHandlerConstants.ENCRYPT)) {
954                 doAction |= WSConstants.ENCR;
955                 actions.add(new Integer(WSConstants.ENCR));
956             } else if (single[i].equals(WSHandlerConstants.SAML_TOKEN_UNSIGNED)) {
957                 doAction |= WSConstants.ST_UNSIGNED;
958                 actions.add(new Integer(WSConstants.ST_UNSIGNED));
959             } else if (single[i].equals(WSHandlerConstants.SAML_TOKEN_SIGNED)) {
960                 doAction |= WSConstants.ST_SIGNED;
961                 actions.add(new Integer(WSConstants.ST_SIGNED));
962             } else if (single[i].equals(WSHandlerConstants.TIMESTAMP)) {
963                 doAction |= WSConstants.TS;
964                 actions.add(new Integer(WSConstants.TS));
965             } else if (single[i].equals(WSHandlerConstants.NO_SERIALIZATION)) {
966                 doAction |= WSConstants.NO_SERIALIZE;
967                 actions.add(new Integer(WSConstants.NO_SERIALIZE));
968             } else if (single[i].equals(WSHandlerConstants.SIGN_WITH_UT_KEY)) {
969                 doAction |= WSConstants.UT_SIGN;
970                 actions.add(new Integer(WSConstants.UT_SIGN));
971             } else {
972                 throw new WSSecurityException("WSDoAllSender: Unknown action defined" + single[i]);
973             }
974         }
975         return doAction;
976     }
977 }