1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.shared.util;
20
21 import java.io.ByteArrayInputStream;
22 import java.io.ByteArrayOutputStream;
23 import java.io.IOException;
24 import java.io.ObjectInputStream;
25 import java.io.ObjectOutputStream;
26 import java.io.UnsupportedEncodingException;
27 import java.security.AccessController;
28 import java.security.NoSuchAlgorithmException;
29 import java.security.PrivilegedActionException;
30 import java.security.PrivilegedExceptionAction;
31 import java.util.Base64;
32 import java.util.Random;
33 import java.util.logging.Level;
34 import java.util.logging.Logger;
35 import java.util.zip.GZIPInputStream;
36 import java.util.zip.GZIPOutputStream;
37
38 import javax.crypto.Cipher;
39 import javax.crypto.KeyGenerator;
40 import javax.crypto.Mac;
41 import javax.crypto.SecretKey;
42 import javax.crypto.spec.IvParameterSpec;
43 import javax.crypto.spec.SecretKeySpec;
44 import javax.faces.FacesException;
45 import javax.faces.application.ViewExpiredException;
46 import javax.faces.context.ExternalContext;
47 import javax.servlet.ServletContext;
48
49 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
50 import org.apache.myfaces.shared.util.serial.SerialFactory;
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90 public final class StateUtils
91 {
92
93
94 private static final Logger log = Logger.getLogger(StateUtils.class.getName());
95
96 public static final String ZIP_CHARSET = "ISO-8859-1";
97
98 public static final String DEFAULT_ALGORITHM = "DES";
99 public static final String DEFAULT_ALGORITHM_PARAMS = "ECB/PKCS5Padding";
100
101 public static final String INIT_PREFIX = "org.apache.myfaces.";
102
103
104
105
106 @JSFWebConfigParam(name="org.apache.myfaces.USE_ENCRYPTION",since="1.1",
107 defaultValue="true",expectedValues="true,false",group="state")
108 public static final String USE_ENCRYPTION = INIT_PREFIX + "USE_ENCRYPTION";
109
110
111
112
113
114
115
116 @JSFWebConfigParam(name="org.apache.myfaces.SECRET",since="1.1",group="state")
117 public static final String INIT_SECRET = INIT_PREFIX + "SECRET";
118
119
120
121
122 @JSFWebConfigParam(name="org.apache.myfaces.ALGORITHM",since="1.1",
123 defaultValue="DES",group="state",tags="performance")
124 public static final String INIT_ALGORITHM = INIT_PREFIX + "ALGORITHM";
125
126
127
128
129
130 @JSFWebConfigParam(name="org.apache.myfaces.SECRET.CACHE",since="1.1",group="state")
131 public static final String INIT_SECRET_KEY_CACHE = INIT_SECRET + ".CACHE";
132
133
134
135
136 @JSFWebConfigParam(name="org.apache.myfaces.ALGORITHM.IV",since="1.1",group="state")
137 public static final String INIT_ALGORITHM_IV = INIT_ALGORITHM + ".IV";
138
139
140
141
142 @JSFWebConfigParam(name="org.apache.myfaces.ALGORITHM.PARAMETERS",since="1.1",
143 defaultValue="ECB/PKCS5Padding",group="state")
144 public static final String INIT_ALGORITHM_PARAM = INIT_ALGORITHM + ".PARAMETERS";
145
146
147
148
149
150
151 @JSFWebConfigParam(name="org.apache.myfaces.SERIAL_FACTORY", since="1.1",group="state",tags="performance")
152 public static final String SERIAL_FACTORY = INIT_PREFIX + "SERIAL_FACTORY";
153
154
155
156
157 @JSFWebConfigParam(name="org.apache.myfaces.COMPRESS_STATE_IN_CLIENT",since="1.1",defaultValue="false",
158 expectedValues="true,false",group="state",tags="performance")
159 public static final String COMPRESS_STATE_IN_CLIENT = INIT_PREFIX + "COMPRESS_STATE_IN_CLIENT";
160
161 public static final String DEFAULT_MAC_ALGORITHM = "HmacSHA1";
162
163
164
165
166
167 @JSFWebConfigParam(name="org.apache.myfaces.MAC_ALGORITHM",defaultValue="HmacSHA1",
168 group="state",tags="performance")
169 public static final String INIT_MAC_ALGORITHM = "org.apache.myfaces.MAC_ALGORITHM";
170
171
172
173
174
175 @JSFWebConfigParam(name="org.apache.myfaces.MAC_SECRET",group="state")
176 public static final String INIT_MAC_SECRET = "org.apache.myfaces.MAC_SECRET";
177
178
179
180
181
182 @JSFWebConfigParam(name="org.apache.myfaces.MAC_SECRET.CACHE",group="state")
183 public static final String INIT_MAC_SECRET_KEY_CACHE = "org.apache.myfaces.MAC_SECRET.CACHE";
184
185
186 private StateUtils()
187 {
188
189 }
190
191 private static void testConfiguration(ExternalContext ctx)
192 {
193
194 String algorithmParams = ctx.getInitParameter(INIT_ALGORITHM_PARAM);
195
196 if (algorithmParams == null)
197 {
198 algorithmParams = ctx.getInitParameter(INIT_ALGORITHM_PARAM.toLowerCase());
199 }
200 String iv = ctx.getInitParameter(INIT_ALGORITHM_IV);
201
202 if (iv == null)
203 {
204 iv = ctx.getInitParameter(INIT_ALGORITHM_IV.toLowerCase());
205 }
206
207 if (algorithmParams != null && algorithmParams.startsWith("CBC") )
208 {
209 if(iv == null)
210 {
211 throw new FacesException(INIT_ALGORITHM_PARAM +
212 " parameter has been set with CBC mode," +
213 " but no initialization vector has been set " +
214 " with " + INIT_ALGORITHM_IV);
215 }
216 }
217
218 }
219
220 public static boolean enableCompression(ExternalContext ctx)
221 {
222 if(ctx == null)
223 {
224 throw new NullPointerException("ExternalContext ctx");
225 }
226
227 return "true".equals(ctx.getInitParameter(COMPRESS_STATE_IN_CLIENT));
228 }
229
230 public static boolean isSecure(ExternalContext ctx)
231 {
232
233 if(ctx == null)
234 {
235 throw new NullPointerException("ExternalContext ctx");
236 }
237
238 return ! "false".equals(ctx.getInitParameter(USE_ENCRYPTION));
239 }
240
241
242
243
244
245 public static final String construct(Object object, ExternalContext ctx)
246 {
247 byte[] bytes = getAsByteArray(object, ctx);
248 if( enableCompression(ctx) )
249 {
250 bytes = compress(bytes);
251 }
252 if(isSecure(ctx))
253 {
254 bytes = encrypt(bytes, ctx);
255 }
256 bytes = encode(bytes);
257 try
258 {
259 return new String(bytes, ZIP_CHARSET);
260 }
261 catch (UnsupportedEncodingException e)
262 {
263 throw new FacesException(e);
264 }
265 }
266
267
268
269
270
271
272
273
274
275
276 public static final byte[] getAsByteArray(Object object, ExternalContext ctx)
277 {
278 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
279
280
281 SerialFactory serialFactory = (SerialFactory) ctx.getApplicationMap().get(SERIAL_FACTORY);
282
283 if(serialFactory == null)
284 {
285 throw new NullPointerException("serialFactory");
286 }
287
288 try
289 {
290 ObjectOutputStream writer = serialFactory.getObjectOutputStream(outputStream);
291 writer.writeObject(object);
292 byte[] bytes = outputStream.toByteArray();
293 writer.close();
294 outputStream.close();
295 writer = null;
296 outputStream = null;
297 return bytes;
298 }
299 catch (IOException e)
300 {
301 throw new FacesException(e);
302 }
303 }
304
305 public static byte[] encrypt(byte[] insecure, ExternalContext ctx)
306 {
307
308 if (ctx == null)
309 {
310 throw new NullPointerException("ExternalContext ctx");
311 }
312
313 testConfiguration(ctx);
314
315 SecretKey secretKey = (SecretKey) getSecret(ctx);
316 String algorithm = findAlgorithm(ctx);
317 String algorithmParams = findAlgorithmParams(ctx);
318 byte[] iv = findInitializationVector(ctx);
319
320 SecretKey macSecretKey = (SecretKey) getMacSecret(ctx);
321 String macAlgorithm = findMacAlgorithm(ctx);
322
323 try
324 {
325
326 Mac mac = Mac.getInstance(macAlgorithm);
327 mac.init(macSecretKey);
328 Cipher cipher = Cipher.getInstance(algorithm + "/" + algorithmParams);
329 if (iv != null)
330 {
331 IvParameterSpec ivSpec = new IvParameterSpec(iv);
332 cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
333 }
334 else
335 {
336 cipher.init(Cipher.ENCRYPT_MODE, secretKey);
337 }
338 if (log.isLoggable(Level.FINE))
339 {
340 log.fine("encrypting w/ " + algorithm + "/" + algorithmParams);
341 }
342
343
344 int macLenght = mac.getMacLength();
345 byte[] secure = new byte[cipher.getOutputSize(insecure.length)+ macLenght];
346 int secureCount = cipher.doFinal(insecure,0,insecure.length,secure);
347 mac.update(secure, 0, secureCount);
348 mac.doFinal(secure, secureCount);
349
350 return secure;
351 }
352 catch (Exception e)
353 {
354 throw new FacesException(e);
355 }
356 }
357
358 public static final byte[] compress(byte[] bytes)
359 {
360 ByteArrayOutputStream baos = new ByteArrayOutputStream();
361 try
362 {
363 GZIPOutputStream gzip = new GZIPOutputStream(baos);
364 gzip.write(bytes, 0, bytes.length);
365 gzip.finish();
366 byte[] fewerBytes = baos.toByteArray();
367 gzip.close();
368 baos.close();
369 gzip = null;
370 baos = null;
371 return fewerBytes;
372 }
373 catch (IOException e)
374 {
375 throw new FacesException(e);
376 }
377 }
378
379 public static final byte[] encode(byte[] bytes)
380 {
381 return Base64.getEncoder().encode(bytes);
382 }
383
384
385
386
387 public static final Object reconstruct(String string, ExternalContext ctx)
388 {
389 byte[] bytes;
390 try
391 {
392 if(log.isLoggable(Level.FINE))
393 {
394 log.fine("Processing state : " + string);
395 }
396
397 bytes = string.getBytes(ZIP_CHARSET);
398 bytes = decode(bytes);
399 if(isSecure(ctx))
400 {
401 bytes = decrypt(bytes, ctx);
402 }
403 if( enableCompression(ctx) )
404 {
405 bytes = decompress(bytes);
406 }
407 return getAsObject(bytes, ctx);
408 }
409 catch (Throwable e)
410 {
411 if (log.isLoggable(Level.FINE))
412 {
413 log.log(Level.FINE, "View State cannot be reconstructed", e);
414 }
415 return null;
416 }
417 }
418
419 public static final byte[] decode(byte[] bytes)
420 {
421 return Base64.getDecoder().decode(bytes);
422 }
423
424 public static final byte[] decompress(byte[] bytes)
425 {
426 if(bytes == null)
427 {
428 throw new NullPointerException("byte[] bytes");
429 }
430
431 ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
432 ByteArrayOutputStream baos = new ByteArrayOutputStream();
433 byte[] buffer = new byte[bytes.length];
434 int length;
435
436 try
437 {
438 GZIPInputStream gis = new GZIPInputStream(bais);
439 while ((length = gis.read(buffer)) != -1)
440 {
441 baos.write(buffer, 0, length);
442 }
443
444 byte[] moreBytes = baos.toByteArray();
445 baos.close();
446 bais.close();
447 gis.close();
448 baos = null;
449 bais = null;
450 gis = null;
451 return moreBytes;
452 }
453 catch (IOException e)
454 {
455 throw new FacesException(e);
456 }
457 }
458
459 public static byte[] decrypt(byte[] secure, ExternalContext ctx)
460 {
461 if (ctx == null)
462 {
463 throw new NullPointerException("ExternalContext ctx");
464 }
465
466 testConfiguration(ctx);
467
468 SecretKey secretKey = (SecretKey) getSecret(ctx);
469 String algorithm = findAlgorithm(ctx);
470 String algorithmParams = findAlgorithmParams(ctx);
471 byte[] iv = findInitializationVector(ctx);
472
473 SecretKey macSecretKey = (SecretKey) getMacSecret(ctx);
474 String macAlgorithm = findMacAlgorithm(ctx);
475
476 try
477 {
478
479 Mac mac = Mac.getInstance(macAlgorithm);
480 mac.init(macSecretKey);
481 Cipher cipher = Cipher.getInstance(algorithm + "/"
482 + algorithmParams);
483 if (iv != null)
484 {
485 IvParameterSpec ivSpec = new IvParameterSpec(iv);
486 cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
487 }
488 else
489 {
490 cipher.init(Cipher.DECRYPT_MODE, secretKey);
491 }
492 if (log.isLoggable(Level.FINE))
493 {
494 log.fine("decrypting w/ " + algorithm + "/" + algorithmParams);
495 }
496
497
498 int macLenght = mac.getMacLength();
499 mac.update(secure, 0, secure.length-macLenght);
500 byte[] signedDigestHash = mac.doFinal();
501
502 boolean isMacEqual = true;
503 for (int i = 0; i < signedDigestHash.length; i++)
504 {
505 if (signedDigestHash[i] != secure[secure.length-macLenght+i])
506 {
507 isMacEqual = false;
508
509
510
511
512
513
514
515 }
516 }
517 if (!isMacEqual)
518 {
519 throw new ViewExpiredException();
520 }
521
522 return cipher.doFinal(secure, 0, secure.length-macLenght);
523 }
524 catch (Exception e)
525 {
526 throw new FacesException(e);
527 }
528 }
529
530
531
532
533
534
535
536
537
538
539 public static final Object getAsObject(byte[] bytes, ExternalContext ctx)
540 {
541 ByteArrayInputStream input = null;
542
543 try
544 {
545 input = new ByteArrayInputStream(bytes);
546
547
548 SerialFactory serialFactory = (SerialFactory) ctx.getApplicationMap().get(SERIAL_FACTORY);
549
550 if(serialFactory == null)
551 {
552 throw new NullPointerException("serialFactory");
553 }
554
555 ObjectInputStream s = null;
556 Exception pendingException = null;
557 try
558 {
559 s = serialFactory.getObjectInputStream(input);
560 Object object = null;
561 if (System.getSecurityManager() != null)
562 {
563 final ObjectInputStream ois = s;
564 object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>()
565 {
566
567
568 public Object run() throws PrivilegedActionException,
569 IOException, ClassNotFoundException
570 {
571 return ois.readObject();
572 }
573 });
574
575
576
577
578
579
580
581
582 }
583 else
584 {
585 object = s.readObject();
586 }
587 return object;
588 }
589 catch (Exception e)
590 {
591 pendingException = e;
592 throw new FacesException(e);
593 }
594 finally
595 {
596 if (s != null)
597 {
598 try
599 {
600 s.close();
601 }
602 catch (IOException e)
603 {
604
605
606
607
608
609
610
611
612
613
614 if (pendingException == null)
615 {
616 throw new FacesException(e);
617 }
618 }
619 finally
620 {
621 s = null;
622 }
623 }
624 }
625 }
626 finally
627 {
628 if (input != null)
629 {
630 try
631 {
632 input.close();
633 }
634 catch (IOException e)
635 {
636
637
638
639 }
640 finally
641 {
642 input = null;
643 }
644 }
645 }
646 }
647
648
649
650
651
652
653
654 public static void main (String[] args) throws UnsupportedEncodingException
655 {
656 byte[] bytes = encode(args[0].getBytes(ZIP_CHARSET));
657 System.out.println(new String(bytes, ZIP_CHARSET));
658 }
659
660 private static byte[] findInitializationVector(ExternalContext ctx)
661 {
662
663 byte[] iv = null;
664 String ivString = ctx.getInitParameter(INIT_ALGORITHM_IV);
665
666 if(ivString == null)
667 {
668 ivString = ctx.getInitParameter(INIT_ALGORITHM_IV.toLowerCase());
669 }
670
671 if (ivString != null)
672 {
673 iv = decode(ivString.getBytes());
674 }
675
676 return iv;
677 }
678
679 private static String findAlgorithmParams(ExternalContext ctx)
680 {
681
682 String algorithmParams = ctx.getInitParameter(INIT_ALGORITHM_PARAM);
683
684 if (algorithmParams == null)
685 {
686 algorithmParams = ctx.getInitParameter(INIT_ALGORITHM_PARAM.toLowerCase());
687 }
688
689 if (algorithmParams == null)
690 {
691 algorithmParams = DEFAULT_ALGORITHM_PARAMS;
692 }
693
694 if (log.isLoggable(Level.FINE))
695 {
696 log.fine("Using algorithm paramaters " + algorithmParams);
697 }
698
699 return algorithmParams;
700 }
701
702 private static String findAlgorithm(ExternalContext ctx)
703 {
704
705 String algorithm = ctx.getInitParameter(INIT_ALGORITHM);
706
707 if (algorithm == null)
708 {
709 algorithm = ctx.getInitParameter(INIT_ALGORITHM.toLowerCase());
710 }
711
712 return findAlgorithm( algorithm );
713 }
714
715 private static String findAlgorithm(ServletContext ctx)
716 {
717
718 String algorithm = ctx.getInitParameter(INIT_ALGORITHM);
719
720 if (algorithm == null)
721 {
722 algorithm = ctx.getInitParameter(INIT_ALGORITHM.toLowerCase());
723 }
724
725 return findAlgorithm( algorithm );
726 }
727
728 private static String findAlgorithm(String initParam)
729 {
730
731 if (initParam == null)
732 {
733 initParam = DEFAULT_ALGORITHM;
734 }
735
736 if (log.isLoggable(Level.FINE))
737 {
738 log.fine("Using algorithm " + initParam);
739 }
740
741 return initParam;
742
743 }
744
745
746
747
748
749
750
751
752
753
754
755 public static void initSecret(ServletContext ctx)
756 {
757
758 if(ctx == null)
759 {
760 throw new NullPointerException("ServletContext ctx");
761 }
762
763 if (log.isLoggable(Level.FINE))
764 {
765 log.fine("Storing SecretKey @ " + INIT_SECRET_KEY_CACHE);
766 }
767
768
769 String cache = ctx.getInitParameter(INIT_SECRET_KEY_CACHE);
770
771 if(cache == null)
772 {
773 cache = ctx.getInitParameter(INIT_SECRET_KEY_CACHE.toLowerCase());
774 }
775
776 if (!"false".equals(cache))
777 {
778 String algorithm = findAlgorithm(ctx);
779
780 ctx.setAttribute(INIT_SECRET_KEY_CACHE, new SecretKeySpec(
781 findSecret(ctx, algorithm), algorithm));
782 }
783
784 if (log.isLoggable(Level.FINE))
785 {
786 log.fine("Storing SecretKey @ " + INIT_MAC_SECRET_KEY_CACHE);
787 }
788
789 String macCache = ctx.getInitParameter(INIT_MAC_SECRET_KEY_CACHE);
790
791 if(macCache == null)
792 {
793 macCache = ctx.getInitParameter(INIT_MAC_SECRET_KEY_CACHE.toLowerCase());
794 }
795
796 if (!"false".equals(macCache))
797 {
798 String macAlgorithm = findMacAlgorithm(ctx);
799
800 ctx.setAttribute(INIT_MAC_SECRET_KEY_CACHE, new SecretKeySpec(
801 findMacSecret(ctx, macAlgorithm), macAlgorithm));
802 }
803 }
804
805 private static SecretKey getSecret(ExternalContext ctx)
806 {
807 Object secretKey = (SecretKey) ctx.getApplicationMap().get(INIT_SECRET_KEY_CACHE);
808
809 if (secretKey == null)
810 {
811 String cache = ctx.getInitParameter(INIT_SECRET_KEY_CACHE);
812
813 if(cache == null)
814 {
815 cache = ctx.getInitParameter(INIT_SECRET_KEY_CACHE.toLowerCase());
816 }
817
818 if ("false".equals(cache))
819 {
820
821 String secret = ctx.getInitParameter(INIT_SECRET);
822
823 if (secret == null)
824 {
825 secret = ctx.getInitParameter(INIT_SECRET.toLowerCase());
826 }
827
828 if (secret == null)
829 {
830 throw new NullPointerException("Could not find secret using key '" + INIT_SECRET + "'");
831 }
832
833 String algorithm = findAlgorithm(ctx);
834
835 secretKey = new SecretKeySpec(findSecret(ctx, algorithm), algorithm);
836 }
837 else
838 {
839 throw new NullPointerException("Could not find SecretKey in application scope using key '"
840 + INIT_SECRET_KEY_CACHE + "'");
841 }
842 }
843
844 if( ! ( secretKey instanceof SecretKey ) )
845 {
846 throw new ClassCastException("Did not find an instance of SecretKey "
847 + "in application scope using the key '" + INIT_SECRET_KEY_CACHE + "'");
848 }
849
850
851 return (SecretKey) secretKey;
852 }
853
854 private static byte[] findSecret(ExternalContext ctx, String algorithm)
855 {
856 String secret = ctx.getInitParameter(INIT_SECRET);
857
858 if (secret == null)
859 {
860 secret = ctx.getInitParameter(INIT_SECRET.toLowerCase());
861 }
862
863 return findSecret(secret, algorithm);
864 }
865
866 private static byte[] findSecret(ServletContext ctx, String algorithm)
867 {
868 String secret = ctx.getInitParameter(INIT_SECRET);
869
870 if (secret == null)
871 {
872 secret = ctx.getInitParameter(INIT_SECRET.toLowerCase());
873 }
874
875 return findSecret(secret, algorithm);
876 }
877
878 private static byte[] findSecret(String secret, String algorithm)
879 {
880 byte[] bytes = null;
881
882 if(secret == null)
883 {
884 try
885 {
886 KeyGenerator kg = KeyGenerator.getInstance(algorithm);
887 bytes = kg.generateKey().getEncoded();
888
889 if(log.isLoggable(Level.FINE))
890 {
891 log.fine("generated random password of length " + bytes.length);
892 }
893 }
894 catch (NoSuchAlgorithmException e)
895 {
896
897 int length = 8;
898 bytes = new byte[length];
899 new Random().nextBytes(bytes);
900
901 if(log.isLoggable(Level.FINE))
902 {
903 log.fine("generated random password of length " + length);
904 }
905 }
906 }
907 else
908 {
909 bytes = decode(secret.getBytes());
910 }
911
912 return bytes;
913 }
914
915 private static String findMacAlgorithm(ExternalContext ctx)
916 {
917
918 String algorithm = ctx.getInitParameter(INIT_MAC_ALGORITHM);
919
920 if (algorithm == null)
921 {
922 algorithm = ctx.getInitParameter(INIT_MAC_ALGORITHM.toLowerCase());
923 }
924
925 return findMacAlgorithm( algorithm );
926
927 }
928
929 private static String findMacAlgorithm(ServletContext ctx)
930 {
931
932 String algorithm = ctx.getInitParameter(INIT_MAC_ALGORITHM);
933
934 if (algorithm == null)
935 {
936 algorithm = ctx.getInitParameter(INIT_MAC_ALGORITHM.toLowerCase());
937 }
938
939 return findMacAlgorithm( algorithm );
940
941 }
942
943 private static String findMacAlgorithm(String initParam)
944 {
945
946 if (initParam == null)
947 {
948 initParam = DEFAULT_MAC_ALGORITHM;
949 }
950
951 if (log.isLoggable(Level.FINE))
952 {
953 log.fine("Using algorithm " + initParam);
954 }
955
956 return initParam;
957
958 }
959
960 private static SecretKey getMacSecret(ExternalContext ctx)
961 {
962 Object secretKey = (SecretKey) ctx.getApplicationMap().get(INIT_MAC_SECRET_KEY_CACHE);
963
964 if (secretKey == null)
965 {
966 String cache = ctx.getInitParameter(INIT_MAC_SECRET_KEY_CACHE);
967
968 if(cache == null)
969 {
970 cache = ctx.getInitParameter(INIT_MAC_SECRET_KEY_CACHE.toLowerCase());
971 }
972
973 if ("false".equals(cache))
974 {
975
976 String secret = ctx.getInitParameter(INIT_MAC_SECRET);
977
978 if (secret == null)
979 {
980 secret = ctx.getInitParameter(INIT_MAC_SECRET.toLowerCase());
981 }
982
983 if (secret == null)
984 {
985 throw new NullPointerException("Could not find secret using key '" + INIT_MAC_SECRET + "'");
986 }
987
988 String macAlgorithm = findMacAlgorithm(ctx);
989
990 secretKey = new SecretKeySpec(findMacSecret(ctx, macAlgorithm), macAlgorithm);
991 }
992 else
993 {
994 throw new NullPointerException("Could not find SecretKey in application scope using key '"
995 + INIT_MAC_SECRET_KEY_CACHE + "'");
996 }
997 }
998
999 if( ! ( secretKey instanceof SecretKey ) )
1000 {
1001 throw new ClassCastException("Did not find an instance of SecretKey "
1002 + "in application scope using the key '" + INIT_MAC_SECRET_KEY_CACHE + "'");
1003 }
1004
1005
1006 return (SecretKey) secretKey;
1007 }
1008
1009 private static byte[] findMacSecret(ExternalContext ctx, String algorithm)
1010 {
1011 String secret = ctx.getInitParameter(INIT_MAC_SECRET);
1012
1013 if (secret == null)
1014 {
1015 secret = ctx.getInitParameter(INIT_MAC_SECRET.toLowerCase());
1016 }
1017
1018 return findMacSecret(secret, algorithm);
1019 }
1020
1021 private static byte[] findMacSecret(ServletContext ctx, String algorithm)
1022 {
1023 String secret = ctx.getInitParameter(INIT_MAC_SECRET);
1024
1025 if (secret == null)
1026 {
1027 secret = ctx.getInitParameter(INIT_MAC_SECRET.toLowerCase());
1028 }
1029
1030 return findMacSecret(secret, algorithm);
1031 }
1032
1033 private static byte[] findMacSecret(String secret, String algorithm)
1034 {
1035 byte[] bytes = null;
1036
1037 if(secret == null)
1038 {
1039 try
1040 {
1041 KeyGenerator kg = KeyGenerator.getInstance(algorithm);
1042 bytes = kg.generateKey().getEncoded();
1043
1044 if(log.isLoggable(Level.FINE))
1045 {
1046 log.fine("generated random mac password of length " + bytes.length);
1047 }
1048 }
1049 catch (NoSuchAlgorithmException e)
1050 {
1051
1052 int length = 8;
1053 bytes = new byte[length];
1054 new Random().nextBytes(bytes);
1055
1056 if(log.isLoggable(Level.FINE))
1057 {
1058 log.fine("generated random mac password of length " + length);
1059 }
1060 }
1061 }
1062 else
1063 {
1064 bytes = decode(secret.getBytes());
1065 }
1066
1067 return bytes;
1068 }
1069 }