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.getAttributeNS(null, "ID")))
414 || (se.hasAttribute("AssertionID")
415 && value.equals(se.getAttributeNS(null, "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).getAttributeNodeNS(null, "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 String soapNamespace = WSSecurityUtil.getSOAPNamespace(doc.getDocumentElement());
725 Element header =
726 getDirectChildElement(
727 doc.getDocumentElement(),
728 WSConstants.ELEM_HEADER,
729 soapNamespace
730 );
731 if (header == null) {
732 if (doCreate) {
733 header = createElementInSameNamespace(envelope, WSConstants.ELEM_HEADER);
734 header = prependChildElement(envelope, header);
735 } else {
736 return null;
737 }
738 }
739
740 String actorLocal = WSConstants.ATTR_ACTOR;
741 if (WSConstants.URI_SOAP12_ENV.equals(soapNamespace)) {
742 actorLocal = WSConstants.ATTR_ROLE;
743 }
744
745
746
747
748 Element foundSecurityHeader = null;
749 for (
750 Node currentChild = header.getFirstChild();
751 currentChild != null;
752 currentChild = currentChild.getNextSibling()
753 ) {
754 if (Node.ELEMENT_NODE == currentChild.getNodeType()
755 && WSConstants.WSSE_LN.equals(currentChild.getLocalName())
756 && WSConstants.WSSE_NS.equals(currentChild.getNamespaceURI())) {
757
758 Element elem = (Element)currentChild;
759 Attr attr = elem.getAttributeNodeNS(soapNamespace, actorLocal);
760 String hActor = (attr != null) ? attr.getValue() : null;
761
762 if (WSSecurityUtil.isActorEqual(actor, hActor)) {
763 if (foundSecurityHeader != null) {
764 if (log.isDebugEnabled()) {
765 log.debug(
766 "Two or more security headers have the same actor name: " + actor
767 );
768 }
769 throw new WSSecurityException(WSSecurityException.INVALID_SECURITY);
770 }
771 foundSecurityHeader = elem;
772 }
773 }
774 }
775 if (foundSecurityHeader != null) {
776 return foundSecurityHeader;
777 } else if (doCreate) {
778 foundSecurityHeader = doc.createElementNS(WSConstants.WSSE_NS, "wsse:Security");
779 foundSecurityHeader.setAttributeNS(WSConstants.XMLNS_NS, "xmlns:wsse", WSConstants.WSSE_NS);
780 return prependChildElement(header, foundSecurityHeader);
781 }
782 return null;
783 }
784
785
786
787
788
789
790
791
792 public static Text createBase64EncodedTextNode(Document doc, byte data[]) {
793 return doc.createTextNode(Base64.encode(data));
794 }
795
796 public static SOAPConstants getSOAPConstants(Element startElement) {
797 Document doc = startElement.getOwnerDocument();
798 String ns = doc.getDocumentElement().getNamespaceURI();
799 if (WSConstants.URI_SOAP12_ENV.equals(ns)) {
800 return new SOAP12Constants();
801 }
802 return new SOAP11Constants();
803 }
804
805 public static String getSOAPNamespace(Element startElement) {
806 return getSOAPConstants(startElement).getEnvelopeURI();
807 }
808
809
810
811
812
813 public static SecretKey prepareSecretKey(String symEncAlgo, byte[] rawKey) {
814
815 int size = 0;
816 try {
817 size = JCEMapper.getKeyLengthFromURI(symEncAlgo) / 8;
818 } catch (Exception e) {
819
820 if (log.isDebugEnabled()) {
821 log.debug(e.getMessage());
822 }
823 }
824 String keyAlgorithm = JCEMapper.getJCEKeyAlgorithmFromURI(symEncAlgo);
825 SecretKeySpec keySpec;
826 if (size > 0) {
827 keySpec =
828 new SecretKeySpec(
829 rawKey, 0, ((rawKey.length > size) ? size : rawKey.length), keyAlgorithm
830 );
831 } else {
832 keySpec = new SecretKeySpec(rawKey, keyAlgorithm);
833 }
834 return (SecretKey)keySpec;
835 }
836
837
838
839
840
841
842 public static Cipher getCipherInstance(String cipherAlgo)
843 throws WSSecurityException {
844 try {
845 String keyAlgorithm = JCEMapper.translateURItoJCEID(cipherAlgo);
846 return Cipher.getInstance(keyAlgorithm);
847 } catch (NoSuchPaddingException ex) {
848 throw new WSSecurityException(
849 WSSecurityException.UNSUPPORTED_ALGORITHM, "unsupportedKeyTransp",
850 new Object[] { "No such padding: " + cipherAlgo }, ex
851 );
852 } catch (NoSuchAlgorithmException ex) {
853
854
855 if (WSConstants.KEYTRANSPORT_RSAOEP.equals(cipherAlgo)) {
856 try {
857 return Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
858 } catch (Exception e) {
859 throw new WSSecurityException(
860 WSSecurityException.UNSUPPORTED_ALGORITHM, "unsupportedKeyTransp",
861 new Object[] { "No such algorithm: " + cipherAlgo }, e
862 );
863 }
864 } else {
865 throw new WSSecurityException(
866 WSSecurityException.UNSUPPORTED_ALGORITHM, "unsupportedKeyTransp",
867 new Object[] { "No such algorithm: " + cipherAlgo }, ex
868 );
869 }
870 }
871 }
872
873
874
875
876
877
878
879
880
881
882 public static WSSecurityEngineResult fetchActionResult(
883 List<WSSecurityEngineResult> resultList,
884 int action
885 ) {
886 WSSecurityEngineResult returnResult = null;
887
888 for (WSSecurityEngineResult result : resultList) {
889
890
891
892 int resultAction =
893 ((java.lang.Integer)result.get(WSSecurityEngineResult.TAG_ACTION)).intValue();
894 if (resultAction == action) {
895 returnResult = result;
896 }
897 }
898
899 return returnResult;
900 }
901
902
903
904
905
906
907
908
909
910
911
912 public static List<WSSecurityEngineResult> fetchAllActionResults(
913 List<WSSecurityEngineResult> resultList,
914 int action,
915 List<WSSecurityEngineResult> actionResultList
916 ) {
917 for (WSSecurityEngineResult result : resultList) {
918
919
920
921 int resultAction =
922 ((java.lang.Integer)result.get(WSSecurityEngineResult.TAG_ACTION)).intValue();
923 if (resultAction == action) {
924 actionResultList.add(result);
925 }
926 }
927 return actionResultList;
928 }
929
930 public static int decodeAction(
931 String action,
932 List<Integer> actions
933 ) throws WSSecurityException {
934
935 int doAction = 0;
936 if (action == null) {
937 return doAction;
938 }
939 String single[] = StringUtil.split(action, ' ');
940 for (int i = 0; i < single.length; i++) {
941 if (single[i].equals(WSHandlerConstants.NO_SECURITY)) {
942 doAction = WSConstants.NO_SECURITY;
943 return doAction;
944 } else if (single[i].equals(WSHandlerConstants.USERNAME_TOKEN)) {
945 doAction |= WSConstants.UT;
946 actions.add(Integer.valueOf(WSConstants.UT));
947 } else if (single[i].equals(WSHandlerConstants.USERNAME_TOKEN_NO_PASSWORD)) {
948 doAction |= WSConstants.UT_NOPASSWORD;
949 actions.add(Integer.valueOf(WSConstants.UT_NOPASSWORD));
950 } else if (single[i].equals(WSHandlerConstants.SIGNATURE)) {
951 doAction |= WSConstants.SIGN;
952 actions.add(Integer.valueOf(WSConstants.SIGN));
953 } else if (single[i].equals(WSHandlerConstants.ENCRYPT)) {
954 doAction |= WSConstants.ENCR;
955 actions.add(Integer.valueOf(WSConstants.ENCR));
956 } else if (single[i].equals(WSHandlerConstants.SAML_TOKEN_UNSIGNED)) {
957 doAction |= WSConstants.ST_UNSIGNED;
958 actions.add(Integer.valueOf(WSConstants.ST_UNSIGNED));
959 } else if (single[i].equals(WSHandlerConstants.SAML_TOKEN_SIGNED)) {
960 doAction |= WSConstants.ST_SIGNED;
961 actions.add(Integer.valueOf(WSConstants.ST_SIGNED));
962 } else if (single[i].equals(WSHandlerConstants.TIMESTAMP)) {
963 doAction |= WSConstants.TS;
964 actions.add(Integer.valueOf(WSConstants.TS));
965 } else if (single[i].equals(WSHandlerConstants.SIGN_WITH_UT_KEY)) {
966 doAction |= WSConstants.UT_SIGN;
967 actions.add(Integer.valueOf(WSConstants.UT_SIGN));
968 } else if (single[i].equals(WSHandlerConstants.ENABLE_SIGNATURE_CONFIRMATION)) {
969 doAction |= WSConstants.SC;
970 actions.add(Integer.valueOf(WSConstants.SC));
971 } else {
972 throw new WSSecurityException(
973 "Unknown action defined: " + single[i]
974 );
975 }
976 }
977 return doAction;
978 }
979
980
981
982
983
984
985
986
987
988
989 public static int decodeAction(
990 String action,
991 List<Integer> actions,
992 WSSConfig wssConfig
993 ) throws WSSecurityException {
994
995 int doAction = 0;
996 if (action == null) {
997 return doAction;
998 }
999 String single[] = StringUtil.split(action, ' ');
1000 for (int i = 0; i < single.length; i++) {
1001 if (single[i].equals(WSHandlerConstants.NO_SECURITY)) {
1002 doAction = WSConstants.NO_SECURITY;
1003 return doAction;
1004 } else if (single[i].equals(WSHandlerConstants.USERNAME_TOKEN)) {
1005 doAction |= WSConstants.UT;
1006 actions.add(Integer.valueOf(WSConstants.UT));
1007 } else if (single[i].equals(WSHandlerConstants.SIGNATURE)) {
1008 doAction |= WSConstants.SIGN;
1009 actions.add(Integer.valueOf(WSConstants.SIGN));
1010 } else if (single[i].equals(WSHandlerConstants.ENCRYPT)) {
1011 doAction |= WSConstants.ENCR;
1012 actions.add(Integer.valueOf(WSConstants.ENCR));
1013 } else if (single[i].equals(WSHandlerConstants.SAML_TOKEN_UNSIGNED)) {
1014 doAction |= WSConstants.ST_UNSIGNED;
1015 actions.add(Integer.valueOf(WSConstants.ST_UNSIGNED));
1016 } else if (single[i].equals(WSHandlerConstants.SAML_TOKEN_SIGNED)) {
1017 doAction |= WSConstants.ST_SIGNED;
1018 actions.add(Integer.valueOf(WSConstants.ST_SIGNED));
1019 } else if (single[i].equals(WSHandlerConstants.TIMESTAMP)) {
1020 doAction |= WSConstants.TS;
1021 actions.add(Integer.valueOf(WSConstants.TS));
1022 } else if (single[i].equals(WSHandlerConstants.SIGN_WITH_UT_KEY)) {
1023 doAction |= WSConstants.UT_SIGN;
1024 actions.add(Integer.valueOf(WSConstants.UT_SIGN));
1025 } else if (single[i].equals(WSHandlerConstants.ENABLE_SIGNATURE_CONFIRMATION)) {
1026 doAction |= WSConstants.SC;
1027 actions.add(Integer.valueOf(WSConstants.SC));
1028 } else {
1029 try {
1030 int parsedAction = Integer.parseInt(single[i]);
1031 if (wssConfig.getAction(parsedAction) == null) {
1032 throw new WSSecurityException(
1033 "Unknown action defined: " + single[i]
1034 );
1035 }
1036 actions.add(Integer.valueOf(parsedAction));
1037 } catch (NumberFormatException ex) {
1038 throw new WSSecurityException(
1039 "Unknown action defined: " + single[i]
1040 );
1041 }
1042 }
1043 }
1044 return doAction;
1045 }
1046
1047
1048
1049
1050
1051
1052
1053 public static int getKeyLength(String algorithm) throws WSSecurityException {
1054 if (algorithm.equals(WSConstants.TRIPLE_DES)) {
1055 return 24;
1056 } else if (algorithm.equals(WSConstants.AES_128)) {
1057 return 16;
1058 } else if (algorithm.equals(WSConstants.AES_192)) {
1059 return 24;
1060 } else if (algorithm.equals(WSConstants.AES_256)) {
1061 return 32;
1062 } else if (WSConstants.HMAC_SHA1.equals(algorithm)) {
1063 return 20;
1064 } else if (WSConstants.HMAC_SHA256.equals(algorithm)) {
1065 return 32;
1066 } else if (WSConstants.HMAC_SHA384.equals(algorithm)) {
1067 return 48;
1068 } else if (WSConstants.HMAC_SHA512.equals(algorithm)) {
1069 return 64;
1070 } else if (WSConstants.HMAC_MD5.equals(algorithm)) {
1071 return 16;
1072 } else {
1073 throw new WSSecurityException(
1074 WSSecurityException.UNSUPPORTED_ALGORITHM, null, null, null
1075 );
1076 }
1077 }
1078
1079
1080
1081
1082
1083
1084
1085
1086 public static synchronized byte[] generateNonce(int length) throws WSSecurityException {
1087 try {
1088 if (random == null) {
1089 random = SecureRandom.getInstance("SHA1PRNG");
1090 }
1091 byte[] temp = new byte[length];
1092 random.nextBytes(temp);
1093 return temp;
1094 } catch (Exception ex) {
1095 throw new WSSecurityException(
1096 "Error in generating nonce of length " + length, ex
1097 );
1098 }
1099 }
1100
1101
1102
1103
1104
1105
1106
1107
1108 public static synchronized byte[] generateDigest(byte[] inputBytes) throws WSSecurityException {
1109 try {
1110 if (digest == null) {
1111 digest = MessageDigest.getInstance("SHA-1");
1112 }
1113 return digest.digest(inputBytes);
1114 } catch (Exception e) {
1115 throw new WSSecurityException(
1116 "Error in generating digest", e
1117 );
1118 }
1119 }
1120
1121
1122
1123
1124
1125
1126
1127
1128 @SuppressWarnings("unchecked")
1129 public static void checkAllElementsProtected(
1130 List<WSSecurityEngineResult> results,
1131 int action,
1132 QName[] requiredParts
1133 ) throws WSSecurityException {
1134
1135 if (requiredParts != null) {
1136 for (int i = 0; i < requiredParts.length; i++) {
1137 QName requiredPart = requiredParts[i];
1138
1139 boolean found = false;
1140 for (Iterator<WSSecurityEngineResult> iter = results.iterator();
1141 iter.hasNext() && !found;) {
1142 WSSecurityEngineResult result = iter.next();
1143 int resultAction =
1144 ((java.lang.Integer)result.get(WSSecurityEngineResult.TAG_ACTION)).intValue();
1145 if (resultAction != action) {
1146 continue;
1147 }
1148 List<WSDataRef> refList =
1149 (List<WSDataRef>)result.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
1150 if (refList != null) {
1151 for (WSDataRef dataRef : refList) {
1152 if (dataRef.getName().equals(requiredPart)) {
1153 found = true;
1154 break;
1155 }
1156 }
1157 }
1158 }
1159 if (!found) {
1160 throw new WSSecurityException(
1161 WSSecurityException.FAILED_CHECK,
1162 "requiredElementNotProtected",
1163 new Object[] {requiredPart}
1164 );
1165 }
1166 }
1167 log.debug("All required elements are protected");
1168 }
1169 }
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179 @SuppressWarnings("unchecked")
1180 public static void checkSignsAllElements(
1181 WSSecurityEngineResult resultItem,
1182 String[] requiredIDs
1183 ) throws WSSecurityException {
1184 int resultAction =
1185 ((java.lang.Integer)resultItem.get(WSSecurityEngineResult.TAG_ACTION)).intValue();
1186 if (resultAction != WSConstants.SIGN) {
1187 throw new IllegalArgumentException("Not a SIGN result");
1188 }
1189
1190 List<WSDataRef> signedElemsRefList =
1191 (List<WSDataRef>)resultItem.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
1192 if (signedElemsRefList == null) {
1193 throw new WSSecurityException(
1194 "WSSecurityEngineResult does not contain any references to signed elements"
1195 );
1196 }
1197
1198 log.debug("Checking required elements are in the signature...");
1199 for (int i = 0; i < requiredIDs.length; i++) {
1200 boolean found = false;
1201 for (int j = 0; j < signedElemsRefList.size(); j++) {
1202 WSDataRef dataRef = (WSDataRef)signedElemsRefList.get(j);
1203 String wsuId = dataRef.getWsuId();
1204 if (wsuId.charAt(0) == '#') {
1205 wsuId = wsuId.substring(1);
1206 }
1207 if (wsuId.equals(requiredIDs[i])) {
1208 found = true;
1209 }
1210 }
1211 if (!found) {
1212 throw new WSSecurityException(
1213 WSSecurityException.FAILED_CHECK,
1214 "requiredElementNotSigned",
1215 new Object[] {requiredIDs[i]}
1216 );
1217 }
1218 log.debug("Element with ID " + requiredIDs[i] + " was correctly signed");
1219 }
1220 log.debug("All required elements are signed");
1221 }
1222
1223
1224
1225
1226
1227 public static List<Node>
1228 listChildren(
1229 final Node parent
1230 ) {
1231 final List<Node> ret = new ArrayList<Node>();
1232 if (parent != null) {
1233 Node node = parent.getFirstChild();
1234 while (node != null) {
1235 ret.add(node);
1236 node = node.getNextSibling();
1237 }
1238 }
1239 return ret;
1240 }
1241
1242
1243
1244
1245 public static List<Node>
1246 newNodes(
1247 final List<Node> a,
1248 final List<Node> b
1249 ) {
1250 if (a.size() == 0) {
1251 return b;
1252 }
1253 final List<Node> ret = new ArrayList<Node>();
1254 if (b.size() == 0) {
1255 return ret;
1256 }
1257 for (
1258 final Iterator<Node> bpos = b.iterator();
1259 bpos.hasNext();
1260 ) {
1261 final Node bnode = bpos.next();
1262 final String bns = bnode.getNamespaceURI();
1263 final String bln = bnode.getLocalName();
1264 boolean found = false;
1265 for (
1266 final Iterator<Node> apos = a.iterator();
1267 apos.hasNext() && !found;
1268 ) {
1269 final Node anode = apos.next();
1270 final String ans = anode.getNamespaceURI();
1271 final String aln = anode.getLocalName();
1272 final boolean nsmatch =
1273 ans == null
1274 ? ((bns == null) ? true : false)
1275 : ((bns == null) ? false : ans.equals(bns));
1276 final boolean lnmatch =
1277 aln == null
1278 ? ((bln == null) ? true : false)
1279 : ((bln == null) ? false : aln.equals(bln));
1280 if (nsmatch && lnmatch) {
1281 found = true;
1282 }
1283 }
1284 if (!found) {
1285 ret.add(bnode);
1286 }
1287 }
1288 return ret;
1289 }
1290
1291
1292
1293
1294
1295 public static void storeElementInContext(
1296 DOMCryptoContext context,
1297 String uri,
1298 Element element
1299 ) {
1300 String id = uri;
1301 if (uri.charAt(0) == '#') {
1302 id = id.substring(1);
1303 }
1304
1305 if (element.hasAttributeNS(WSConstants.WSU_NS, "Id")
1306 && id.equals(element.getAttributeNS(WSConstants.WSU_NS, "Id"))) {
1307 context.setIdAttributeNS(element, WSConstants.WSU_NS, "Id");
1308 }
1309 if (element.hasAttributeNS(null, "Id")
1310 && id.equals(element.getAttributeNS(null, "Id"))) {
1311 context.setIdAttributeNS(element, null, "Id");
1312 }
1313 if (element.hasAttributeNS(null, "ID")
1314 && id.equals(element.getAttributeNS(null, "ID"))) {
1315 context.setIdAttributeNS(element, null, "ID");
1316 }
1317 if (element.hasAttributeNS(null, "AssertionID")
1318 && id.equals(element.getAttributeNS(null, "AssertionID"))) {
1319 context.setIdAttributeNS(element, null, "AssertionID");
1320 }
1321 }
1322
1323
1324
1325
1326
1327 public static void storeElementInContext(
1328 DOMCryptoContext context,
1329 Element element
1330 ) {
1331 if (element.hasAttributeNS(WSConstants.WSU_NS, "Id")) {
1332 context.setIdAttributeNS(element, WSConstants.WSU_NS, "Id");
1333 }
1334 if (element.hasAttributeNS(null, "Id")) {
1335 context.setIdAttributeNS(element, null, "Id");
1336 }
1337 if (element.hasAttributeNS(null, "ID")) {
1338 context.setIdAttributeNS(element, null, "ID");
1339 }
1340 if (element.hasAttributeNS(null, "AssertionID")) {
1341 context.setIdAttributeNS(element, null, "AssertionID");
1342 }
1343 }
1344
1345 public static void verifySignedElement(Element elem, Document doc, Element securityHeader)
1346 throws WSSecurityException {
1347 final Element envelope = doc.getDocumentElement();
1348 final Set<String> signatureRefIDs = getSignatureReferenceIDs(securityHeader);
1349 if (!signatureRefIDs.isEmpty()) {
1350 Node cur = elem;
1351 while (!cur.isSameNode(envelope)) {
1352 if (cur.getNodeType() == Node.ELEMENT_NODE) {
1353 if (WSConstants.SIG_LN.equals(cur.getLocalName())
1354 && WSConstants.SIG_NS.equals(cur.getNamespaceURI())) {
1355 throw new WSSecurityException(WSSecurityException.FAILED_CHECK,
1356 "requiredElementNotSigned", new Object[] {elem});
1357 } else if (isLinkedBySignatureRefs((Element)cur, signatureRefIDs)) {
1358 return;
1359 }
1360 }
1361 cur = cur.getParentNode();
1362 }
1363 }
1364 throw new WSSecurityException(
1365 WSSecurityException.FAILED_CHECK, "requiredElementNotSigned", new Object[] {elem});
1366 }
1367
1368 private static boolean isLinkedBySignatureRefs(Element elem, Set<String> allIDs) {
1369
1370 String attributeNS = elem.getAttributeNS(WSConstants.WSU_NS, "Id");
1371 if (!"".equals(attributeNS) && allIDs.contains(attributeNS)) {
1372 return true;
1373 }
1374 attributeNS = elem.getAttributeNS(null, "Id");
1375 return (!"".equals(attributeNS) && allIDs.contains(attributeNS));
1376 }
1377
1378 private static Set<String> getSignatureReferenceIDs(Element wsseHeader) throws WSSecurityException {
1379 final Set<String> refs = new HashSet<String>();
1380 final List<Element> signatures = WSSecurityUtil.getDirectChildElements(wsseHeader, WSConstants.SIG_LN, WSConstants.SIG_NS);
1381 for (Element signature : signatures) {
1382 Element sigInfo = WSSecurityUtil.getDirectChildElement(signature, WSConstants.SIG_INFO_LN, WSConstants.SIG_NS);
1383 List<Element> references = WSSecurityUtil.getDirectChildElements(sigInfo, WSConstants.REF_LN, WSConstants.SIG_NS);
1384 for (Element reference : references) {
1385 String uri = reference.getAttributeNS(null, "URI");
1386 if (!"".equals(uri)) {
1387 boolean added = refs.add(WSSecurityUtil.getIDFromReference(uri));
1388 if (!added) {
1389 log.warn("Duplicated reference uri: " + uri);
1390 }
1391 }
1392 }
1393 }
1394 return refs;
1395 }
1396
1397 }