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