Coverage Report - org.apache.myfaces.application.viewstate.SessionIdGenerator
 
Classes in this File Line Coverage Branch Coverage Complexity
SessionIdGenerator
0%
0/75
0%
0/36
3.75
 
 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.application.viewstate;
 20  
 
 21  
 import java.security.NoSuchAlgorithmException;
 22  
 import java.security.NoSuchProviderException;
 23  
 import java.security.SecureRandom;
 24  
 import java.util.Queue;
 25  
 import java.util.concurrent.ConcurrentLinkedQueue;
 26  
 import java.util.logging.Level;
 27  
 import java.util.logging.Logger;
 28  
 
 29  
 /**
 30  
  * NOTE: Class taken from tomcat 7 org.apache.catalina.util.SessionIdGenerator
 31  
  * and used here as an alternative for server side state token encryption.
 32  
  * 
 33  
  */
 34  0
 class SessionIdGenerator
 35  
 {
 36  
 
 37  0
     private static Logger log = Logger.getLogger(SessionIdGenerator.class.getName());
 38  
 
 39  
     /**
 40  
      * Queue of random number generator objects to be used when creating session
 41  
      * identifiers. If the queue is empty when a random number generator is
 42  
      * required, a new random number generator object is created. This is
 43  
      * designed this way since random number generators use a sync to make them
 44  
      * thread-safe and the sync makes using a a single object slow(er).
 45  
      */
 46  0
     private Queue<SecureRandom> randoms =
 47  
             new ConcurrentLinkedQueue<SecureRandom>();
 48  
     /**
 49  
      * The Java class name of the secure random number generator class to be
 50  
      * used when generating session identifiers. The random number generator
 51  
      * class must be self-seeding and have a zero-argument constructor. If not
 52  
      * specified, an instance of {@link SecureRandom} will be generated.
 53  
      */
 54  0
     private String secureRandomClass = null;
 55  
     /**
 56  
      * The name of the algorithm to use to create instances of
 57  
      * {@link SecureRandom} which are used to generate session IDs. If no
 58  
      * algorithm is specified, SHA1PRNG is used. To use the platform default
 59  
      * (which may be SHA1PRNG), specify the empty string. If an invalid
 60  
      * algorithm and/or provider is specified the {@link SecureRandom} instances
 61  
      * will be created using the defaults. If that fails, the {@link
 62  
      * SecureRandom} instances will be created using platform defaults.
 63  
      */
 64  0
     private String secureRandomAlgorithm = "SHA1PRNG";
 65  
     /**
 66  
      * The name of the provider to use to create instances of
 67  
      * {@link SecureRandom} which are used to generate session IDs. If no
 68  
      * algorithm is specified the of SHA1PRNG default is used. If an invalid
 69  
      * algorithm and/or provider is specified the {@link SecureRandom} instances
 70  
      * will be created using the defaults. If that fails, the {@link
 71  
      * SecureRandom} instances will be created using platform defaults.
 72  
      */
 73  0
     private String secureRandomProvider = null;
 74  
     /**
 75  
      * Node identifier when in a cluster. Defaults to the empty string.
 76  
      */
 77  0
     private String jvmRoute = "";
 78  
     /**
 79  
      * Number of bytes in a session ID. Defaults to 16.
 80  
      */
 81  0
     private int sessionIdLength = 16;
 82  
 
 83  
     /**
 84  
      * Specify a non-default @{link {@link SecureRandom} implementation to use.
 85  
      *
 86  
      * @param secureRandomClass The fully-qualified class name
 87  
      */
 88  
     public void setSecureRandomClass(String secureRandomClass)
 89  
     {
 90  0
         this.secureRandomClass = secureRandomClass;
 91  0
     }
 92  
 
 93  
     /**
 94  
      * Specify a non-default algorithm to use to generate random numbers.
 95  
      *
 96  
      * @param secureRandomAlgorithm The name of the algorithm
 97  
      */
 98  
     public void setSecureRandomAlgorithm(String secureRandomAlgorithm)
 99  
     {
 100  0
         this.secureRandomAlgorithm = secureRandomAlgorithm;
 101  0
     }
 102  
 
 103  
     /**
 104  
      * Specify a non-default provider to use to generate random numbers.
 105  
      *
 106  
      * @param secureRandomProvider The name of the provider
 107  
      */
 108  
     public void setSecureRandomProvider(String secureRandomProvider)
 109  
     {
 110  0
         this.secureRandomProvider = secureRandomProvider;
 111  0
     }
 112  
 
 113  
     /**
 114  
      * Specify the node identifier associated with this node which will be
 115  
      * included in the generated session ID.
 116  
      *
 117  
      * @param jvmRoute The node identifier
 118  
      */
 119  
     public void setJvmRoute(String jvmRoute)
 120  
     {
 121  0
         this.jvmRoute = jvmRoute;
 122  0
     }
 123  
 
 124  
     /**
 125  
      * Specify the number of bytes for a session ID
 126  
      *
 127  
      * @param sessionIdLength Number of bytes
 128  
      */
 129  
     public void setSessionIdLength(int sessionIdLength)
 130  
     {
 131  0
         this.sessionIdLength = sessionIdLength;
 132  0
     }
 133  
 
 134  
     /**
 135  
      * Generate and return a new session identifier.
 136  
      */
 137  
     public String generateSessionId()
 138  
     {
 139  
 
 140  0
         byte random[] = new byte[16];
 141  
 
 142  
         // Render the result as a String of hexadecimal digits
 143  0
         StringBuilder buffer = new StringBuilder();
 144  
 
 145  0
         int resultLenBytes = 0;
 146  
 
 147  0
         while (resultLenBytes < sessionIdLength)
 148  
         {
 149  0
             getRandomBytes(random);
 150  0
             for (int j = 0;
 151  0
                     j < random.length && resultLenBytes < sessionIdLength;
 152  0
                     j++)
 153  
             {
 154  0
                 byte b1 = (byte) ((random[j] & 0xf0) >> 4);
 155  0
                 byte b2 = (byte) (random[j] & 0x0f);
 156  0
                 if (b1 < 10)
 157  
                 {
 158  0
                     buffer.append((char) ('0' + b1));
 159  
                 }
 160  
                 else
 161  
                 {
 162  0
                     buffer.append((char) ('A' + (b1 - 10)));
 163  
                 }
 164  0
                 if (b2 < 10)
 165  
                 {
 166  0
                     buffer.append((char) ('0' + b2));
 167  
                 }
 168  
                 else
 169  
                 {
 170  0
                     buffer.append((char) ('A' + (b2 - 10)));
 171  
                 }
 172  0
                 resultLenBytes++;
 173  
             }
 174  
         }
 175  
 
 176  0
         if (jvmRoute != null && jvmRoute.length() > 0)
 177  
         {
 178  0
             buffer.append('.').append(jvmRoute);
 179  
         }
 180  
 
 181  0
         return buffer.toString();
 182  
     }
 183  
 
 184  
     public void getRandomBytes(byte bytes[])
 185  
     {
 186  0
         SecureRandom random = randoms.poll();
 187  0
         if (random == null)
 188  
         {
 189  0
             random = createSecureRandom();
 190  
         }
 191  0
         random.nextBytes(bytes);
 192  0
         randoms.add(random);
 193  0
     }
 194  
 
 195  
     /**
 196  
      * Create a new random number generator instance we should use for
 197  
      * generating session identifiers.
 198  
      */
 199  
     private SecureRandom createSecureRandom()
 200  
     {
 201  
 
 202  0
         SecureRandom result = null;
 203  
 
 204  0
         long t1 = System.currentTimeMillis();
 205  0
         if (secureRandomClass != null)
 206  
         {
 207  
             try
 208  
             {
 209  
                 // Construct and seed a new random number generator
 210  0
                 Class<?> clazz = Class.forName(secureRandomClass);
 211  0
                 result = (SecureRandom) clazz.newInstance();
 212  
             }
 213  0
             catch (Exception e)
 214  
             {
 215  0
                 log.log(Level.SEVERE, "Exception initializing random number generator of class "+ 
 216  
                         secureRandomClass + ". Falling back to java.secure.SecureRandom", e);
 217  0
             }
 218  
         }
 219  
 
 220  0
         if (result == null)
 221  
         {
 222  
             // No secureRandomClass or creation failed. Use SecureRandom.
 223  
             try
 224  
             {
 225  0
                 if (secureRandomProvider != null
 226  
                         && secureRandomProvider.length() > 0)
 227  
                 {
 228  0
                     result = SecureRandom.getInstance(secureRandomAlgorithm,
 229  
                             secureRandomProvider);
 230  
                 }
 231  
                 else
 232  
                 {
 233  0
                     if (secureRandomAlgorithm != null
 234  
                             && secureRandomAlgorithm.length() > 0)
 235  
                     {
 236  0
                         result = SecureRandom.getInstance(secureRandomAlgorithm);
 237  
                     }
 238  
                 }
 239  
             }
 240  0
             catch (NoSuchAlgorithmException e)
 241  
             {
 242  0
                 log.log(Level.SEVERE, "Exception initializing random number generator using algorithm: "+
 243  
                         secureRandomAlgorithm, e);
 244  
             }
 245  0
             catch (NoSuchProviderException e)
 246  
             {
 247  0
                 log.log(Level.SEVERE, "Exception initializing random number generator using provider: " + 
 248  
                         secureRandomProvider, e);
 249  0
             }
 250  
         }
 251  
 
 252  0
         if (result == null)
 253  
         {
 254  
             // Invalid provider / algorithm
 255  
             try
 256  
             {
 257  0
                 result = SecureRandom.getInstance("SHA1PRNG");
 258  
             }
 259  0
             catch (NoSuchAlgorithmException e)
 260  
             {
 261  0
                 log.log(Level.SEVERE, "Invalid provider / algoritm SHA1PRNG for generate secure random token", e);
 262  0
             }
 263  
         }
 264  
 
 265  0
         if (result == null)
 266  
         {
 267  
             // Nothing works - use platform default
 268  0
             result = new SecureRandom();
 269  
         }
 270  
 
 271  
         // Force seeding to take place
 272  0
         result.nextInt();
 273  
 
 274  0
         long t2 = System.currentTimeMillis();
 275  0
         if ((t2 - t1) > 100)
 276  
         {
 277  0
             if (log.isLoggable(Level.FINEST))
 278  
             {
 279  0
                 log.info("Creation of SecureRandom instance for session ID generation using ["
 280  
                         +result.getAlgorithm()+"] took ["+Long.valueOf(t2 - t1)+"] milliseconds.");
 281  
             }
 282  
         }
 283  0
         return result;
 284  
     }
 285  
 }