1 7 8 package org.jboss.web.tomcat.tc5.session; 9 10 import java.util.Collection ; 11 import java.util.Iterator ; 12 import java.util.Random ; 13 import java.security.MessageDigest ; 14 import java.security.NoSuchAlgorithmException ; 15 import java.security.SecureRandom ; 16 17 import org.jboss.logging.Logger; 18 19 24 public class SessionIDGenerator 25 { 26 protected final static int SESSION_ID_BYTES = 16; protected final static String SESSION_ID_HASH_ALGORITHM = "MD5"; 28 protected final static String SESSION_ID_RANDOM_ALGORITHM = "SHA1PRNG"; 29 protected final static String SESSION_ID_RANDOM_ALGORITHM_ALT = "IBMSecureRandom"; 30 protected Logger log = Logger.getLogger(SessionIDGenerator.class); 31 32 protected MessageDigest digest = null; 33 protected Random random = null; 34 protected static SessionIDGenerator s_; 35 36 protected String sessionIdAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-*"; 37 38 public static SessionIDGenerator getInstance() 39 { 40 if (s_ == null) s_ = new SessionIDGenerator(); 41 return s_; 42 } 43 44 47 public void setSessionIdAlphabet(String sessionIdAlphabet) 48 { 49 if (sessionIdAlphabet.length() != 65) { 50 throw new IllegalArgumentException ("SessionIdAlphabet must be exactly 65 characters long"); 51 } 52 53 checkDuplicateChars(sessionIdAlphabet); 54 55 this.sessionIdAlphabet = sessionIdAlphabet; 56 } 57 58 protected void checkDuplicateChars(String sessionIdAlphabet) { 59 char[] alphabet = sessionIdAlphabet.toCharArray(); 60 for (int i=0; i < alphabet.length; i++) { 61 if (!uniqueChar(alphabet[i], sessionIdAlphabet)) { 62 throw new IllegalArgumentException ("All chars in SessionIdAlphabet must be unique"); 63 } 64 } 65 } 66 67 protected boolean uniqueChar(char c, String s) { 69 int firstIndex = s.indexOf(c); 70 if (firstIndex == -1) return false; 71 return s.indexOf(c, firstIndex + 1) == -1; 72 } 73 74 77 public String getSessionIdAlphabet() { 78 return this.sessionIdAlphabet; 79 } 80 81 public synchronized String getSessionId() 82 { 83 String id = generateSessionId(); 84 if (log.isDebugEnabled()) 85 log.debug("getSessionId called: " + id); 86 return id; 87 } 88 89 90 95 protected synchronized String generateSessionId() 96 { 97 if (this.digest == null) 98 { 99 this.digest = getDigest(); 100 } 101 102 if (this.random == null) 103 { 104 this.random = getRandom(); 105 } 106 107 byte[] bytes = new byte[SESSION_ID_BYTES]; 108 109 this.random.nextBytes(bytes); 111 112 bytes = this.digest.digest(bytes); 114 115 return encode(bytes); 117 } 118 119 127 protected String encode(byte[] data) 128 { 129 char[] out = new char[((data.length + 2) / 3) * 4]; 130 char[] alphabet = this.sessionIdAlphabet.toCharArray(); 131 132 for (int i = 0, index = 0; i < data.length; i += 3, index += 4) 137 { 138 boolean quad = false; 139 boolean trip = false; 140 141 int val = (0xFF & (int) data[i]); 142 val <<= 8; 143 if ((i + 1) < data.length) 144 { 145 val |= (0xFF & (int) data[i + 1]); 146 trip = true; 147 } 148 val <<= 8; 149 if ((i + 2) < data.length) 150 { 151 val |= (0xFF & (int) data[i + 2]); 152 quad = true; 153 } 154 out[index + 3] = alphabet[(quad ? (val & 0x3F) : 64)]; 155 val >>= 6; 156 out[index + 2] = alphabet[(trip ? (val & 0x3F) : 64)]; 157 val >>= 6; 158 out[index + 1] = alphabet[val & 0x3F]; 159 val >>= 6; 160 out[index + 0] = alphabet[val & 0x3F]; 161 } 162 return new String (out); 163 } 164 165 170 protected synchronized Random getRandom() 171 { 172 long seed; 173 Random random = null; 174 175 seed = System.currentTimeMillis(); 177 seed ^= Runtime.getRuntime().freeMemory(); 178 179 try 180 { 181 random = SecureRandom.getInstance(SESSION_ID_RANDOM_ALGORITHM); 182 } 183 catch (NoSuchAlgorithmException e) 184 { 185 try 186 { 187 random = SecureRandom.getInstance(SESSION_ID_RANDOM_ALGORITHM_ALT); 188 } 189 catch (NoSuchAlgorithmException e_alt) 190 { 191 log.error("Could not generate SecureRandom for session-id randomness", e); 192 log.error("Could not generate SecureRandom for session-id randomness", e_alt); 193 return null; 194 } 195 } 196 197 random.setSeed(seed); 199 200 return random; 201 } 202 203 208 protected synchronized MessageDigest getDigest() 209 { 210 MessageDigest digest = null; 211 212 try 213 { 214 digest = MessageDigest.getInstance(SESSION_ID_HASH_ALGORITHM); 215 } 216 catch (NoSuchAlgorithmException e) 217 { 218 log.error("Could not generate MessageDigest for session-id hashing", e); 219 return null; 220 } 221 222 return digest; 223 } 224 225 } 226 | Popular Tags |