1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.ws.security.util;
21
22 import org.apache.ws.security.SOAP11Constants;
23 import org.apache.ws.security.SOAP12Constants;
24 import org.apache.ws.security.SOAPConstants;
25 import org.apache.ws.security.WSConstants;
26 import org.apache.ws.security.WSDataRef;
27 import org.apache.ws.security.WSEncryptionPart;
28 import org.apache.ws.security.WSSecurityEngineResult;
29 import org.apache.ws.security.WSSecurityException;
30 import org.apache.ws.security.WSSConfig;
31 import org.apache.ws.security.handler.WSHandlerConstants;
32 import org.apache.ws.security.message.CallbackLookup;
33 import org.apache.xml.security.algorithms.JCEMapper;
34 import org.w3c.dom.Attr;
35 import org.w3c.dom.Document;
36 import org.w3c.dom.Element;
37 import org.w3c.dom.NamedNodeMap;
38 import org.w3c.dom.Node;
39 import org.w3c.dom.Text;
40
41 import javax.crypto.Cipher;
42 import javax.crypto.NoSuchPaddingException;
43 import javax.crypto.SecretKey;
44 import javax.crypto.spec.SecretKeySpec;
45 import javax.xml.crypto.dom.DOMCryptoContext;
46 import javax.xml.namespace.QName;
47
48 import java.security.MessageDigest;
49 import java.security.NoSuchAlgorithmException;
50 import java.security.SecureRandom;
51 import java.util.ArrayList;
52 import java.util.Collections;
53 import java.util.HashSet;
54 import java.util.Iterator;
55 import java.util.List;
56 import java.util.Set;
57
58
59
60
61
62
63 public final class WSSecurityUtil {
64 private static org.apache.commons.logging.Log log =
65 org.apache.commons.logging.LogFactory.getLog(WSSecurityUtil.class);
66
67
68
69
70
71
72
73 private static SecureRandom random = null;
74
75
76
77
78 private static MessageDigest digest = null;
79
80 private WSSecurityUtil() {
81
82 }
83
84
85
86
87
88
89
90
91
92
93 public static Element getSecurityHeader(Document doc, String actor) throws WSSecurityException {
94 String soapNamespace = WSSecurityUtil.getSOAPNamespace(doc.getDocumentElement());
95 Element soapHeaderElement =
96 getDirectChildElement(
97 doc.getDocumentElement(),
98 WSConstants.ELEM_HEADER,
99 soapNamespace
100 );
101 if (soapHeaderElement == null) {
102 return null;
103 }
104
105 String actorLocal = WSConstants.ATTR_ACTOR;
106 if (WSConstants.URI_SOAP12_ENV.equals(soapNamespace)) {
107 actorLocal = WSConstants.ATTR_ROLE;
108 }
109
110
111
112
113 Element foundSecurityHeader = null;
114 for (
115 Node currentChild = soapHeaderElement.getFirstChild();
116 currentChild != null;
117 currentChild = currentChild.getNextSibling()
118 ) {
119 if (Node.ELEMENT_NODE == currentChild.getNodeType()
120 && WSConstants.WSSE_LN.equals(currentChild.getLocalName())
121 && WSConstants.WSSE_NS.equals(currentChild.getNamespaceURI())) {
122
123 Element elem = (Element)currentChild;
124 Attr attr = elem.getAttributeNodeNS(soapNamespace, actorLocal);
125 String hActor = (attr != null) ? attr.getValue() : null;
126
127 if (WSSecurityUtil.isActorEqual(actor, hActor)) {
128 if (foundSecurityHeader != null) {
129 if (log.isDebugEnabled()) {
130 log.debug(
131 "Two or more security headers have the same actor name: " + actor
132 );
133 }
134 throw new WSSecurityException(WSSecurityException.INVALID_SECURITY);
135 }
136 foundSecurityHeader = elem;
137 }
138 }
139 }
140 return foundSecurityHeader;
141 }
142
143
144
145
146
147
148
149
150
151
152 public static boolean isActorEqual(String actor, String hActor) {
153 if (((hActor == null) || (hActor.length() == 0))
154 && ((actor == null) || (actor.length() == 0))) {
155 return true;
156 }
157
158 if ((hActor != null) && (actor != null) && hActor.equalsIgnoreCase(actor)) {
159 return true;
160 }
161
162 return false;
163 }
164
165
166
167
168
169
170
171
172
173
174 public static Element getDirectChildElement(
175 Node parentNode,
176 String localName,
177 String namespace
178 ) {
179 if (parentNode == null) {
180 return null;
181 }
182 for (
183 Node currentChild = parentNode.getFirstChild();
184 currentChild != null;
185 currentChild = currentChild.getNextSibling()
186 ) {
187 if (Node.ELEMENT_NODE == currentChild.getNodeType()
188 && localName.equals(currentChild.getLocalName())
189 && namespace.equals(currentChild.getNamespaceURI())) {
190 return (Element)currentChild;
191 }
192 }
193 return null;
194 }
195
196
197
198
199
200
201
202
203
204
205 public static List<Element> getDirectChildElements(
206 Node fNode,
207 String localName,
208 String namespace
209 ) {
210 List<Element> children = new ArrayList<Element>();
211 for (
212 Node currentChild = fNode.getFirstChild();
213 currentChild != null;
214 currentChild = currentChild.getNextSibling()
215 ) {
216 if (Node.ELEMENT_NODE == currentChild.getNodeType()
217 && localName.equals(currentChild.getLocalName())
218 && namespace.equals(currentChild.getNamespaceURI())) {
219 children.add((Element)currentChild);
220 }
221 }
222 return children;
223 }
224
225
226
227
228
229
230
231
232
233 public static Element findBodyElement(Document doc) {
234
235
236
237 Element docElement = doc.getDocumentElement();
238 String ns = docElement.getNamespaceURI();
239 return getDirectChildElement(docElement, WSConstants.ELEM_BODY, ns);
240 }
241
242
243
244
245
246
247
248
249
250
251
252 public static List<Element> findElements(
253 WSEncryptionPart part, CallbackLookup callbackLookup, Document doc
254 ) throws WSSecurityException {
255
256 if (part.getElement() != null) {
257 return Collections.singletonList(part.getElement());
258 }
259
260
261 String id = part.getId();
262 if (id != null) {
263 Element foundElement = callbackLookup.getElement(id, null, false);
264 return Collections.singletonList(foundElement);
265 }
266
267 return callbackLookup.getElements(part.getName(), part.getNamespace());
268 }
269
270
271
272
273
274
275
276
277
278
279
280
281 public static Element findElement(Node startNode, String name, String namespace) {
282
283
284
285
286 if (startNode == null) {
287 return null;
288 }
289 Node startParent = startNode.getParentNode();
290 Node processedNode = null;
291
292 while (startNode != null) {
293
294 if (startNode.getNodeType() == Node.ELEMENT_NODE
295 && startNode.getLocalName().equals(name)) {
296 String ns = startNode.getNamespaceURI();
297 if (ns != null && ns.equals(namespace)) {
298 return (Element)startNode;
299 }
300
301 if ((namespace == null || namespace.length() == 0)
302 && (ns == null || ns.length() == 0)) {
303 return (Element)startNode;
304 }
305 }
306 processedNode = startNode;
307 startNode = startNode.getFirstChild();
308
309
310 if (startNode == null) {
311
312 startNode = processedNode.getNextSibling();
313 }
314
315
316 while (startNode == null) {
317 processedNode = processedNode.getParentNode();
318 if (processedNode == startParent) {
319 return null;
320 }
321
322 startNode = processedNode.getNextSibling();
323 }
324 }
325 return null;
326 }
327
328
329
330
331
332
333
334
335
336
337
338
339 public static List<Element> findElements(Node startNode, String name, String namespace) {
340
341
342
343
344 if (startNode == null) {
345 return null;
346 }
347 Node startParent = startNode.getParentNode();
348 Node processedNode = null;
349
350 List<Element> foundNodes = new ArrayList<Element>();
351 while (startNode != null) {
352
353 if (startNode.getNodeType() == Node.ELEMENT_NODE
354 && startNode.getLocalName().equals(name)) {
355 String ns = startNode.getNamespaceURI();
356 if (ns != null && ns.equals(namespace)) {
357 foundNodes.add((Element)startNode);
358 }
359
360 if ((namespace == null || namespace.length() == 0)
361 && (ns == null || ns.length() == 0)) {
362 foundNodes.add((Element)startNode);
363 }
364 }
365 processedNode = startNode;
366 startNode = startNode.getFirstChild();
367
368
369 if (startNode == null) {
370
371 startNode = processedNode.getNextSibling();
372 }
373
374
375 while (startNode == null) {
376 processedNode = processedNode.getParentNode();
377 if (processedNode == startParent) {
378 return foundNodes;
379 }
380
381 startNode = processedNode.getNextSibling();
382 }
383 }
384 return foundNodes;
385 }
386
387
388
389
390
391
392
393
394
395
396 public static Element findSAMLAssertionElementById(Node startNode, String value) {
397 Element foundElement = null;
398
399
400
401
402
403 if (startNode == null) {
404 return null;
405 }
406 Node startParent = startNode.getParentNode();
407 Node processedNode = null;
408
409 while (startNode != null) {
410
411 if (startNode.getNodeType() == Node.ELEMENT_NODE) {
412 Element se = (Element) startNode;
413 if ((se.hasAttribute("ID") && value.equals(se.getAttribute("ID")))
414 || (se.hasAttribute("AssertionID")
415 && value.equals(se.getAttribute("AssertionID")))) {
416 if (foundElement == null) {
417 foundElement = se;
418 } else {
419 log.warn("Multiple elements with the same 'ID' attribute value!");
420 return null;
421 }
422 }
423 }
424
425 processedNode = startNode;
426 startNode = startNode.getFirstChild();
427
428
429 if (startNode == null) {
430
431 startNode = processedNode.getNextSibling();
432 }
433
434
435 while (startNode == null) {
436 processedNode = processedNode.getParentNode();
437 if (processedNode == startParent) {
438 return foundElement;
439 }
440
441 startNode = processedNode.getNextSibling();
442 }
443 }
444 return foundElement;
445 }
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465 public static Element findElementById(
466 Node startNode, String value, boolean checkMultipleElements
467 ) {
468
469
470
471 Node startParent = startNode.getParentNode();
472 Node processedNode = null;
473 Element foundElement = null;
474 String id = getIDFromReference(value);
475
476 while (startNode != null) {
477
478 if (startNode.getNodeType() == Node.ELEMENT_NODE) {
479 Element se = (Element) startNode;
480
481 String attributeNS = se.getAttributeNS(WSConstants.WSU_NS, "Id");
482 if ("".equals(attributeNS) || !id.equals(attributeNS)) {
483 attributeNS = se.getAttributeNS(null, "Id");
484 }
485 if (!"".equals(attributeNS) && id.equals(attributeNS)) {
486 if (!checkMultipleElements) {
487 return se;
488 } else if (foundElement == null) {
489 foundElement = se;
490 } else {
491 log.warn("Multiple elements with the same 'Id' attribute value!");
492 return null;
493 }
494 }
495 }
496
497 processedNode = startNode;
498 startNode = startNode.getFirstChild();
499
500
501 if (startNode == null) {
502
503 startNode = processedNode.getNextSibling();
504 }
505
506
507 while (startNode == null) {
508 processedNode = processedNode.getParentNode();
509 if (processedNode == startParent) {
510 return foundElement;
511 }
512
513 startNode = processedNode.getNextSibling();
514 }
515 }
516 return foundElement;
517 }
518
519
520
521
522
523
524
525
526
527
528
529
530 public static String setNamespace(Element element, String namespace, String prefix) {
531 String pre = getPrefixNS(namespace, element);
532 if (pre != null) {
533 return pre;
534 }
535 element.setAttributeNS(WSConstants.XMLNS_NS, "xmlns:" + prefix, namespace);
536 return prefix;
537 }
538
539
540
541
542 public static String getPrefixNS(String uri, Node e) {
543 while (e != null && (e.getNodeType() == Element.ELEMENT_NODE)) {
544 NamedNodeMap attrs = e.getAttributes();
545 for (int n = 0; n < attrs.getLength(); n++) {
546 Attr a = (Attr) attrs.item(n);
547 String name = a.getName();
548 if (name.startsWith("xmlns:") && a.getNodeValue().equals(uri)) {
549 return name.substring("xmlns:".length());
550 }
551 }
552 e = e.getParentNode();
553 }
554 return null;
555 }
556
557 public static String getNamespace(String prefix, Node e) {
558 while (e != null && (e.getNodeType() == Node.ELEMENT_NODE)) {
559 Attr attr = null;
560 if (prefix == null) {
561 attr = ((Element) e).getAttributeNode("xmlns");
562 } else {
563 attr = ((Element) e).getAttributeNodeNS(WSConstants.XMLNS_NS, prefix);
564 }
565 if (attr != null) {
566 return attr.getValue();
567 }
568 e = e.getParentNode();
569 }
570 return null;
571 }
572
573
574
575
576
577
578
579 public static QName getQNameFromString(String str, Node e) {
580 return getQNameFromString(str, e, false);
581 }
582
583
584
585
586
587
588
589
590 public static QName getFullQNameFromString(String str, Node e) {
591 return getQNameFromString(str, e, true);
592 }
593
594 private static QName getQNameFromString(String str, Node e, boolean defaultNS) {
595 if (str == null || e == null) {
596 return null;
597 }
598 int idx = str.indexOf(':');
599 if (idx > -1) {
600 String prefix = str.substring(0, idx);
601 String ns = getNamespace(prefix, e);
602 if (ns == null) {
603 return null;
604 }
605 return new QName(ns, str.substring(idx + 1));
606 } else {
607 if (defaultNS) {
608 String ns = getNamespace(null, e);
609 if (ns != null) {
610 return new QName(ns, str);
611 }
612 }
613 return new QName("", str);
614 }
615 }
616
617
618
619
620
621 public static String getStringForQName(QName qname, Element e) {
622 String uri = qname.getNamespaceURI();
623 String prefix = getPrefixNS(uri, e);
624 if (prefix == null) {
625 int i = 1;
626 prefix = "ns" + i;
627 while (getNamespace(prefix, e) != null) {
628 i++;
629 prefix = "ns" + i;
630 }
631 e.setAttributeNS(WSConstants.XMLNS_NS, "xmlns:" + prefix, uri);
632 }
633 return prefix + ":" + qname.getLocalPart();
634 }
635
636
637
638
639
640
641
642
643 public static String getIDFromReference(String ref) {
644 String id = ref.trim();
645 if (id.length() == 0) {
646 return null;
647 }
648 if (id.charAt(0) == '#') {
649 id = id.substring(1);
650 }
651 return id;
652 }
653
654
655
656
657
658
659
660
661 private static Element createElementInSameNamespace(Element parent, String localName) {
662 String qName = localName;
663 String prefix = parent.getPrefix();
664 if (prefix != null && prefix.length() > 0) {
665 qName = prefix + ":" + localName;
666 }
667
668 String nsUri = parent.getNamespaceURI();
669 return parent.getOwnerDocument().createElementNS(nsUri, qName);
670 }
671
672
673
674
675
676
677
678
679
680 public static Element prependChildElement(
681 Element parent,
682 Element child
683 ) {
684 Node firstChild = parent.getFirstChild();
685 if (firstChild == null) {
686 return (Element)parent.appendChild(child);
687 } else {
688 return (Element)parent.insertBefore(child, firstChild);
689 }
690 }
691
692
693
694
695
696
697
698
699
700
701 public static Element findWsseSecurityHeaderBlock(
702 Document doc,
703 Element envelope,
704 boolean doCreate
705 ) throws WSSecurityException {
706 return findWsseSecurityHeaderBlock(doc, envelope, null, doCreate);
707 }
708
709
710
711
712
713
714
715
716
717
718 public static Element findWsseSecurityHeaderBlock(
719 Document doc,
720 Element envelope,
721 String actor,
722 boolean doCreate
723 ) throws WSSecurityException {
724 Element wsseSecurity = getSecurityHeader(doc, actor);
725 if (wsseSecurity != null) {
726 return wsseSecurity;
727 } else if (doCreate) {
728 String soapNamespace = WSSecurityUtil.getSOAPNamespace(envelope);
729 Element header =
730 getDirectChildElement(envelope, WSConstants.ELEM_HEADER, soapNamespace);
731 if (header == null) {
732 header = createElementInSameNamespace(envelope, WSConstants.ELEM_HEADER);
733 header = prependChildElement(envelope, header);
734 }
735 wsseSecurity = doc.createElementNS(WSConstants.WSSE_NS, "wsse:Security");
736 wsseSecurity.setAttributeNS(WSConstants.XMLNS_NS, "xmlns:wsse", WSConstants.WSSE_NS);
737 return prependChildElement(header, wsseSecurity);
738 }
739 return null;
740 }
741
742
743
744
745
746
747
748
749 public static Text createBase64EncodedTextNode(Document doc, byte data[]) {
750 return doc.createTextNode(Base64.encode(data));
751 }
752
753 public static SOAPConstants getSOAPConstants(Element startElement) {
754 Document doc = startElement.getOwnerDocument();
755 String ns = doc.getDocumentElement().getNamespaceURI();
756 if (WSConstants.URI_SOAP12_ENV.equals(ns)) {
757 return new SOAP12Constants();
758 }
759 return new SOAP11Constants();
760 }
761
762 public static String getSOAPNamespace(Element startElement) {
763 return getSOAPConstants(startElement).getEnvelopeURI();
764 }
765
766
767
768
769
770 public static SecretKey prepareSecretKey(String symEncAlgo, byte[] rawKey) {
771
772 int size = 0;
773 try {
774 size = JCEMapper.getKeyLengthFromURI(symEncAlgo) / 8;
775 } catch (Exception e) {
776
777 if (log.isDebugEnabled()) {
778 log.debug(e.getMessage());
779 }
780 }
781 String keyAlgorithm = JCEMapper.getJCEKeyAlgorithmFromURI(symEncAlgo);
782 SecretKeySpec keySpec;
783 if (size > 0) {
784 keySpec =
785 new SecretKeySpec(
786 rawKey, 0, ((rawKey.length > size) ? size : rawKey.length), keyAlgorithm
787 );
788 } else {
789 keySpec = new SecretKeySpec(rawKey, keyAlgorithm);
790 }
791 return (SecretKey)keySpec;
792 }
793
794
795
796
797
798
799 public static Cipher getCipherInstance(String cipherAlgo)
800 throws WSSecurityException {
801 try {
802 String keyAlgorithm = JCEMapper.translateURItoJCEID(cipherAlgo);
803 return Cipher.getInstance(keyAlgorithm);
804 } catch (NoSuchPaddingException ex) {
805 throw new WSSecurityException(
806 WSSecurityException.UNSUPPORTED_ALGORITHM, "unsupportedKeyTransp",
807 new Object[] { "No such padding: " + cipherAlgo }, ex
808 );
809 } catch (NoSuchAlgorithmException ex) {
810
811
812 if (WSConstants.KEYTRANSPORT_RSAOEP.equals(cipherAlgo)) {
813 try {
814 return Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
815 } catch (Exception e) {
816 throw new WSSecurityException(
817 WSSecurityException.UNSUPPORTED_ALGORITHM, "unsupportedKeyTransp",
818 new Object[] { "No such algorithm: " + cipherAlgo }, e
819 );
820 }
821 } else {
822 throw new WSSecurityException(
823 WSSecurityException.UNSUPPORTED_ALGORITHM, "unsupportedKeyTransp",
824 new Object[] { "No such algorithm: " + cipherAlgo }, ex
825 );
826 }
827 }
828 }
829
830
831
832
833
834
835
836
837
838
839 public static WSSecurityEngineResult fetchActionResult(
840 List<WSSecurityEngineResult> resultList,
841 int action
842 ) {
843 WSSecurityEngineResult returnResult = null;
844
845 for (WSSecurityEngineResult result : resultList) {
846
847
848
849 int resultAction =
850 ((java.lang.Integer)result.get(WSSecurityEngineResult.TAG_ACTION)).intValue();
851 if (resultAction == action) {
852 returnResult = result;
853 }
854 }
855
856 return returnResult;
857 }
858
859
860
861
862
863
864
865
866
867
868
869 public static List<WSSecurityEngineResult> fetchAllActionResults(
870 List<WSSecurityEngineResult> resultList,
871 int action,
872 List<WSSecurityEngineResult> actionResultList
873 ) {
874 for (WSSecurityEngineResult result : resultList) {
875
876
877
878 int resultAction =
879 ((java.lang.Integer)result.get(WSSecurityEngineResult.TAG_ACTION)).intValue();
880 if (resultAction == action) {
881 actionResultList.add(result);
882 }
883 }
884 return actionResultList;
885 }
886
887 public static int decodeAction(
888 String action,
889 List<Integer> actions
890 ) throws WSSecurityException {
891
892 int doAction = 0;
893 if (action == null) {
894 return doAction;
895 }
896 String single[] = StringUtil.split(action, ' ');
897 for (int i = 0; i < single.length; i++) {
898 if (single[i].equals(WSHandlerConstants.NO_SECURITY)) {
899 doAction = WSConstants.NO_SECURITY;
900 return doAction;
901 } else if (single[i].equals(WSHandlerConstants.USERNAME_TOKEN)) {
902 doAction |= WSConstants.UT;
903 actions.add(Integer.valueOf(WSConstants.UT));
904 } else if (single[i].equals(WSHandlerConstants.USERNAME_TOKEN_NO_PASSWORD)) {
905 doAction |= WSConstants.UT_NOPASSWORD;
906 actions.add(Integer.valueOf(WSConstants.UT_NOPASSWORD));
907 } else if (single[i].equals(WSHandlerConstants.SIGNATURE)) {
908 doAction |= WSConstants.SIGN;
909 actions.add(Integer.valueOf(WSConstants.SIGN));
910 } else if (single[i].equals(WSHandlerConstants.ENCRYPT)) {
911 doAction |= WSConstants.ENCR;
912 actions.add(Integer.valueOf(WSConstants.ENCR));
913 } else if (single[i].equals(WSHandlerConstants.SAML_TOKEN_UNSIGNED)) {
914 doAction |= WSConstants.ST_UNSIGNED;
915 actions.add(Integer.valueOf(WSConstants.ST_UNSIGNED));
916 } else if (single[i].equals(WSHandlerConstants.SAML_TOKEN_SIGNED)) {
917 doAction |= WSConstants.ST_SIGNED;
918 actions.add(Integer.valueOf(WSConstants.ST_SIGNED));
919 } else if (single[i].equals(WSHandlerConstants.TIMESTAMP)) {
920 doAction |= WSConstants.TS;
921 actions.add(Integer.valueOf(WSConstants.TS));
922 } else if (single[i].equals(WSHandlerConstants.SIGN_WITH_UT_KEY)) {
923 doAction |= WSConstants.UT_SIGN;
924 actions.add(Integer.valueOf(WSConstants.UT_SIGN));
925 } else if (single[i].equals(WSHandlerConstants.ENABLE_SIGNATURE_CONFIRMATION)) {
926 doAction |= WSConstants.SC;
927 actions.add(Integer.valueOf(WSConstants.SC));
928 } else {
929 throw new WSSecurityException(
930 "Unknown action defined: " + single[i]
931 );
932 }
933 }
934 return doAction;
935 }
936
937
938
939
940
941
942
943
944
945
946 public static int decodeAction(
947 String action,
948 List<Integer> actions,
949 WSSConfig wssConfig
950 ) throws WSSecurityException {
951
952 int doAction = 0;
953 if (action == null) {
954 return doAction;
955 }
956 String single[] = StringUtil.split(action, ' ');
957 for (int i = 0; i < single.length; i++) {
958 if (single[i].equals(WSHandlerConstants.NO_SECURITY)) {
959 doAction = WSConstants.NO_SECURITY;
960 return doAction;
961 } else if (single[i].equals(WSHandlerConstants.USERNAME_TOKEN)) {
962 doAction |= WSConstants.UT;
963 actions.add(Integer.valueOf(WSConstants.UT));
964 } else if (single[i].equals(WSHandlerConstants.SIGNATURE)) {
965 doAction |= WSConstants.SIGN;
966 actions.add(Integer.valueOf(WSConstants.SIGN));
967 } else if (single[i].equals(WSHandlerConstants.ENCRYPT)) {
968 doAction |= WSConstants.ENCR;
969 actions.add(Integer.valueOf(WSConstants.ENCR));
970 } else if (single[i].equals(WSHandlerConstants.SAML_TOKEN_UNSIGNED)) {
971 doAction |= WSConstants.ST_UNSIGNED;
972 actions.add(Integer.valueOf(WSConstants.ST_UNSIGNED));
973 } else if (single[i].equals(WSHandlerConstants.SAML_TOKEN_SIGNED)) {
974 doAction |= WSConstants.ST_SIGNED;
975 actions.add(Integer.valueOf(WSConstants.ST_SIGNED));
976 } else if (single[i].equals(WSHandlerConstants.TIMESTAMP)) {
977 doAction |= WSConstants.TS;
978 actions.add(Integer.valueOf(WSConstants.TS));
979 } else if (single[i].equals(WSHandlerConstants.SIGN_WITH_UT_KEY)) {
980 doAction |= WSConstants.UT_SIGN;
981 actions.add(Integer.valueOf(WSConstants.UT_SIGN));
982 } else if (single[i].equals(WSHandlerConstants.ENABLE_SIGNATURE_CONFIRMATION)) {
983 doAction |= WSConstants.SC;
984 actions.add(Integer.valueOf(WSConstants.SC));
985 } else {
986 try {
987 int parsedAction = Integer.parseInt(single[i]);
988 if (wssConfig.getAction(parsedAction) == null) {
989 throw new WSSecurityException(
990 "Unknown action defined: " + single[i]
991 );
992 }
993 actions.add(Integer.valueOf(parsedAction));
994 } catch (NumberFormatException ex) {
995 throw new WSSecurityException(
996 "Unknown action defined: " + single[i]
997 );
998 }
999 }
1000 }
1001 return doAction;
1002 }
1003
1004
1005
1006
1007
1008
1009
1010 public static int getKeyLength(String algorithm) throws WSSecurityException {
1011 if (algorithm.equals(WSConstants.TRIPLE_DES)) {
1012 return 24;
1013 } else if (algorithm.equals(WSConstants.AES_128)) {
1014 return 16;
1015 } else if (algorithm.equals(WSConstants.AES_192)) {
1016 return 24;
1017 } else if (algorithm.equals(WSConstants.AES_256)) {
1018 return 32;
1019 } else if (WSConstants.HMAC_SHA1.equals(algorithm)) {
1020 return 20;
1021 } else if (WSConstants.HMAC_SHA256.equals(algorithm)) {
1022 return 32;
1023 } else if (WSConstants.HMAC_SHA384.equals(algorithm)) {
1024 return 48;
1025 } else if (WSConstants.HMAC_SHA512.equals(algorithm)) {
1026 return 64;
1027 } else if (WSConstants.HMAC_MD5.equals(algorithm)) {
1028 return 16;
1029 } else {
1030 throw new WSSecurityException(
1031 WSSecurityException.UNSUPPORTED_ALGORITHM, null, null, null
1032 );
1033 }
1034 }
1035
1036
1037
1038
1039
1040
1041
1042
1043 public static synchronized byte[] generateNonce(int length) throws WSSecurityException {
1044 try {
1045 if (random == null) {
1046 random = SecureRandom.getInstance("SHA1PRNG");
1047 }
1048 byte[] temp = new byte[length];
1049 random.nextBytes(temp);
1050 return temp;
1051 } catch (Exception ex) {
1052 throw new WSSecurityException(
1053 "Error in generating nonce of length " + length, ex
1054 );
1055 }
1056 }
1057
1058
1059
1060
1061
1062
1063
1064
1065 public static synchronized byte[] generateDigest(byte[] inputBytes) throws WSSecurityException {
1066 try {
1067 if (digest == null) {
1068 digest = MessageDigest.getInstance("SHA-1");
1069 }
1070 return digest.digest(inputBytes);
1071 } catch (Exception e) {
1072 throw new WSSecurityException(
1073 "Error in generating digest", e
1074 );
1075 }
1076 }
1077
1078
1079
1080
1081
1082
1083
1084
1085 @SuppressWarnings("unchecked")
1086 public static void checkAllElementsProtected(
1087 List<WSSecurityEngineResult> results,
1088 int action,
1089 QName[] requiredParts
1090 ) throws WSSecurityException {
1091
1092 if (requiredParts != null) {
1093 for (int i = 0; i < requiredParts.length; i++) {
1094 QName requiredPart = requiredParts[i];
1095
1096 boolean found = false;
1097 for (Iterator<WSSecurityEngineResult> iter = results.iterator();
1098 iter.hasNext() && !found;) {
1099 WSSecurityEngineResult result = iter.next();
1100 int resultAction =
1101 ((java.lang.Integer)result.get(WSSecurityEngineResult.TAG_ACTION)).intValue();
1102 if (resultAction != action) {
1103 continue;
1104 }
1105 List<WSDataRef> refList =
1106 (List<WSDataRef>)result.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
1107 if (refList != null) {
1108 for (WSDataRef dataRef : refList) {
1109 if (dataRef.getName().equals(requiredPart)) {
1110 found = true;
1111 break;
1112 }
1113 }
1114 }
1115 }
1116 if (!found) {
1117 throw new WSSecurityException(
1118 WSSecurityException.FAILED_CHECK,
1119 "requiredElementNotProtected",
1120 new Object[] {requiredPart}
1121 );
1122 }
1123 }
1124 log.debug("All required elements are protected");
1125 }
1126 }
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136 @SuppressWarnings("unchecked")
1137 public static void checkSignsAllElements(
1138 WSSecurityEngineResult resultItem,
1139 String[] requiredIDs
1140 ) throws WSSecurityException {
1141 int resultAction =
1142 ((java.lang.Integer)resultItem.get(WSSecurityEngineResult.TAG_ACTION)).intValue();
1143 if (resultAction != WSConstants.SIGN) {
1144 throw new IllegalArgumentException("Not a SIGN result");
1145 }
1146
1147 List<WSDataRef> signedElemsRefList =
1148 (List<WSDataRef>)resultItem.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
1149 if (signedElemsRefList == null) {
1150 throw new WSSecurityException(
1151 "WSSecurityEngineResult does not contain any references to signed elements"
1152 );
1153 }
1154
1155 log.debug("Checking required elements are in the signature...");
1156 for (int i = 0; i < requiredIDs.length; i++) {
1157 boolean found = false;
1158 for (int j = 0; j < signedElemsRefList.size(); j++) {
1159 WSDataRef dataRef = (WSDataRef)signedElemsRefList.get(j);
1160 String wsuId = dataRef.getWsuId();
1161 if (wsuId.charAt(0) == '#') {
1162 wsuId = wsuId.substring(1);
1163 }
1164 if (wsuId.equals(requiredIDs[i])) {
1165 found = true;
1166 }
1167 }
1168 if (!found) {
1169 throw new WSSecurityException(
1170 WSSecurityException.FAILED_CHECK,
1171 "requiredElementNotSigned",
1172 new Object[] {requiredIDs[i]}
1173 );
1174 }
1175 log.debug("Element with ID " + requiredIDs[i] + " was correctly signed");
1176 }
1177 log.debug("All required elements are signed");
1178 }
1179
1180
1181
1182
1183
1184 public static List<Node>
1185 listChildren(
1186 final Node parent
1187 ) {
1188 final List<Node> ret = new ArrayList<Node>();
1189 if (parent != null) {
1190 Node node = parent.getFirstChild();
1191 while (node != null) {
1192 ret.add(node);
1193 node = node.getNextSibling();
1194 }
1195 }
1196 return ret;
1197 }
1198
1199
1200
1201
1202 public static List<Node>
1203 newNodes(
1204 final List<Node> a,
1205 final List<Node> b
1206 ) {
1207 if (a.size() == 0) {
1208 return b;
1209 }
1210 final List<Node> ret = new ArrayList<Node>();
1211 if (b.size() == 0) {
1212 return ret;
1213 }
1214 for (
1215 final Iterator<Node> bpos = b.iterator();
1216 bpos.hasNext();
1217 ) {
1218 final Node bnode = bpos.next();
1219 final String bns = bnode.getNamespaceURI();
1220 final String bln = bnode.getLocalName();
1221 boolean found = false;
1222 for (
1223 final Iterator<Node> apos = a.iterator();
1224 apos.hasNext() && !found;
1225 ) {
1226 final Node anode = apos.next();
1227 final String ans = anode.getNamespaceURI();
1228 final String aln = anode.getLocalName();
1229 final boolean nsmatch =
1230 ans == null
1231 ? ((bns == null) ? true : false)
1232 : ((bns == null) ? false : ans.equals(bns));
1233 final boolean lnmatch =
1234 aln == null
1235 ? ((bln == null) ? true : false)
1236 : ((bln == null) ? false : aln.equals(bln));
1237 if (nsmatch && lnmatch) {
1238 found = true;
1239 }
1240 }
1241 if (!found) {
1242 ret.add(bnode);
1243 }
1244 }
1245 return ret;
1246 }
1247
1248
1249
1250
1251
1252 public static void storeElementInContext(
1253 DOMCryptoContext context,
1254 String uri,
1255 Element element
1256 ) {
1257 String id = uri;
1258 if (uri.charAt(0) == '#') {
1259 id = id.substring(1);
1260 }
1261
1262 if (element.hasAttributeNS(WSConstants.WSU_NS, "Id")
1263 && id.equals(element.getAttributeNS(WSConstants.WSU_NS, "Id"))) {
1264 context.setIdAttributeNS(element, WSConstants.WSU_NS, "Id");
1265 }
1266 if (element.hasAttributeNS(null, "Id")
1267 && id.equals(element.getAttributeNS(null, "Id"))) {
1268 context.setIdAttributeNS(element, null, "Id");
1269 }
1270 if (element.hasAttributeNS(null, "ID")
1271 && id.equals(element.getAttributeNS(null, "ID"))) {
1272 context.setIdAttributeNS(element, null, "ID");
1273 }
1274 if (element.hasAttributeNS(null, "AssertionID")
1275 && id.equals(element.getAttributeNS(null, "AssertionID"))) {
1276 context.setIdAttributeNS(element, null, "AssertionID");
1277 }
1278 }
1279
1280
1281
1282
1283
1284 public static void storeElementInContext(
1285 DOMCryptoContext context,
1286 Element element
1287 ) {
1288 if (element.hasAttributeNS(WSConstants.WSU_NS, "Id")) {
1289 context.setIdAttributeNS(element, WSConstants.WSU_NS, "Id");
1290 }
1291 if (element.hasAttributeNS(null, "Id")) {
1292 context.setIdAttributeNS(element, null, "Id");
1293 }
1294 if (element.hasAttributeNS(null, "ID")) {
1295 context.setIdAttributeNS(element, null, "ID");
1296 }
1297 if (element.hasAttributeNS(null, "AssertionID")) {
1298 context.setIdAttributeNS(element, null, "AssertionID");
1299 }
1300 }
1301
1302 public static void verifySignedElement(Element elem, Document doc, Element securityHeader)
1303 throws WSSecurityException {
1304 final Element envelope = doc.getDocumentElement();
1305 final Set<String> signatureRefIDs = getSignatureReferenceIDs(securityHeader);
1306 if (!signatureRefIDs.isEmpty()) {
1307 Node cur = elem;
1308 while (!cur.isSameNode(envelope)) {
1309 if (cur.getNodeType() == Node.ELEMENT_NODE) {
1310 if (WSConstants.SIG_LN.equals(cur.getLocalName())
1311 && WSConstants.SIG_NS.equals(cur.getNamespaceURI())) {
1312 throw new WSSecurityException(WSSecurityException.FAILED_CHECK,
1313 "requiredElementNotSigned", new Object[] {elem});
1314 } else if (isLinkedBySignatureRefs((Element)cur, signatureRefIDs)) {
1315 return;
1316 }
1317 }
1318 cur = cur.getParentNode();
1319 }
1320 }
1321 throw new WSSecurityException(
1322 WSSecurityException.FAILED_CHECK, "requiredElementNotSigned", new Object[] {elem});
1323 }
1324
1325 private static boolean isLinkedBySignatureRefs(Element elem, Set<String> allIDs) {
1326
1327 String attributeNS = elem.getAttributeNS(WSConstants.WSU_NS, "Id");
1328 if (!"".equals(attributeNS) && allIDs.contains(attributeNS)) {
1329 return true;
1330 }
1331 attributeNS = elem.getAttributeNS(null, "Id");
1332 return (!"".equals(attributeNS) && allIDs.contains(attributeNS));
1333 }
1334
1335 private static Set<String> getSignatureReferenceIDs(Element wsseHeader) throws WSSecurityException {
1336 final Set<String> refs = new HashSet<String>();
1337 final List<Element> signatures = WSSecurityUtil.getDirectChildElements(wsseHeader, WSConstants.SIG_LN, WSConstants.SIG_NS);
1338 for (Element signature : signatures) {
1339 Element sigInfo = WSSecurityUtil.getDirectChildElement(signature, WSConstants.SIG_INFO_LN, WSConstants.SIG_NS);
1340 List<Element> references = WSSecurityUtil.getDirectChildElements(sigInfo, WSConstants.REF_LN, WSConstants.SIG_NS);
1341 for (Element reference : references) {
1342 String uri = reference.getAttributeNS(null, "URI");
1343 if (!"".equals(uri)) {
1344 boolean added = refs.add(WSSecurityUtil.getIDFromReference(uri));
1345 if (!added) {
1346 log.warn("Duplicated reference uri: " + uri);
1347 }
1348 }
1349 }
1350 }
1351 return refs;
1352 }
1353
1354 }