Coverage Report - org.apache.myfaces.shared_impl.util.StateUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
StateUtils
0%
0/321
0%
0/146
0
StateUtils$1
0%
0/2
N/A
0
 
 1  
 /*
 2  
  *  Licensed to the Apache Software Foundation (ASF) under one
 3  
  *  or more contributor license agreements.  See the NOTICE file
 4  
  *  distributed with this work for additional information
 5  
  *  regarding copyright ownership.  The ASF licenses this file
 6  
  *  to you under the Apache License, Version 2.0 (the
 7  
  *  "License"); you may not use this file except in compliance
 8  
  *  with the License.  You may obtain a copy of the License at
 9  
  * 
 10  
  *  http://www.apache.org/licenses/LICENSE-2.0
 11  
  * 
 12  
  *  Unless required by applicable law or agreed to in writing,
 13  
  *  software distributed under the License is distributed on an
 14  
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  *  KIND, either express or implied.  See the License for the
 16  
  *  specific language governing permissions and limitations
 17  
  *  under the License.
 18  
  */
 19  
 package org.apache.myfaces.shared_impl.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.zip.GZIPInputStream;
 33  
 import java.util.zip.GZIPOutputStream;
 34  
 
 35  
 import javax.crypto.Cipher;
 36  
 import javax.crypto.KeyGenerator;
 37  
 import javax.crypto.Mac;
 38  
 import javax.crypto.SecretKey;
 39  
 import javax.crypto.spec.IvParameterSpec;
 40  
 import javax.crypto.spec.SecretKeySpec;
 41  
 import javax.faces.FacesException;
 42  
 import javax.faces.application.ViewExpiredException;
 43  
 import javax.faces.context.ExternalContext;
 44  
 import javax.servlet.ServletContext;
 45  
 
 46  
 import org.apache.commons.codec.binary.Base64;
 47  
 import org.apache.commons.logging.Log;
 48  
 import org.apache.commons.logging.LogFactory;
 49  
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
 50  
 import org.apache.myfaces.shared_impl.util.serial.SerialFactory;
 51  
 
 52  
 /**
 53  
  * <p>This Class exposes a handful of methods related to encryption,
 54  
  * compression and serialization.</p>
 55  
  * 
 56  
  * <ul>
 57  
  * <li>ISO-8859-1 is the character set used.</li>
 58  
  * <li>GZIP is used for all compression/decompression.</li>
 59  
  * <li>Base64 is used for all encoding and decoding.</li>
 60  
  * <li>DES is the default encryption algorithm</li>
 61  
  * <li>ECB is the default mode</li>
 62  
  * <li>PKCS5Padding is the default padding</li>
 63  
  * <li>HmacSHA1 is the default MAC algorithm</li>
 64  
  * <li>The default algorithm can be overridden using the
 65  
  * <i>org.apache.myfaces.ALGORITHM</i> parameter</li>
 66  
  * <li>The default mode and padding can be overridden using the
 67  
  * <i>org.apache.myfaces.ALGORITHM.PARAMETERS</i> parameter</li>
 68  
  * <li>This class has not been tested with modes other than ECB and CBC</li>
 69  
  * <li>An initialization vector can be specified via the
 70  
  * <i>org.apache.myfaces.ALGORITHM.IV</i> parameter</li>
 71  
  * <li>The default MAC algorithm can be overridden using the
 72  
  * <i>org.apache.myfaces.MAC_ALGORITHM</i> parameter</li>
 73  
  * </ul>
 74  
  *
 75  
  * <p>The secret is interpretted as base 64 encoded.  In other
 76  
  * words, if your secret is "76543210", you would put "NzY1NDMyMTA=" in
 77  
  * the deployment descriptor.  This is needed so that key values are not
 78  
  * limited to just values composed of printable characters.</p>
 79  
  *
 80  
  * <p>If you are using CBC mode encryption, you <b>must</b> specify an
 81  
  * initialization vector.</p>
 82  
  *
 83  
  * <p>If you are using the AES algorithm and getting a SecurityException
 84  
  * complaining about keysize, you most likely need to get the unlimited
 85  
  * strength jurisdiction policy files from a place like
 86  
  * http://java.sun.com/j2se/1.4.2/download.html .</p>
 87  
  *
 88  
  * @author Dennis C. Byrne
 89  
  * @see org.apache.myfaces.webapp.StartupServletContextListener
 90  
  */
 91  
 public final class StateUtils {
 92  
 
 93  0
     private static final Log log = LogFactory.getLog(StateUtils.class);
 94  
 
 95  
     public static final String ZIP_CHARSET = "ISO-8859-1";
 96  
 
 97  
     public static final String DEFAULT_ALGORITHM = "DES";
 98  
     public static final String DEFAULT_ALGORITHM_PARAMS = "ECB/PKCS5Padding";
 99  
 
 100  
     public static final String INIT_PREFIX = "org.apache.myfaces.";
 101  
     
 102  
     /**
 103  
      * Indicate if the view state is encrypted or not. By default, encryption is enabled.
 104  
      */
 105  
     @JSFWebConfigParam(name="org.apache.myfaces.USE_ENCRYPTION",since="1.1",defaultValue="true",expectedValues="true,false")
 106  
     public static final String USE_ENCRYPTION = INIT_PREFIX + "USE_ENCRYPTION";
 107  
     
 108  
     /**
 109  
      * Defines the secret (Base64 encoded) used to initialize the secret key
 110  
      * for encryption algorithm. See MyFaces wiki/web site documentation 
 111  
      * for instructions on how to configure an application for 
 112  
      * different encryption strengths.
 113  
      */
 114  
     @JSFWebConfigParam(name="org.apache.myfaces.SECRET",since="1.1")
 115  
     public static final String INIT_SECRET = INIT_PREFIX + "SECRET";
 116  
     
 117  
     /**
 118  
      * Indicate the encryption algorithm used for encrypt the view state.
 119  
      */
 120  
     @JSFWebConfigParam(name="org.apache.myfaces.ALGORITHM",since="1.1",defaultValue="DES")
 121  
     public static final String INIT_ALGORITHM = INIT_PREFIX + "ALGORITHM";
 122  
 
 123  
     /**
 124  
      * If is set to "false", the secret key used for encryption algorithm is not cached. This is used
 125  
      * when the returned SecretKey for encryption algorithm is not thread safe. 
 126  
      */
 127  
     @JSFWebConfigParam(name="org.apache.myfaces.SECRET.CACHE",since="1.1")
 128  
     public static final String INIT_SECRET_KEY_CACHE = INIT_SECRET + ".CACHE";
 129  
     
 130  
     /**
 131  
      * Defines the initialization vector (Base64 encoded) used for the encryption algorithm
 132  
      */
 133  
     @JSFWebConfigParam(name="org.apache.myfaces.ALGORITHM.IV",since="1.1")
 134  
     public static final String INIT_ALGORITHM_IV = INIT_ALGORITHM + ".IV";
 135  
     
 136  
     /**
 137  
      * Defines the default mode and padding used for the encryption algorithm
 138  
      */
 139  
     @JSFWebConfigParam(name="org.apache.myfaces.ALGORITHM.PARAMETERS",since="1.1",defaultValue="ECB/PKCS5Padding")
 140  
     public static final String INIT_ALGORITHM_PARAM = INIT_ALGORITHM + ".PARAMETERS";
 141  
     
 142  
     /**
 143  
      * Defines the factory class name using for serialize/deserialize the view state returned 
 144  
      * by state manager into a byte array. The expected class must implement
 145  
      * org.apache.myfaces.shared_impl.util.serial.SerialFactory interface.
 146  
      */
 147  
     @JSFWebConfigParam(name="org.apache.myfaces.SERIAL_FACTORY", since="1.1")
 148  
     public static final String SERIAL_FACTORY = INIT_PREFIX + "SERIAL_FACTORY";
 149  
     
 150  
     /**
 151  
      * Indicate if the view state should be compressed before encrypted(optional) and encoded
 152  
      */
 153  
     @JSFWebConfigParam(name="org.apache.myfaces.COMPRESS_STATE_IN_CLIENT",since="1.1",defaultValue="false",expectedValues="true,false")
 154  
     public static final String COMPRESS_STATE_IN_CLIENT = INIT_PREFIX + "COMPRESS_STATE_IN_CLIENT";
 155  
 
 156  
     public static final String DEFAULT_MAC_ALGORITHM = "HmacSHA1";
 157  
 
 158  
     /**
 159  
      * Indicate the algorithm used to calculate the Message Authentication Code that is
 160  
      * added to the view state.
 161  
      */
 162  
     @JSFWebConfigParam(name="org.apache.myfaces.MAC_ALGORITHM",defaultValue="HmacSHA1")
 163  
     public static final String INIT_MAC_ALGORITHM = "org.apache.myfaces.MAC_ALGORITHM";
 164  
     
 165  
     /**
 166  
      * Define the initialization code that are used to initialize the secret key used
 167  
      * on the Message Authentication Code algorithm
 168  
      */
 169  
     @JSFWebConfigParam(name="org.apache.myfaces.MAC_SECRET")
 170  
     public static final String INIT_MAC_SECRET = "org.apache.myfaces.MAC_SECRET";
 171  
 
 172  
     /**
 173  
      * If is set to "false", the secret key used for MAC algorithm is not cached. This is used
 174  
      * when the returned SecretKey for mac algorithm is not thread safe. 
 175  
      */
 176  
     @JSFWebConfigParam(name="org.apache.myfaces.MAC_SECRET.CACHE")
 177  
     public static final String INIT_MAC_SECRET_KEY_CACHE = "org.apache.myfaces.MAC_SECRET.CACHE";
 178  
     
 179  
     /** Utility class, do not instatiate */
 180  
     private StateUtils()
 181  0
     {
 182  
         //nope
 183  0
     }
 184  
 
 185  
     private static void testConfiguration(ExternalContext ctx){
 186  
 
 187  0
         String algorithmParams = ctx.getInitParameter(INIT_ALGORITHM_PARAM);
 188  
         
 189  0
         if (algorithmParams == null)
 190  
         {
 191  0
             algorithmParams = ctx.getInitParameter(INIT_ALGORITHM_PARAM.toLowerCase());
 192  
         }
 193  0
         String iv = ctx.getInitParameter(INIT_ALGORITHM_IV);
 194  
         
 195  0
         if (iv == null)
 196  
         {
 197  0
             iv = ctx.getInitParameter(INIT_ALGORITHM_IV.toLowerCase());
 198  
         }
 199  
         
 200  0
         if (algorithmParams != null && algorithmParams.startsWith("CBC") )
 201  
         {
 202  0
             if(iv == null)
 203  0
                 throw new FacesException(INIT_ALGORITHM_PARAM +
 204  
                                     " parameter has been set with CBC mode," +
 205  
                                     " but no initialization vector has been set " +
 206  
                                     " with " + INIT_ALGORITHM_IV);
 207  
         }
 208  
 
 209  0
     }
 210  
     
 211  
     public static boolean enableCompression(ExternalContext ctx)
 212  
     {
 213  0
         if(ctx == null)
 214  0
             throw new NullPointerException("ExternalContext ctx");
 215  
     
 216  0
         return "true".equals(ctx.getInitParameter(COMPRESS_STATE_IN_CLIENT));
 217  
     }
 218  
     
 219  
     public static boolean isSecure(ExternalContext ctx)
 220  
     {
 221  
         
 222  0
         if(ctx == null)
 223  0
             throw new NullPointerException("ExternalContext ctx");
 224  
         
 225  0
         return ! "false".equals(ctx.getInitParameter(USE_ENCRYPTION));
 226  
     }
 227  
 
 228  
     /**
 229  
      * This fires during the Render Response phase, saving state.
 230  
      */
 231  
 
 232  
     public static final String construct(Object object, ExternalContext ctx){
 233  0
         byte[] bytes = getAsByteArray(object, ctx);
 234  0
         if( enableCompression(ctx) )
 235  0
                 bytes = compress(bytes);
 236  0
         if(isSecure(ctx))
 237  0
                 bytes = encrypt(bytes, ctx);
 238  0
         bytes = encode(bytes);
 239  
         try
 240  
         {
 241  0
             return new String(bytes, ZIP_CHARSET);
 242  
         }
 243  0
         catch (UnsupportedEncodingException e)
 244  
         {
 245  0
             throw new FacesException(e);
 246  
         }
 247  
     }
 248  
 
 249  
     /**
 250  
      * Performs serialization with the serialization provider created by the 
 251  
      * SerialFactory.  
 252  
      * 
 253  
      * @param object
 254  
      * @param ctx
 255  
      * @return
 256  
      */
 257  
     
 258  
     public static final byte[] getAsByteArray(Object object, ExternalContext ctx)
 259  
     {
 260  0
         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
 261  
         
 262  
         // get the Factory that was instantiated @ startup
 263  0
         SerialFactory serialFactory = (SerialFactory) ctx.getApplicationMap().get(SERIAL_FACTORY);
 264  
         
 265  0
         if(serialFactory == null)
 266  0
             throw new NullPointerException("serialFactory");
 267  
         
 268  
         try
 269  
         {
 270  0
             ObjectOutputStream writer = serialFactory.getObjectOutputStream(outputStream);
 271  0
             writer.writeObject(object);
 272  0
             byte[] bytes = outputStream.toByteArray();
 273  0
             writer.close();
 274  0
             outputStream.close();
 275  0
             writer = null;
 276  0
             outputStream = null;
 277  0
             return bytes;
 278  
         }
 279  0
         catch (IOException e)
 280  
         {
 281  0
             throw new FacesException(e);
 282  
         }
 283  
     }
 284  
 
 285  
     public static byte[] encrypt(byte[] insecure, ExternalContext ctx)
 286  
     {
 287  
 
 288  0
         if (ctx == null)
 289  0
             throw new NullPointerException("ExternalContext ctx");
 290  
 
 291  0
         testConfiguration(ctx);
 292  
         
 293  0
         SecretKey secretKey = (SecretKey) getSecret(ctx);
 294  0
         String algorithm = findAlgorithm(ctx);
 295  0
         String algorithmParams = findAlgorithmParams(ctx);
 296  0
         byte[] iv = findInitializationVector(ctx);
 297  
         
 298  0
         SecretKey macSecretKey = (SecretKey) getMacSecret(ctx);
 299  0
         String macAlgorithm = findMacAlgorithm(ctx);
 300  
                 
 301  
         try
 302  
         {
 303  
             // keep local to avoid threading issue
 304  0
             Mac mac = Mac.getInstance(macAlgorithm);
 305  0
             mac.init(macSecretKey);
 306  0
             Cipher cipher = Cipher.getInstance(algorithm + "/" + algorithmParams);
 307  0
             if (iv != null)
 308  
             {
 309  0
                 IvParameterSpec ivSpec = new IvParameterSpec(iv);
 310  0
                 cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
 311  0
             }
 312  
             else
 313  
             {
 314  0
                 cipher.init(Cipher.ENCRYPT_MODE, secretKey);
 315  
             }
 316  0
             if (log.isDebugEnabled())
 317  
             {
 318  0
                 log.debug("encrypting w/ " + algorithm + "/" + algorithmParams);
 319  
             }
 320  
             
 321  
             //EtM Composition Approach
 322  0
             int macLenght = mac.getMacLength();
 323  0
             byte[] secure = new byte[cipher.getOutputSize(insecure.length)+ macLenght];
 324  0
             int secureCount = cipher.doFinal(insecure,0,insecure.length,secure);
 325  0
             mac.update(secure, 0, secureCount);
 326  0
             mac.doFinal(secure, secureCount);
 327  
                         
 328  0
             return secure;
 329  
         }
 330  0
         catch (Exception e)
 331  
         {
 332  0
             throw new FacesException(e);
 333  
         }
 334  
     }
 335  
 
 336  
     public static final byte[] compress(byte[] bytes)
 337  
     {
 338  0
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
 339  
         try
 340  
         {
 341  0
             GZIPOutputStream gzip = new GZIPOutputStream(baos);
 342  0
             gzip.write(bytes, 0, bytes.length);
 343  0
             gzip.finish();
 344  0
             byte[] fewerBytes = baos.toByteArray();
 345  0
             gzip.close();
 346  0
             baos.close();
 347  0
             gzip = null;
 348  0
             baos = null;
 349  0
             return fewerBytes;
 350  
         }
 351  0
         catch (IOException e)
 352  
         {
 353  0
             throw new FacesException(e);
 354  
         }
 355  
     }
 356  
 
 357  
     public static final byte[] encode(byte[] bytes)
 358  
     {
 359  0
           return new Base64().encode(bytes);
 360  
     }
 361  
 
 362  
     /**
 363  
      * This fires during the Restore View phase, restoring state.
 364  
      */
 365  
     public static final Object reconstruct(String string, ExternalContext ctx)
 366  
     {
 367  
         byte[] bytes;
 368  
         try
 369  
         {
 370  0
             if(log.isDebugEnabled())
 371  0
                 log.debug("Processing state : "+string);
 372  
 
 373  0
             bytes = string.getBytes(ZIP_CHARSET);
 374  0
             bytes = decode(bytes);
 375  0
             if(isSecure(ctx))
 376  0
                 bytes = decrypt(bytes, ctx);
 377  0
             if( enableCompression(ctx) )
 378  0
                 bytes = decompress(bytes);
 379  0
             return getAsObject(bytes, ctx);
 380  
         }
 381  0
         catch (Throwable e)
 382  
         {
 383  0
             if (log.isErrorEnabled())
 384  
             {
 385  0
                 log.error("View State cannot be reconstructed", e);
 386  
             }
 387  0
             return null;
 388  
         }
 389  
     }
 390  
 
 391  
     public static final byte[] decode(byte[] bytes)
 392  
     {
 393  0
           return new Base64().decode(bytes);
 394  
     }
 395  
 
 396  
     public static final byte[] decompress(byte[] bytes)
 397  
     {
 398  0
         if(bytes == null)
 399  0
             throw new NullPointerException("byte[] bytes");
 400  
         
 401  0
         ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
 402  0
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
 403  0
         byte[] buffer = new byte[bytes.length];
 404  
         int length;
 405  
 
 406  
         try
 407  
         {
 408  0
             GZIPInputStream gis = new GZIPInputStream(bais);
 409  0
             while ((length = gis.read(buffer)) != -1)
 410  
             {
 411  0
                 baos.write(buffer, 0, length);
 412  
             }
 413  
 
 414  0
             byte[] moreBytes = baos.toByteArray();
 415  0
             baos.close();
 416  0
             bais.close();
 417  0
             gis.close();
 418  0
             baos = null;
 419  0
             bais = null;
 420  0
             gis = null;
 421  0
             return moreBytes;
 422  
         }
 423  0
         catch (IOException e)
 424  
         {
 425  0
             throw new FacesException(e);
 426  
         }
 427  
     }
 428  
     
 429  
     public static byte[] decrypt(byte[] secure, ExternalContext ctx)
 430  
     {
 431  0
         if (ctx == null)
 432  0
             throw new NullPointerException("ExternalContext ctx");
 433  
 
 434  0
         testConfiguration(ctx);
 435  
                 
 436  0
         SecretKey secretKey = (SecretKey) getSecret(ctx);
 437  0
         String algorithm = findAlgorithm(ctx);
 438  0
         String algorithmParams = findAlgorithmParams(ctx);
 439  0
         byte[] iv = findInitializationVector(ctx);
 440  
         
 441  0
         SecretKey macSecretKey = (SecretKey) getMacSecret(ctx);
 442  0
         String macAlgorithm = findMacAlgorithm(ctx);
 443  
 
 444  
         try
 445  
         {
 446  
             // keep local to avoid threading issue
 447  0
             Mac mac = Mac.getInstance(macAlgorithm);
 448  0
             mac.init(macSecretKey);
 449  0
             Cipher cipher = Cipher.getInstance(algorithm + "/"
 450  
                     + algorithmParams);
 451  0
             if (iv != null)
 452  
             {
 453  0
                 IvParameterSpec ivSpec = new IvParameterSpec(iv);
 454  0
                 cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
 455  0
             }
 456  
             else
 457  
             {
 458  0
                 cipher.init(Cipher.DECRYPT_MODE, secretKey);
 459  
             }
 460  0
             if (log.isDebugEnabled())
 461  
             {
 462  0
                 log.debug("decrypting w/ " + algorithm + "/" + algorithmParams);
 463  
             }
 464  
 
 465  
             //EtM Composition Approach
 466  0
             int macLenght = mac.getMacLength();
 467  0
             mac.update(secure, 0, secure.length-macLenght);
 468  0
             byte[] signedDigestHash = mac.doFinal();
 469  
 
 470  0
             boolean isMacEqual = true;
 471  0
             for (int i = 0; i < signedDigestHash.length; i++)
 472  
             {
 473  0
                 if (signedDigestHash[i] != secure[secure.length-macLenght+i])
 474  
                 {
 475  0
                     isMacEqual = false;
 476  0
                     break;
 477  
                 }
 478  
             }
 479  0
             if (!isMacEqual)
 480  
             {
 481  0
                 throw new ViewExpiredException();
 482  
             }
 483  
             
 484  0
             return cipher.doFinal(secure, 0, secure.length-macLenght);
 485  
         }
 486  0
         catch (Exception e)
 487  
         {
 488  0
             throw new FacesException(e);
 489  
         }
 490  
     }
 491  
 
 492  
     /**
 493  
      * Performs deserialization with the serialization provider created from the
 494  
      * SerialFactory.
 495  
      * 
 496  
      * @param bytes
 497  
      * @param ctx
 498  
      * @return
 499  
      */
 500  
     
 501  
     public static final Object getAsObject(byte[] bytes, ExternalContext ctx)
 502  
     {
 503  0
         ByteArrayInputStream input = null;
 504  
 
 505  
         try
 506  
         {
 507  0
             input = new ByteArrayInputStream(bytes);
 508  
 
 509  
             // get the Factory that was instantiated @ startup
 510  0
             SerialFactory serialFactory = (SerialFactory) ctx.getApplicationMap().get(SERIAL_FACTORY);
 511  
             
 512  0
             if(serialFactory == null)
 513  0
                 throw new NullPointerException("serialFactory");
 514  
             
 515  0
             ObjectInputStream s = null;
 516  0
             Exception pendingException = null;
 517  
             try
 518  
             {
 519  0
                 s = serialFactory.getObjectInputStream(input); 
 520  0
                 Object object = null;
 521  0
                 if (System.getSecurityManager() != null)
 522  
                 {
 523  0
                     final ObjectInputStream ois = s;
 524  0
                     object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>()
 525  0
                     {
 526  
                         //Put IOException and ClassNotFoundException as "checked" exceptions,
 527  
                         //so AccessController wrap them in a PrivilegedActionException
 528  
                         public Object run() throws  PrivilegedActionException, IOException, ClassNotFoundException
 529  
                         {
 530  0
                             return ois.readObject();
 531  
                         }
 532  
                     });
 533  
                     // Since s has the same instance as ois,
 534  
                     // we don't need to close it here, rather
 535  
                     // close it on the finally block related to s
 536  
                     // and avoid duplicate close exceptions
 537  
                     // finally
 538  
                     // {
 539  
                     //    ois.close();
 540  
                     // }
 541  0
                 }
 542  
                 else
 543  
                 {
 544  0
                     object = s.readObject();
 545  
                 }
 546  0
                 return object;
 547  
             }
 548  0
             catch (Exception e)
 549  
             {
 550  0
                 pendingException = e;
 551  0
                 throw new FacesException(e);
 552  
             }
 553  
             finally
 554  
             {
 555  0
                 if (s != null)
 556  
                 {
 557  
                     try
 558  
                     {
 559  0
                         s.close();
 560  
                     }
 561  0
                     catch (IOException e)
 562  
                     {
 563  
                         // If a previous exception is thrown 
 564  
                         // ignore this, but if not, wrap it in a
 565  
                         // FacesException and throw it. In this way
 566  
                         // we preserve the original semantic of this
 567  
                         // method, but we handle correctly the case
 568  
                         // when we close a stream. Obviously, the 
 569  
                         // information about this exception is lost,
 570  
                         // but note that the interesting information 
 571  
                         // is always on pendingException, since we
 572  
                         // only do a readObject() on the outer try block.
 573  0
                         if (pendingException == null)
 574  
                         {
 575  0
                             throw new FacesException(e);
 576  
                         }                        
 577  
                     }
 578  
                     finally
 579  
                     {
 580  0
                         s = null;
 581  0
                     }
 582  
                 }
 583  
             }
 584  
         }
 585  
         finally
 586  
         {
 587  0
             if (input != null)
 588  
             {
 589  
                 try
 590  
                 {
 591  0
                     input.close();
 592  
                 }
 593  0
                 catch (IOException e)
 594  
                 {
 595  
                     //ignore it, because ByteArrayInputStream.close has
 596  
                     //no effect, but it is better to call close and preserve
 597  
                     //semantic from previous code.
 598  
                 }
 599  
                 finally
 600  
                 {
 601  0
                     input = null;
 602  0
                 }
 603  
             }
 604  
         }
 605  
     }
 606  
 
 607  
     /**
 608  
      * Utility method for generating base 64 encoded strings.
 609  
      * 
 610  
      * @param args
 611  
      * @throws UnsupportedEncodingException
 612  
      */
 613  
     public static void main (String[] args) throws UnsupportedEncodingException
 614  
     {
 615  0
         byte[] bytes = encode(args[0].getBytes(ZIP_CHARSET));
 616  0
           System.out.println(new String(bytes, ZIP_CHARSET));
 617  0
     }
 618  
 
 619  
     private static byte[] findInitializationVector(ExternalContext ctx) {
 620  
         
 621  0
         byte[] iv = null;
 622  0
         String _iv = ctx.getInitParameter(INIT_ALGORITHM_IV);
 623  
         
 624  0
         if(_iv == null)
 625  
         {
 626  0
             _iv = ctx.getInitParameter(INIT_ALGORITHM_IV.toLowerCase());
 627  
         }
 628  
         
 629  0
         if (_iv != null)
 630  0
             iv = new Base64().decode(_iv.getBytes());
 631  
         
 632  0
         return iv;
 633  
     }
 634  
 
 635  
     private static String findAlgorithmParams(ExternalContext ctx) {
 636  
         
 637  0
         String algorithmParams = ctx.getInitParameter(INIT_ALGORITHM_PARAM);
 638  
         
 639  0
         if (algorithmParams == null)
 640  
         {
 641  0
             algorithmParams = ctx.getInitParameter(INIT_ALGORITHM_PARAM.toLowerCase());
 642  
         }
 643  
         
 644  0
         if (algorithmParams == null)
 645  
         {
 646  0
             algorithmParams = DEFAULT_ALGORITHM_PARAMS;
 647  
         }
 648  
         
 649  0
         if (log.isDebugEnabled())
 650  
         {
 651  0
             log.debug("Using algorithm paramaters " + algorithmParams);
 652  
         }
 653  
         
 654  0
         return algorithmParams;
 655  
     }
 656  
 
 657  
     private static String findAlgorithm(ExternalContext ctx) {
 658  
         
 659  0
         String algorithm = ctx.getInitParameter(INIT_ALGORITHM);
 660  
         
 661  0
         if (algorithm == null)
 662  
         {
 663  0
             algorithm = ctx.getInitParameter(INIT_ALGORITHM.toLowerCase());
 664  
         }
 665  
 
 666  0
         return findAlgorithm( algorithm );
 667  
     }
 668  
     
 669  
     private static String findAlgorithm(ServletContext ctx) {
 670  
 
 671  0
         String algorithm = ctx.getInitParameter(INIT_ALGORITHM);
 672  
         
 673  0
         if (algorithm == null)
 674  
         {
 675  0
             algorithm = ctx.getInitParameter(INIT_ALGORITHM.toLowerCase());
 676  
         }
 677  
 
 678  0
         return findAlgorithm( algorithm );
 679  
     }
 680  
     
 681  
     private static String findAlgorithm(String initParam) {
 682  
         
 683  0
         if (initParam == null)
 684  
         {
 685  0
             initParam = DEFAULT_ALGORITHM;
 686  
         }
 687  
         
 688  0
         if (log.isDebugEnabled())
 689  
         {
 690  0
             log.debug("Using algorithm " + initParam);
 691  
         }
 692  
         
 693  0
         return initParam;
 694  
         
 695  
     }
 696  
 
 697  
     /**
 698  
      * Does nothing if the user has disabled the SecretKey cache. This is
 699  
      * useful when dealing with a JCA provider whose SecretKey 
 700  
      * implementation is not thread safe.
 701  
      * 
 702  
      * Instantiates a SecretKey instance based upon what the user has 
 703  
      * specified in the deployment descriptor.  The SecretKey is then 
 704  
      * stored in application scope where it can be used for all requests.
 705  
      */
 706  
     
 707  
     public static void initSecret(ServletContext ctx){
 708  
         
 709  0
         if(ctx == null)
 710  0
             throw new NullPointerException("ServletContext ctx");
 711  
         
 712  0
         if (log.isDebugEnabled())
 713  0
             log.debug("Storing SecretKey @ " + INIT_SECRET_KEY_CACHE);
 714  
 
 715  
         // Create and store SecretKey on application scope
 716  0
         String cache = ctx.getInitParameter(INIT_SECRET_KEY_CACHE);
 717  
         
 718  0
         if(cache == null)
 719  
         {
 720  0
             cache = ctx.getInitParameter(INIT_SECRET_KEY_CACHE.toLowerCase());
 721  
         }
 722  
         
 723  0
         if (!"false".equals(cache))
 724  
         {
 725  0
             String algorithm = findAlgorithm(ctx);
 726  
             // you want to create this as few times as possible
 727  0
             ctx.setAttribute(INIT_SECRET_KEY_CACHE, new SecretKeySpec(findSecret(ctx, algorithm), algorithm));
 728  
         }
 729  
 
 730  0
         if (log.isDebugEnabled())
 731  0
             log.debug("Storing SecretKey @ " + INIT_MAC_SECRET_KEY_CACHE);
 732  
         
 733  0
         String macCache = ctx.getInitParameter(INIT_MAC_SECRET_KEY_CACHE);
 734  
         
 735  0
         if(macCache == null)
 736  
         {
 737  0
             macCache = ctx.getInitParameter(INIT_MAC_SECRET_KEY_CACHE.toLowerCase());
 738  
         }
 739  
         
 740  0
         if (!"false".equals(macCache))
 741  
         {
 742  0
             String macAlgorithm = findMacAlgorithm(ctx);
 743  
             // init mac secret and algorithm 
 744  0
             ctx.setAttribute(INIT_MAC_SECRET_KEY_CACHE, new SecretKeySpec(findMacSecret(ctx, macAlgorithm), macAlgorithm));
 745  
         }
 746  0
     }
 747  
     
 748  
     private static SecretKey getSecret(ExternalContext ctx)
 749  
     {
 750  0
         Object secretKey = (SecretKey) ctx.getApplicationMap().get(INIT_SECRET_KEY_CACHE);
 751  
         
 752  0
         if (secretKey == null)
 753  
         {
 754  0
             String cache = ctx.getInitParameter(INIT_SECRET_KEY_CACHE);
 755  
             
 756  0
             if(cache == null)
 757  
             {
 758  0
                 cache = ctx.getInitParameter(INIT_SECRET_KEY_CACHE.toLowerCase());
 759  
             }
 760  
             
 761  0
             if ("false".equals(cache))
 762  
             {
 763  
                 // No cache is used. This option is activated
 764  0
                 String secret = ctx.getInitParameter(INIT_SECRET);
 765  
                 
 766  0
                 if (secret == null)
 767  
                 {
 768  0
                     secret = ctx.getInitParameter(INIT_SECRET.toLowerCase());
 769  
                 }
 770  
 
 771  0
                 if (secret == null)
 772  
                 {
 773  0
                     throw new NullPointerException("Could not find secret using key '" + INIT_SECRET + "'");
 774  
                 }
 775  
                 
 776  0
                 String algorithm = findAlgorithm(ctx);
 777  
                 
 778  0
                 secretKey = new SecretKeySpec(findSecret(ctx, algorithm), algorithm);
 779  0
             }
 780  
             else
 781  
             {
 782  0
                 throw new NullPointerException("Could not find SecretKey in application scope using key '" 
 783  
                         + INIT_SECRET_KEY_CACHE + "'");
 784  
             }
 785  
         }
 786  
         
 787  0
         if( ! ( secretKey instanceof SecretKey ) )
 788  0
             throw new ClassCastException("Did not find an instance of SecretKey "
 789  
                     + "in application scope using the key '" + INIT_SECRET_KEY_CACHE + "'");
 790  
 
 791  
         
 792  0
         return (SecretKey) secretKey;
 793  
     }
 794  
 
 795  
     private static byte[] findSecret(ExternalContext ctx, String algorithm)
 796  
     {
 797  0
         String secret = ctx.getInitParameter(INIT_SECRET);
 798  
         
 799  0
         if (secret == null)
 800  
         {
 801  0
             secret = ctx.getInitParameter(INIT_SECRET.toLowerCase());
 802  
         }
 803  
         
 804  0
         return findSecret(secret, algorithm);
 805  
     }    
 806  
     
 807  
     private static byte[] findSecret(ServletContext ctx, String algorithm)
 808  
     {
 809  0
         String secret = ctx.getInitParameter(INIT_SECRET);
 810  
         
 811  0
         if (secret == null)
 812  
         {
 813  0
             secret = ctx.getInitParameter(INIT_SECRET.toLowerCase());
 814  
         }
 815  
         
 816  0
         return findSecret(secret, algorithm);
 817  
     }
 818  
     
 819  
     private static byte[] findSecret(String secret, String algorithm) {
 820  0
         byte[] bytes = null;
 821  
         
 822  0
         if(secret == null)
 823  
         {
 824  
             try
 825  
             {
 826  0
                 KeyGenerator kg = KeyGenerator.getInstance(algorithm);
 827  0
                 bytes = kg.generateKey().getEncoded();
 828  
                 
 829  0
                 if(log.isDebugEnabled())
 830  0
                     log.debug("generated random password of length " + bytes.length);
 831  
             }
 832  0
             catch (NoSuchAlgorithmException e)
 833  
             {
 834  
                 // Generate random password length 8, 
 835  0
                 int length = 8;
 836  0
                 bytes = new byte[length];
 837  0
                 new Random().nextBytes(bytes);
 838  
                 
 839  0
                 if(log.isDebugEnabled())
 840  0
                     log.debug("generated random password of length " + length);
 841  0
             }
 842  
         }
 843  
         else 
 844  
         {
 845  0
             bytes = new Base64().decode(secret.getBytes());
 846  
         }
 847  
         
 848  0
         return bytes;
 849  
     }
 850  
 
 851  
     private static String findMacAlgorithm(ExternalContext ctx) {
 852  
         
 853  0
         String algorithm = ctx.getInitParameter(INIT_MAC_ALGORITHM);
 854  
         
 855  0
         if (algorithm == null)
 856  
         {
 857  0
             algorithm = ctx.getInitParameter(INIT_MAC_ALGORITHM.toLowerCase());
 858  
         }
 859  
 
 860  0
         return findMacAlgorithm( algorithm );
 861  
 
 862  
     }
 863  
     
 864  
     private static String findMacAlgorithm(ServletContext ctx) {
 865  
 
 866  0
         String algorithm = ctx.getInitParameter(INIT_MAC_ALGORITHM);
 867  
         
 868  0
         if (algorithm == null)
 869  
         {
 870  0
             algorithm = ctx.getInitParameter(INIT_MAC_ALGORITHM.toLowerCase());
 871  
         }
 872  
 
 873  0
         return findMacAlgorithm( algorithm );
 874  
         
 875  
     }
 876  
     
 877  
     private static String findMacAlgorithm(String initParam) {
 878  
         
 879  0
         if (initParam == null)
 880  
         {
 881  0
             initParam = DEFAULT_MAC_ALGORITHM;
 882  
         }
 883  
         
 884  0
         if (log.isDebugEnabled())
 885  
         {
 886  0
             log.debug("Using algorithm " + initParam);
 887  
         }
 888  
         
 889  0
         return initParam;
 890  
         
 891  
     }
 892  
     
 893  
     private static SecretKey getMacSecret(ExternalContext ctx)
 894  
     {
 895  0
         Object secretKey = (SecretKey) ctx.getApplicationMap().get(INIT_MAC_SECRET_KEY_CACHE);
 896  
         
 897  0
         if (secretKey == null)
 898  
         {
 899  0
             String cache = ctx.getInitParameter(INIT_MAC_SECRET_KEY_CACHE);
 900  
             
 901  0
             if(cache == null)
 902  
             {
 903  0
                 cache = ctx.getInitParameter(INIT_MAC_SECRET_KEY_CACHE.toLowerCase());
 904  
             }
 905  
             
 906  0
             if ("false".equals(cache))
 907  
             {
 908  
                 // No cache is used. This option is activated
 909  0
                 String secret = ctx.getInitParameter(INIT_MAC_SECRET);
 910  
                 
 911  0
                 if (secret == null)
 912  
                 {
 913  0
                     secret = ctx.getInitParameter(INIT_MAC_SECRET.toLowerCase());
 914  
                 }
 915  
                 
 916  0
                 if (secret == null)
 917  
                 {
 918  0
                     throw new NullPointerException("Could not find secret using key '" + INIT_MAC_SECRET + "'");
 919  
                 }
 920  
                 
 921  0
                 String macAlgorithm = findMacAlgorithm(ctx);
 922  
 
 923  0
                 secretKey = new SecretKeySpec(findMacSecret(ctx, macAlgorithm), macAlgorithm);
 924  0
             }
 925  
             else
 926  
             {
 927  0
                 throw new NullPointerException("Could not find SecretKey in application scope using key '" 
 928  
                         + INIT_MAC_SECRET_KEY_CACHE + "'");
 929  
             }
 930  
         }
 931  
         
 932  0
         if( ! ( secretKey instanceof SecretKey ) )
 933  0
             throw new ClassCastException("Did not find an instance of SecretKey "
 934  
                     + "in application scope using the key '" + INIT_MAC_SECRET_KEY_CACHE + "'");
 935  
 
 936  
         
 937  0
         return (SecretKey) secretKey;
 938  
     }
 939  
 
 940  
     private static byte[] findMacSecret(ExternalContext ctx, String algorithm)
 941  
     {
 942  0
         String secret = ctx.getInitParameter(INIT_MAC_SECRET);
 943  
         
 944  0
         if (secret == null)
 945  
         {
 946  0
             secret = ctx.getInitParameter(INIT_MAC_SECRET.toLowerCase());
 947  
         }
 948  
  
 949  0
         return findMacSecret(secret, algorithm);
 950  
     }    
 951  
     
 952  
     private static byte[] findMacSecret(ServletContext ctx, String algorithm)
 953  
     {
 954  0
         String secret = ctx.getInitParameter(INIT_MAC_SECRET);
 955  
         
 956  0
         if (secret == null)
 957  
         {
 958  0
             secret = ctx.getInitParameter(INIT_MAC_SECRET.toLowerCase());
 959  
         }
 960  
         
 961  0
         return findMacSecret(secret, algorithm);
 962  
     }
 963  
 
 964  
     private static byte[] findMacSecret(String secret, String algorithm) {
 965  0
         byte[] bytes = null;
 966  
         
 967  0
         if(secret == null)
 968  
         {
 969  
             try
 970  
             {
 971  0
                 KeyGenerator kg = KeyGenerator.getInstance(algorithm);
 972  0
                 bytes = kg.generateKey().getEncoded();
 973  
                 
 974  0
                 if(log.isDebugEnabled())
 975  0
                     log.debug("generated random mac password of length " + bytes.length);
 976  
             }
 977  0
             catch (NoSuchAlgorithmException e)
 978  
             {
 979  
                 // Generate random password length 8, 
 980  0
                 int length = 8;
 981  0
                 bytes = new byte[length];
 982  0
                 new Random().nextBytes(bytes);
 983  
                 
 984  0
                 if(log.isDebugEnabled())
 985  0
                     log.debug("generated random mac password of length " + length);
 986  0
             }
 987  
         }
 988  
         else 
 989  
         {
 990  0
             bytes = new Base64().decode(secret.getBytes());
 991  
         }
 992  
         
 993  0
         return bytes;
 994  
     }
 995  
 }