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