KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > web > tomcat > tc5 > session > SessionIDGenerator


1 /*
2  * JBoss, the OpenSource J2EE webOS
3  *
4  * Distributable under LGPL license.
5  * See terms of license at gnu.org.
6  */

7
8 package org.jboss.web.tomcat.tc5.session;
9
10 import java.util.Collection JavaDoc;
11 import java.util.Iterator JavaDoc;
12 import java.util.Random JavaDoc;
13 import java.security.MessageDigest JavaDoc;
14 import java.security.NoSuchAlgorithmException JavaDoc;
15 import java.security.SecureRandom JavaDoc;
16
17 import org.jboss.logging.Logger;
18
19 /**
20  * Unique session id generator
21  *
22  * @author Ben Wang
23  */

24 public class SessionIDGenerator
25 {
26    protected final static int SESSION_ID_BYTES = 16; // We want 16 Bytes for the session-id
27
protected final static String JavaDoc SESSION_ID_HASH_ALGORITHM = "MD5";
28    protected final static String JavaDoc SESSION_ID_RANDOM_ALGORITHM = "SHA1PRNG";
29    protected final static String JavaDoc SESSION_ID_RANDOM_ALGORITHM_ALT = "IBMSecureRandom";
30    protected Logger log = Logger.getLogger(SessionIDGenerator.class);
31
32    protected MessageDigest JavaDoc digest = null;
33    protected Random JavaDoc random = null;
34    protected static SessionIDGenerator s_;
35    
36    protected String JavaDoc sessionIdAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-*";
37
38    public static SessionIDGenerator getInstance()
39    {
40       if (s_ == null) s_ = new SessionIDGenerator();
41       return s_;
42    }
43
44    /**
45     * The SessionIdAlphabet is the set of characters used to create a session Id
46     */

47    public void setSessionIdAlphabet(String JavaDoc sessionIdAlphabet)
48    {
49       if (sessionIdAlphabet.length() != 65) {
50          throw new IllegalArgumentException JavaDoc("SessionIdAlphabet must be exactly 65 characters long");
51       }
52
53       checkDuplicateChars(sessionIdAlphabet);
54
55       this.sessionIdAlphabet = sessionIdAlphabet;
56    }
57
58    protected void checkDuplicateChars(String JavaDoc 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 JavaDoc("All chars in SessionIdAlphabet must be unique");
63           }
64       }
65    }
66       
67    // does a character appear in the String once and only once?
68
protected boolean uniqueChar(char c, String JavaDoc s) {
69        int firstIndex = s.indexOf(c);
70        if (firstIndex == -1) return false;
71        return s.indexOf(c, firstIndex + 1) == -1;
72    }
73
74    /**
75     * The SessionIdAlphabet is the set of characters used to create a session Id
76     */

77    public String JavaDoc getSessionIdAlphabet() {
78       return this.sessionIdAlphabet;
79    }
80    
81    public synchronized String JavaDoc getSessionId()
82    {
83       String JavaDoc id = generateSessionId();
84       if (log.isDebugEnabled())
85          log.debug("getSessionId called: " + id);
86       return id;
87    }
88
89
90    /**
91     * Generate a session-id that is not guessable
92     *
93     * @return generated session-id
94     */

95    protected synchronized String JavaDoc 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       // get random bytes
110
this.random.nextBytes(bytes);
111
112       // Hash the random bytes
113
bytes = this.digest.digest(bytes);
114
115       // Render the result as a String of hexadecimal digits
116
return encode(bytes);
117    }
118
119    /**
120     * Encode the bytes into a String with a slightly modified Base64-algorithm
121     * This code was written by Kevin Kelley <kelley@ruralnet.net>
122     * and adapted by Thomas Peuss <jboss@peuss.de>
123     *
124     * @param data The bytes you want to encode
125     * @return the encoded String
126     */

127    protected String JavaDoc encode(byte[] data)
128    {
129       char[] out = new char[((data.length + 2) / 3) * 4];
130       char[] alphabet = this.sessionIdAlphabet.toCharArray();
131
132       //
133
// 3 bytes encode to 4 chars. Output is always an even
134
// multiple of 4 characters.
135
//
136
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 JavaDoc(out);
163    }
164
165    /**
166     * get a random-number generator
167     *
168     * @return a random-number generator
169     */

170    protected synchronized Random JavaDoc getRandom()
171    {
172       long seed;
173       Random JavaDoc random = null;
174
175       // Mix up the seed a bit
176
seed = System.currentTimeMillis();
177       seed ^= Runtime.getRuntime().freeMemory();
178
179       try
180       {
181          random = SecureRandom.getInstance(SESSION_ID_RANDOM_ALGORITHM);
182       }
183       catch (NoSuchAlgorithmException JavaDoc e)
184       {
185          try
186          {
187             random = SecureRandom.getInstance(SESSION_ID_RANDOM_ALGORITHM_ALT);
188          }
189          catch (NoSuchAlgorithmException JavaDoc 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       // set the generated seed for this PRNG
198
random.setSeed(seed);
199
200       return random;
201    }
202
203    /**
204     * get a MessageDigest hash-generator
205     *
206     * @return a hash generator
207     */

208    protected synchronized MessageDigest JavaDoc getDigest()
209    {
210       MessageDigest JavaDoc digest = null;
211
212       try
213       {
214          digest = MessageDigest.getInstance(SESSION_ID_HASH_ALGORITHM);
215       }
216       catch (NoSuchAlgorithmException JavaDoc 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