1 22 package org.jboss.web.tomcat.tc6.session; 23 24 import java.util.Collection ; 25 import java.util.Iterator ; 26 import java.util.Random ; 27 import java.security.MessageDigest ; 28 import java.security.NoSuchAlgorithmException ; 29 import java.security.SecureRandom ; 30 31 import org.jboss.logging.Logger; 32 33 38 public class SessionIDGenerator 39 { 40 protected final static int SESSION_ID_BYTES = 16; protected final static String SESSION_ID_HASH_ALGORITHM = "MD5"; 42 protected final static String SESSION_ID_RANDOM_ALGORITHM = "SHA1PRNG"; 43 protected final static String SESSION_ID_RANDOM_ALGORITHM_ALT = "IBMSecureRandom"; 44 protected Logger log = Logger.getLogger(SessionIDGenerator.class); 45 46 protected MessageDigest digest = null; 47 protected Random random = null; 48 protected static SessionIDGenerator s_; 49 50 protected String sessionIdAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-*"; 51 52 public static SessionIDGenerator getInstance() 53 { 54 if (s_ == null) s_ = new SessionIDGenerator(); 55 return s_; 56 } 57 58 61 public void setSessionIdAlphabet(String sessionIdAlphabet) 62 { 63 if (sessionIdAlphabet.length() != 65) { 64 throw new IllegalArgumentException ("SessionIdAlphabet must be exactly 65 characters long"); 65 } 66 67 checkDuplicateChars(sessionIdAlphabet); 68 69 this.sessionIdAlphabet = sessionIdAlphabet; 70 } 71 72 protected void checkDuplicateChars(String sessionIdAlphabet) { 73 char[] alphabet = sessionIdAlphabet.toCharArray(); 74 for (int i=0; i < alphabet.length; i++) { 75 if (!uniqueChar(alphabet[i], sessionIdAlphabet)) { 76 throw new IllegalArgumentException ("All chars in SessionIdAlphabet must be unique"); 77 } 78 } 79 } 80 81 protected boolean uniqueChar(char c, String s) { 83 int firstIndex = s.indexOf(c); 84 if (firstIndex == -1) return false; 85 return s.indexOf(c, firstIndex + 1) == -1; 86 } 87 88 91 public String getSessionIdAlphabet() { 92 return this.sessionIdAlphabet; 93 } 94 95 public synchronized String getSessionId() 96 { 97 String id = generateSessionId(); 98 if (log.isDebugEnabled()) 99 log.debug("getSessionId called: " + id); 100 return id; 101 } 102 103 104 109 protected synchronized String generateSessionId() 110 { 111 if (this.digest == null) 112 { 113 this.digest = getDigest(); 114 } 115 116 if (this.random == null) 117 { 118 this.random = getRandom(); 119 } 120 121 byte[] bytes = new byte[SESSION_ID_BYTES]; 122 123 this.random.nextBytes(bytes); 125 126 bytes = this.digest.digest(bytes); 128 129 return encode(bytes); 131 } 132 133 141 protected String encode(byte[] data) 142 { 143 char[] out = new char[((data.length + 2) / 3) * 4]; 144 char[] alphabet = this.sessionIdAlphabet.toCharArray(); 145 146 for (int i = 0, index = 0; i < data.length; i += 3, index += 4) 151 { 152 boolean quad = false; 153 boolean trip = false; 154 155 int val = (0xFF & (int) data[i]); 156 val <<= 8; 157 if ((i + 1) < data.length) 158 { 159 val |= (0xFF & (int) data[i + 1]); 160 trip = true; 161 } 162 val <<= 8; 163 if ((i + 2) < data.length) 164 { 165 val |= (0xFF & (int) data[i + 2]); 166 quad = true; 167 } 168 out[index + 3] = alphabet[(quad ? (val & 0x3F) : 64)]; 169 val >>= 6; 170 out[index + 2] = alphabet[(trip ? (val & 0x3F) : 64)]; 171 val >>= 6; 172 out[index + 1] = alphabet[val & 0x3F]; 173 val >>= 6; 174 out[index + 0] = alphabet[val & 0x3F]; 175 } 176 return new String (out); 177 } 178 179 184 protected synchronized Random getRandom() 185 { 186 long seed; 187 Random random = null; 188 189 seed = System.currentTimeMillis(); 191 seed ^= Runtime.getRuntime().freeMemory(); 192 193 try 194 { 195 random = SecureRandom.getInstance(SESSION_ID_RANDOM_ALGORITHM); 196 } 197 catch (NoSuchAlgorithmException e) 198 { 199 try 200 { 201 random = SecureRandom.getInstance(SESSION_ID_RANDOM_ALGORITHM_ALT); 202 } 203 catch (NoSuchAlgorithmException e_alt) 204 { 205 log.error("Could not generate SecureRandom for session-id randomness", e); 206 log.error("Could not generate SecureRandom for session-id randomness", e_alt); 207 return null; 208 } 209 } 210 211 random.setSeed(seed); 213 214 return random; 215 } 216 217 222 protected synchronized MessageDigest getDigest() 223 { 224 MessageDigest digest = null; 225 226 try 227 { 228 digest = MessageDigest.getInstance(SESSION_ID_HASH_ALGORITHM); 229 } 230 catch (NoSuchAlgorithmException e) 231 { 232 log.error("Could not generate MessageDigest for session-id hashing", e); 233 return null; 234 } 235 236 return digest; 237 } 238 239 } 240 | Popular Tags |