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