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.message.token;
21
22 import org.apache.ws.security.WSConstants;
23 import org.apache.ws.security.WSPasswordCallback;
24 import org.apache.ws.security.WSSecurityException;
25 import org.apache.ws.security.WSUsernameTokenPrincipal;
26 import org.apache.ws.security.handler.RequestData;
27 import org.apache.ws.security.util.DOM2Writer;
28 import org.apache.ws.security.util.DateUtil;
29 import org.apache.ws.security.util.WSSecurityUtil;
30 import org.apache.ws.security.util.XmlSchemaDateFormat;
31 import org.apache.ws.security.util.Base64;
32 import org.w3c.dom.Document;
33 import org.w3c.dom.Element;
34 import org.w3c.dom.Node;
35 import org.w3c.dom.Text;
36
37 import javax.crypto.Mac;
38 import javax.crypto.spec.SecretKeySpec;
39 import javax.security.auth.callback.Callback;
40 import javax.security.auth.callback.UnsupportedCallbackException;
41 import javax.xml.namespace.QName;
42
43 import java.io.IOException;
44 import java.security.MessageDigest;
45 import java.security.NoSuchAlgorithmException;
46 import java.security.Principal;
47 import java.text.ParseException;
48 import java.text.SimpleDateFormat;
49 import java.util.Arrays;
50 import java.util.Date;
51 import java.util.List;
52 import java.text.DateFormat;
53 import java.util.TimeZone;
54
55
56
57
58
59
60
61
62
63
64 public class UsernameToken {
65 public static final String BASE64_ENCODING = WSConstants.SOAPMESSAGE_NS + "#Base64Binary";
66 public static final String PASSWORD_TYPE = "passwordType";
67 public static final int DEFAULT_ITERATION = 1000;
68 public static final QName TOKEN =
69 new QName(WSConstants.WSSE_NS, WSConstants.USERNAME_TOKEN_LN);
70
71 private static final org.apache.commons.logging.Log LOG =
72 org.apache.commons.logging.LogFactory.getLog(UsernameToken.class);
73 private static final boolean DO_DEBUG = LOG.isDebugEnabled();
74
75 protected Element element = null;
76 protected Element elementUsername = null;
77 protected Element elementPassword = null;
78 protected Element elementNonce = null;
79 protected Element elementCreated = null;
80 protected Element elementSalt = null;
81 protected Element elementIteration = null;
82 protected String passwordType = null;
83 protected boolean hashed = true;
84 private String rawPassword;
85 private boolean passwordsAreEncoded = false;
86 private boolean bspCompliantDerivedKey = true;
87 private Date createdDate;
88
89
90
91
92
93
94
95
96
97 public UsernameToken(Element elem) throws WSSecurityException {
98 this (elem, false, true);
99 }
100
101
102
103
104
105
106
107
108
109
110
111
112 public UsernameToken(
113 Element elem,
114 boolean allowNamespaceQualifiedPasswordTypes,
115 boolean bspCompliant
116 ) throws WSSecurityException {
117 element = elem;
118 QName el = new QName(element.getNamespaceURI(), element.getLocalName());
119 if (!el.equals(TOKEN)) {
120 throw new WSSecurityException(
121 WSSecurityException.INVALID_SECURITY_TOKEN,
122 "badUsernameToken"
123 );
124 }
125 elementUsername =
126 WSSecurityUtil.getDirectChildElement(
127 element, WSConstants.USERNAME_LN, WSConstants.WSSE_NS
128 );
129 elementPassword =
130 WSSecurityUtil.getDirectChildElement(
131 element, WSConstants.PASSWORD_LN, WSConstants.WSSE_NS
132 );
133 elementNonce =
134 WSSecurityUtil.getDirectChildElement(
135 element, WSConstants.NONCE_LN, WSConstants.WSSE_NS
136 );
137 elementCreated =
138 WSSecurityUtil.getDirectChildElement(
139 element, WSConstants.CREATED_LN, WSConstants.WSU_NS
140 );
141 elementSalt =
142 WSSecurityUtil.getDirectChildElement(
143 element, WSConstants.SALT_LN, WSConstants.WSSE11_NS
144 );
145 elementIteration =
146 WSSecurityUtil.getDirectChildElement(
147 element, WSConstants.ITERATION_LN, WSConstants.WSSE11_NS
148 );
149 if (elementUsername == null) {
150 throw new WSSecurityException(
151 WSSecurityException.INVALID_SECURITY_TOKEN,
152 "badUsernameToken"
153 );
154 }
155
156 if (bspCompliant) {
157 checkBSPCompliance();
158 }
159
160 hashed = false;
161 if (elementSalt != null) {
162
163
164
165
166
167 if (elementPassword != null || elementIteration == null) {
168 throw new WSSecurityException(
169 WSSecurityException.INVALID_SECURITY_TOKEN,
170 "badUsernameToken"
171 );
172 }
173 return;
174 }
175
176
177 if (elementIteration != null) {
178 String iter = nodeString(elementIteration);
179 if (iter != null) {
180 int iterInt = Integer.parseInt(iter);
181 if (iterInt < 0 || iterInt > 10000) {
182 throw new WSSecurityException(
183 WSSecurityException.INVALID_SECURITY_TOKEN,
184 "badUsernameToken"
185 );
186 }
187 }
188 }
189
190 if (elementPassword != null) {
191 if (elementPassword.hasAttribute(WSConstants.PASSWORD_TYPE_ATTR)) {
192 passwordType = elementPassword.getAttributeNS(null, WSConstants.PASSWORD_TYPE_ATTR);
193 } else if (elementPassword.hasAttributeNS(
194 WSConstants.WSSE_NS, WSConstants.PASSWORD_TYPE_ATTR)
195 ) {
196 if (allowNamespaceQualifiedPasswordTypes) {
197 passwordType =
198 elementPassword.getAttributeNS(
199 WSConstants.WSSE_NS, WSConstants.PASSWORD_TYPE_ATTR
200 );
201 } else {
202 throw new WSSecurityException(
203 WSSecurityException.INVALID_SECURITY_TOKEN,
204 "badUsernameToken"
205 );
206 }
207 }
208
209 }
210 if (WSConstants.PASSWORD_DIGEST.equals(passwordType)) {
211 hashed = true;
212 if (elementNonce == null || elementCreated == null) {
213 throw new WSSecurityException(
214 WSSecurityException.INVALID_SECURITY_TOKEN,
215 "badUsernameToken"
216 );
217 }
218 }
219
220 if (elementCreated != null) {
221 String createdString = getCreated();
222 if (createdString != null && !"".equals(createdString)) {
223 DateFormat zulu = new XmlSchemaDateFormat();
224 if (bspCompliant) {
225 zulu.setLenient(false);
226 }
227 try {
228 createdDate = zulu.parse(createdString);
229 } catch (ParseException e) {
230 throw new WSSecurityException(
231 WSSecurityException.INVALID_SECURITY, "invalidTimestamp", null, e
232 );
233 }
234 }
235 }
236 }
237
238
239
240
241
242
243
244
245 public UsernameToken(boolean milliseconds, Document doc) {
246 this(milliseconds, doc, WSConstants.PASSWORD_DIGEST);
247 }
248
249
250
251
252
253
254
255
256
257
258
259
260 public UsernameToken(boolean milliseconds, Document doc, String pwType) {
261 element =
262 doc.createElementNS(WSConstants.WSSE_NS, "wsse:" + WSConstants.USERNAME_TOKEN_LN);
263
264 elementUsername =
265 doc.createElementNS(WSConstants.WSSE_NS, "wsse:" + WSConstants.USERNAME_LN);
266 elementUsername.appendChild(doc.createTextNode(""));
267 element.appendChild(elementUsername);
268
269 if (pwType != null) {
270 elementPassword =
271 doc.createElementNS(WSConstants.WSSE_NS, "wsse:" + WSConstants.PASSWORD_LN);
272 elementPassword.appendChild(doc.createTextNode(""));
273 element.appendChild(elementPassword);
274
275 passwordType = pwType;
276 if (passwordType.equals(WSConstants.PASSWORD_DIGEST)) {
277 addNonce(doc);
278 addCreated(milliseconds, doc);
279 } else {
280 hashed = false;
281 }
282 }
283 }
284
285
286
287
288
289 public void addWSSENamespace() {
290 WSSecurityUtil.setNamespace(element, WSConstants.WSSE_NS, WSConstants.WSSE_PREFIX);
291 }
292
293
294
295
296
297 public void addWSUNamespace() {
298 WSSecurityUtil.setNamespace(element, WSConstants.WSU_NS, WSConstants.WSU_PREFIX);
299 }
300
301
302
303
304 public void addNonce(Document doc) {
305 if (elementNonce != null) {
306 return;
307 }
308 byte[] nonceValue = null;
309 try {
310 nonceValue = WSSecurityUtil.generateNonce(16);
311 } catch (WSSecurityException ex) {
312 LOG.debug(ex.getMessage(), ex);
313 return;
314 }
315 elementNonce = doc.createElementNS(WSConstants.WSSE_NS, "wsse:" + WSConstants.NONCE_LN);
316 elementNonce.appendChild(doc.createTextNode(Base64.encode(nonceValue)));
317 elementNonce.setAttributeNS(null, "EncodingType", BASE64_ENCODING);
318 element.appendChild(elementNonce);
319 }
320
321
322
323
324 public void addCreated(boolean milliseconds, Document doc) {
325 if (elementCreated != null) {
326 return;
327 }
328 DateFormat zulu = null;
329 if (milliseconds) {
330 zulu = new XmlSchemaDateFormat();
331 } else {
332 zulu = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
333 zulu.setTimeZone(TimeZone.getTimeZone("UTC"));
334 }
335 elementCreated =
336 doc.createElementNS(
337 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.CREATED_LN
338 );
339 Date currentTime = new Date();
340 elementCreated.appendChild(doc.createTextNode(zulu.format(currentTime)));
341 element.appendChild(elementCreated);
342 }
343
344
345
346
347
348
349
350
351
352
353
354
355
356 public byte[] addSalt(Document doc, byte[] saltValue, boolean mac) {
357 if (saltValue == null) {
358 saltValue = generateSalt(mac);
359 }
360 elementSalt =
361 doc.createElementNS(
362 WSConstants.WSSE11_NS, WSConstants.WSSE11_PREFIX + ":" + WSConstants.SALT_LN
363 );
364 WSSecurityUtil.setNamespace(element, WSConstants.WSSE11_NS, WSConstants.WSSE11_PREFIX);
365 elementSalt.appendChild(doc.createTextNode(Base64.encode(saltValue)));
366 element.appendChild(elementSalt);
367 return saltValue;
368 }
369
370
371
372
373 public void addIteration(Document doc, int iteration) {
374 String text = "" + iteration;
375 elementIteration =
376 doc.createElementNS(
377 WSConstants.WSSE11_NS, WSConstants.WSSE11_PREFIX + ":" + WSConstants.ITERATION_LN
378 );
379 WSSecurityUtil.setNamespace(element, WSConstants.WSSE11_NS, WSConstants.WSSE11_PREFIX);
380 elementIteration.appendChild(doc.createTextNode(text));
381 element.appendChild(elementIteration);
382 }
383
384
385
386
387
388
389 public String getName() {
390 return nodeString(elementUsername);
391 }
392
393
394
395
396
397
398
399 public void setName(String name) {
400 Text node = getFirstNode(elementUsername);
401 node.setData(name);
402 }
403
404
405
406
407
408
409 public String getNonce() {
410 return nodeString(elementNonce);
411 }
412
413
414
415
416
417
418 public String getCreated() {
419 return nodeString(elementCreated);
420 }
421
422
423
424
425
426 public Date getCreatedDate() {
427 return createdDate;
428 }
429
430
431
432
433
434
435
436
437 public String getPassword() {
438 String password = nodeString(elementPassword);
439
440 if (password == null && elementPassword != null) {
441 return "";
442 }
443 return password;
444 }
445
446
447
448
449 public boolean containsPasswordElement() {
450 return elementPassword != null;
451 }
452
453
454
455
456
457
458
459
460 public byte[] getSalt() throws WSSecurityException {
461 String salt = nodeString(elementSalt);
462 if (salt != null) {
463 return Base64.decode(salt);
464 }
465 return null;
466 }
467
468
469
470
471
472
473
474
475 public int getIteration() {
476 String iter = nodeString(elementIteration);
477 if (iter != null) {
478 return Integer.parseInt(iter);
479 }
480 return DEFAULT_ITERATION;
481 }
482
483
484
485
486
487
488
489 public boolean isHashed() {
490 return hashed;
491 }
492
493
494
495
496 public String getPasswordType() {
497 return passwordType;
498 }
499
500
501
502
503
504
505
506
507
508 public void setPassword(String pwd) {
509 if (pwd == null) {
510 if (passwordType != null) {
511 throw new IllegalArgumentException("pwd == null but a password is needed");
512 } else {
513
514 return;
515 }
516 }
517
518 rawPassword = pwd;
519 Text node = getFirstNode(elementPassword);
520 try {
521 if (hashed) {
522 if (passwordsAreEncoded) {
523 node.setData(doPasswordDigest(getNonce(), getCreated(), Base64.decode(pwd)));
524 } else {
525 node.setData(doPasswordDigest(getNonce(), getCreated(), pwd));
526 }
527 } else {
528 node.setData(pwd);
529 }
530 if (passwordType != null) {
531 elementPassword.setAttributeNS(null, "Type", passwordType);
532 }
533 } catch (Exception e) {
534 if (DO_DEBUG) {
535 LOG.debug(e.getMessage(), e);
536 }
537 }
538 }
539
540
541
542
543 public void setRawPassword(RequestData data) throws WSSecurityException {
544 WSPasswordCallback pwCb =
545 new WSPasswordCallback(
546 getName(), getPassword(), getPasswordType(),
547 WSPasswordCallback.USERNAME_TOKEN, data
548 );
549
550 if (data.getCallbackHandler() == null) {
551 LOG.debug("CallbackHandler is null");
552 throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
553 }
554 try {
555 data.getCallbackHandler().handle(new Callback[]{pwCb});
556 } catch (IOException e) {
557 if (LOG.isDebugEnabled()) {
558 LOG.debug(e);
559 }
560 throw new WSSecurityException(
561 WSSecurityException.FAILED_AUTHENTICATION, null, null, e
562 );
563 } catch (UnsupportedCallbackException e) {
564 if (LOG.isDebugEnabled()) {
565 LOG.debug(e);
566 }
567 throw new WSSecurityException(
568 WSSecurityException.FAILED_AUTHENTICATION, null, null, e
569 );
570 }
571 rawPassword = pwCb.getPassword();
572 }
573
574
575
576
577 public void setPasswordsAreEncoded(boolean passwordsAreEncoded) {
578 this.passwordsAreEncoded = passwordsAreEncoded;
579 }
580
581
582
583
584 public boolean getPasswordsAreEncoded() {
585 return passwordsAreEncoded;
586 }
587
588 public static String doPasswordDigest(String nonce, String created, byte[] password) {
589 String passwdDigest = null;
590 try {
591 byte[] b1 = nonce != null ? Base64.decode(nonce) : new byte[0];
592 byte[] b2 = created != null ? created.getBytes("UTF-8") : new byte[0];
593 byte[] b3 = password;
594 byte[] b4 = new byte[b1.length + b2.length + b3.length];
595 int offset = 0;
596 System.arraycopy(b1, 0, b4, offset, b1.length);
597 offset += b1.length;
598
599 System.arraycopy(b2, 0, b4, offset, b2.length);
600 offset += b2.length;
601
602 System.arraycopy(b3, 0, b4, offset, b3.length);
603
604 byte[] digestBytes = WSSecurityUtil.generateDigest(b4);
605 passwdDigest = Base64.encode(digestBytes);
606 } catch (Exception e) {
607 if (DO_DEBUG) {
608 LOG.debug(e.getMessage(), e);
609 }
610 }
611 return passwdDigest;
612 }
613
614 public static String doPasswordDigest(String nonce, String created, String password) {
615 String passwdDigest = null;
616 try {
617 passwdDigest = doPasswordDigest(nonce, created, password.getBytes("UTF-8"));
618 } catch (Exception e) {
619 if (DO_DEBUG) {
620 LOG.debug(e.getMessage(), e);
621 }
622 }
623 return passwdDigest;
624 }
625
626
627
628
629
630
631
632
633 private Text getFirstNode(Element e) {
634 Node node = e.getFirstChild();
635 return (node != null && Node.TEXT_NODE == node.getNodeType()) ? (Text) node : null;
636 }
637
638
639
640
641
642
643
644
645 private String nodeString(Element e) {
646 if (e != null) {
647 Node node = e.getFirstChild();
648 StringBuilder builder = new StringBuilder();
649 boolean found = false;
650 while (node != null) {
651 if (Node.TEXT_NODE == node.getNodeType()) {
652 found = true;
653 builder.append(((Text)node).getData());
654 }
655 node = node.getNextSibling();
656 }
657
658 if (!found) {
659 return null;
660 }
661 return builder.toString();
662 }
663 return null;
664 }
665
666
667
668
669
670
671 public Element getElement() {
672 return element;
673 }
674
675
676
677
678
679
680 public String toString() {
681 return DOM2Writer.nodeToString((Node)element);
682 }
683
684
685
686
687
688
689
690 public String getID() {
691 return element.getAttributeNS(WSConstants.WSU_NS, "Id");
692 }
693
694
695
696
697
698
699
700
701 public void setID(String id) {
702 element.setAttributeNS(WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":Id", id);
703 }
704
705
706
707
708
709
710
711
712
713 public byte[] getSecretKey() {
714 return getSecretKey(WSConstants.WSE_DERIVED_KEY_LEN, WSConstants.LABEL_FOR_DERIVED_KEY);
715 }
716
717
718
719
720
721
722
723
724
725 public byte[] getSecretKey(int keylen) {
726 return getSecretKey(keylen, WSConstants.LABEL_FOR_DERIVED_KEY);
727 }
728
729
730
731
732
733
734
735
736
737 public byte[] getSecretKey(int keylen, String labelString) {
738 byte[] key = null;
739 try {
740 Mac mac = Mac.getInstance("HMACSHA1");
741 byte[] password;
742 if (passwordsAreEncoded) {
743 password = Base64.decode(rawPassword);
744 } else {
745 password = rawPassword.getBytes("UTF-8");
746 }
747 byte[] label = labelString.getBytes("UTF-8");
748 byte[] nonce = Base64.decode(getNonce());
749 byte[] created = getCreated().getBytes("UTF-8");
750 byte[] seed = new byte[label.length + nonce.length + created.length];
751
752 int offset = 0;
753 System.arraycopy(label, 0, seed, offset, label.length);
754 offset += label.length;
755
756 System.arraycopy(nonce, 0, seed, offset, nonce.length);
757 offset += nonce.length;
758
759 System.arraycopy(created, 0, seed, offset, created.length);
760
761 key = P_hash(password, seed, mac, keylen);
762
763 if (LOG.isDebugEnabled()) {
764 LOG.debug("label :" + Base64.encode(label));
765 LOG.debug("nonce :" + Base64.encode(nonce));
766 LOG.debug("created :" + Base64.encode(created));
767 LOG.debug("seed :" + Base64.encode(seed));
768 LOG.debug("Key :" + Base64.encode(key));
769 }
770 } catch (Exception e) {
771 if (DO_DEBUG) {
772 LOG.debug(e.getMessage(), e);
773 }
774 return null;
775 }
776 return key;
777 }
778
779
780
781
782
783
784
785
786
787
788
789
790
791 public static byte[] generateDerivedKey(
792 byte[] password,
793 byte[] salt,
794 int iteration
795 ) throws WSSecurityException {
796 if (iteration == 0) {
797 iteration = DEFAULT_ITERATION;
798 }
799
800 byte[] pwSalt = new byte[salt.length + password.length];
801 System.arraycopy(password, 0, pwSalt, 0, password.length);
802 System.arraycopy(salt, 0, pwSalt, password.length, salt.length);
803
804 MessageDigest sha = null;
805 try {
806 sha = MessageDigest.getInstance("SHA1");
807 } catch (NoSuchAlgorithmException e) {
808 if (DO_DEBUG) {
809 LOG.debug(e.getMessage(), e);
810 }
811 throw new WSSecurityException(
812 WSSecurityException.FAILURE, "noSHA1availabe", null, e
813 );
814 }
815
816
817
818 byte[] k = sha.digest(pwSalt);
819
820
821
822 for (int i = 1; i < iteration; i++) {
823 k = sha.digest(k);
824 }
825 return k;
826 }
827
828
829
830
831
832
833
834
835
836
837
838
839 public static byte[] generateDerivedKey(
840 String password,
841 byte[] salt,
842 int iteration
843 ) throws WSSecurityException {
844 try {
845 return generateDerivedKey(password.getBytes("UTF-8"), salt, iteration);
846 } catch (final java.io.UnsupportedEncodingException e) {
847 if (DO_DEBUG) {
848 LOG.debug(e.getMessage(), e);
849 }
850 throw new WSSecurityException("Unable to convert password to UTF-8", e);
851 }
852 }
853
854
855
856
857
858
859
860
861 public byte[] getDerivedKey() throws WSSecurityException {
862 if (rawPassword == null || !bspCompliantDerivedKey) {
863 LOG.debug("The raw password was null or the Username Token is not BSP compliant");
864 throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
865 }
866 int iteration = getIteration();
867 byte[] salt = getSalt();
868 if (passwordsAreEncoded) {
869 return generateDerivedKey(Base64.decode(rawPassword), salt, iteration);
870 } else {
871 return generateDerivedKey(rawPassword, salt, iteration);
872 }
873 }
874
875
876
877
878
879
880
881
882 public boolean isDerivedKey() throws WSSecurityException {
883 if (elementSalt != null && elementIteration != null) {
884 return true;
885 }
886 return false;
887 }
888
889
890
891
892 public Principal createPrincipal() {
893 WSUsernameTokenPrincipal principal =
894 new WSUsernameTokenPrincipal(getName(), isHashed());
895 principal.setNonce(getNonce());
896 principal.setPassword(getPassword());
897 principal.setCreatedTime(getCreated());
898 return principal;
899 }
900
901
902
903
904
905
906
907
908
909 public boolean verifyCreated(
910 int timeToLive,
911 int futureTimeToLive
912 ) {
913 return DateUtil.verifyCreated(createdDate, timeToLive, futureTimeToLive);
914 }
915
916
917
918
919
920
921
922
923 public static byte[] generateSalt(boolean useForMac) {
924 byte[] saltValue = null;
925 try {
926 saltValue = WSSecurityUtil.generateNonce(16);
927 } catch (WSSecurityException ex) {
928 LOG.debug(ex.getMessage(), ex);
929 return null;
930 }
931 if (useForMac) {
932 saltValue[0] = 0x01;
933 } else {
934 saltValue[0] = 0x02;
935 }
936 return saltValue;
937 }
938
939 @Override
940 public int hashCode() {
941 int result = 17;
942 String username = getName();
943 if (username != null) {
944 result = 31 * result + username.hashCode();
945 }
946 String password = getPassword();
947 if (password != null) {
948 result = 31 * result + password.hashCode();
949 }
950 String passwordType = getPasswordType();
951 if (passwordType != null) {
952 result = 31 * result + passwordType.hashCode();
953 }
954 String nonce = getNonce();
955 if (nonce != null) {
956 result = 31 * result + nonce.hashCode();
957 }
958 String created = getCreated();
959 if (created != null) {
960 result = 31 * result + created.hashCode();
961 }
962 try {
963 byte[] salt = getSalt();
964 if (salt != null) {
965 result = 31 * result + Arrays.hashCode(salt);
966 }
967 } catch (WSSecurityException ex) {
968 if (LOG.isDebugEnabled()) {
969 LOG.debug(ex.getMessage(), ex);
970 }
971 }
972 result = 31 * result + Integer.valueOf(getIteration()).hashCode();
973
974 return result;
975 }
976
977 @Override
978 public boolean equals(Object object) {
979 if (!(object instanceof UsernameToken)) {
980 return false;
981 }
982 UsernameToken usernameToken = (UsernameToken)object;
983 if (!compare(usernameToken.getName(), getName())) {
984 return false;
985 }
986 if (!compare(usernameToken.getPassword(), getPassword())) {
987 return false;
988 }
989 if (!compare(usernameToken.getPasswordType(), getPasswordType())) {
990 return false;
991 }
992 if (!compare(usernameToken.getNonce(), getNonce())) {
993 return false;
994 }
995 if (!compare(usernameToken.getCreated(), getCreated())) {
996 return false;
997 }
998 try {
999 byte[] salt = usernameToken.getSalt();
1000 if (!Arrays.equals(salt, getSalt())) {
1001 return false;
1002 }
1003 } catch (WSSecurityException ex) {
1004 if (LOG.isDebugEnabled()) {
1005 LOG.debug(ex.getMessage(), ex);
1006 }
1007 }
1008 int iteration = usernameToken.getIteration();
1009 if (iteration != getIteration()) {
1010 return false;
1011 }
1012 return true;
1013 }
1014
1015 private boolean compare(String item1, String item2) {
1016 if (item1 == null && item2 != null) {
1017 return false;
1018 } else if (item1 != null && !item1.equals(item2)) {
1019 return false;
1020 }
1021 return true;
1022 }
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034 private static byte[] P_hash(
1035 byte[] secret,
1036 byte[] seed,
1037 Mac mac,
1038 int required
1039 ) throws Exception {
1040 byte[] out = new byte[required];
1041 int offset = 0, tocpy;
1042 byte[] a, tmp;
1043
1044
1045
1046 a = seed;
1047 SecretKeySpec key = new SecretKeySpec(secret, "HMACSHA1");
1048 mac.init(key);
1049 while (required > 0) {
1050 mac.update(a);
1051 a = mac.doFinal();
1052 mac.update(a);
1053 mac.update(seed);
1054 tmp = mac.doFinal();
1055 tocpy = min(required, tmp.length);
1056 System.arraycopy(tmp, 0, out, offset, tocpy);
1057 offset += tocpy;
1058 required -= tocpy;
1059 }
1060 return out;
1061 }
1062
1063
1064
1065
1066
1067
1068
1069
1070 private static int min(int a, int b) {
1071 return (a > b) ? b : a;
1072 }
1073
1074
1075
1076
1077
1078 private void checkBSPCompliance() throws WSSecurityException {
1079 List<Element> passwordElements =
1080 WSSecurityUtil.getDirectChildElements(
1081 element, WSConstants.PASSWORD_LN, WSConstants.WSSE_NS
1082 );
1083
1084 if (passwordElements.size() > 1) {
1085 if (LOG.isDebugEnabled()) {
1086 LOG.debug("The Username Token had more than one password element");
1087 }
1088 throw new WSSecurityException(
1089 WSSecurityException.INVALID_SECURITY_TOKEN, "badUsernameToken"
1090 );
1091 }
1092
1093
1094 if (passwordElements.size() == 1) {
1095 Element passwordChild = passwordElements.get(0);
1096 String type = passwordChild.getAttributeNS(null, WSConstants.PASSWORD_TYPE_ATTR);
1097 if (type == null || "".equals(type)) {
1098 if (LOG.isDebugEnabled()) {
1099 LOG.debug("The Username Token password does not have a Type attribute");
1100 }
1101 throw new WSSecurityException(
1102 WSSecurityException.INVALID_SECURITY_TOKEN, "badUsernameToken"
1103 );
1104 }
1105 }
1106
1107 if (elementSalt == null) {
1108
1109 bspCompliantDerivedKey = false;
1110 }
1111 if (elementIteration == null) {
1112
1113 bspCompliantDerivedKey = false;
1114 } else {
1115 String iter = nodeString(elementIteration);
1116 if (iter == null || Integer.parseInt(iter) < 1000) {
1117 bspCompliantDerivedKey = false;
1118 }
1119 }
1120
1121 List<Element> createdElements =
1122 WSSecurityUtil.getDirectChildElements(
1123 element, WSConstants.CREATED_LN, WSConstants.WSU_NS
1124 );
1125
1126 if (createdElements.size() > 1) {
1127 if (LOG.isDebugEnabled()) {
1128 LOG.debug("The Username Token has more than one created element");
1129 }
1130 throw new WSSecurityException(
1131 WSSecurityException.INVALID_SECURITY_TOKEN, "badUsernameToken"
1132 );
1133 }
1134
1135 List<Element> nonceElements =
1136 WSSecurityUtil.getDirectChildElements(
1137 element, WSConstants.NONCE_LN, WSConstants.WSSE_NS
1138 );
1139
1140 if (nonceElements.size() > 1) {
1141 if (LOG.isDebugEnabled()) {
1142 LOG.debug("The Username Token has more than one nonce element");
1143 }
1144 throw new WSSecurityException(
1145 WSSecurityException.INVALID_SECURITY_TOKEN, "badUsernameToken"
1146 );
1147 }
1148
1149 if (nonceElements.size() == 1) {
1150 Element nonce = nonceElements.get(0);
1151 String encodingType = nonce.getAttributeNS(null, "EncodingType");
1152
1153 if (encodingType == null || "".equals(encodingType)
1154 || !BinarySecurity.BASE64_ENCODING.equals(encodingType)) {
1155 if (LOG.isDebugEnabled()) {
1156 LOG.debug("The Username Token's nonce element has a bad encoding type");
1157 }
1158 throw new WSSecurityException(
1159 WSSecurityException.INVALID_SECURITY_TOKEN,
1160 "badUsernameToken"
1161 );
1162 }
1163 }
1164 }
1165 }