KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > lutris > appserver > server > sessionEnhydra > StandardSessionKeyGen


1
2 /*
3  * Enhydra Java Application Server Project
4  *
5  * The contents of this file are subject to the Enhydra Public License
6  * Version 1.1 (the "License"); you may not use this file except in
7  * compliance with the License. You may obtain a copy of the License on
8  * the Enhydra web site ( http://www.enhydra.org/ ).
9  *
10  * Software distributed under the License is distributed on an "AS IS"
11  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
12  * the License for the specific terms governing rights and limitations
13  * under the License.
14  *
15  * The Initial Developer of the Enhydra Application Server is Lutris
16  * Technologies, Inc. The Enhydra Application Server and portions created
17  * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
18  * All Rights Reserved.
19  *
20  * Contributor(s):
21  *
22  * $Id: StandardSessionKeyGen.java,v 1.2 2005/03/24 10:51:20 slobodan Exp $
23  */

24
25
26
27
28
29 package com.lutris.appserver.server.sessionEnhydra;
30
31 import java.io.ByteArrayOutputStream JavaDoc;
32 import java.io.DataOutputStream JavaDoc;
33 import java.io.IOException JavaDoc;
34 import java.security.MessageDigest JavaDoc;
35 import java.security.NoSuchAlgorithmException JavaDoc;
36 import java.security.SecureRandom JavaDoc;
37
38 import com.lutris.util.Base64Encoder;
39 import com.lutris.util.FatalExceptionError;
40
41 /**
42  * The session random key generator. This class implements a background thread
43  * that wakes up and counts the number of Standard Session Manager requests
44  * completed at one or more different interval periods, and
45  * supplements the seed of the Manager's random number generator
46  * in order to make the value of the cookies extremely unpredictable.
47  * This is an absolute requirement if random cookie values are to
48  * be used for any type of security purpose.
49  *
50  * This random number generator uses the JDK 1.1 <code>SecureRandom</code>
51  * object, which implements a cryptographic grade random number
52  * generator based on the RSA MD5 one-way hash. In combination with
53  * external user-generated time delay information, the numbers
54  * generated by this object are highly unpredictable, and therefore
55  * suitably secure for their use as session keys.
56  *
57  * @version $Revision: 1.2 $
58  * @author John Marco
59  * @author Shawn McMurdo
60  */

61 public class StandardSessionKeyGen extends Thread JavaDoc {
62
63     /**
64      * Random number generator used to generate session keys.
65      *
66      * @see com.lutris.StandardSessionManager#randomThread
67      * @see java.security.SecureRandom
68      */

69     private SecureRandom JavaDoc randomizer = new SecureRandom JavaDoc();
70
71     // If you want to improve startup performance significantly
72
// use the following constructor.
73
// new SecureRandom(new Long(System.currentTimeMillis()).toString().getBytes());
74

75     /**
76      * Counter that is incremented by the user of this class to provide a
77      * random external value. Usually done on requests.
78      */

79     private int randomCounter = 0;
80
81     /*
82      * Timer intervals.
83      */

84     private long[] alarmVector;
85     private long[] intervalVector;
86     private int numIntervals;
87     
88     /**
89      * Constructor a new key generator random number entropy
90      * generator. Initializes timers and counters and start a
91      * thread.
92      *
93      * @param manager The Standard session manager to be randomized.
94      * @param intervals An array of one or more intervals, in seconds
95      * in which to periodically supplement the random number
96      * generator with external user-generated entropy.
97      */

98     public StandardSessionKeyGen(long intervals[]) {
99     int i;
100     long now = System.currentTimeMillis();
101     numIntervals = intervals.length;
102     intervalVector = new long[numIntervals];
103
104     //Convert each interval value from seconds to milliseconds.
105
for (i=0; i<numIntervals; i++) {
106         intervalVector[i] = intervals[i] * 1000; // Milliseconds.
107
}
108     alarmVector = new long[numIntervals];
109     for (i=0; i<numIntervals; i++) {
110         alarmVector[i] = now + intervalVector[i];
111     }
112     setDaemon(true); // Don't require this thread to exit.
113
}
114     
115     /**
116      * The main code body of the Idle Timer Thread. Enters an endless
117      * loop that sleeps for a configurable period, periodically waking
118      * up to modify the session manager's random seed. An externally
119      * incremented count is used as a source of user-generated randomness.
120      */

121     public void run() {
122     ByteArrayOutputStream JavaDoc bos = new ByteArrayOutputStream JavaDoc();
123     DataOutputStream JavaDoc dos = new DataOutputStream JavaDoc(bos);
124     MessageDigest JavaDoc md5 = null;
125     int i;
126     long now, least, interval;
127
128     try {
129         md5 = MessageDigest.getInstance("MD5");
130     } catch (NoSuchAlgorithmException JavaDoc e) {
131             // JDK1.1 always has MD5.
132
throw new FatalExceptionError(e);
133         }
134     while (true) {
135         now = System.currentTimeMillis();
136         least = Long.MAX_VALUE;
137
138         // Check each alarm for expiry, and processes if needed.
139
for (i=0; i<numIntervals; i++) {
140         if (now >= alarmVector[i]) {
141             try {
142             dos.writeLong(randomCounter);
143             dos.writeLong(now);
144             dos.flush();
145             } catch (IOException JavaDoc e) {
146                         throw new FatalExceptionError(e); //- won't happen.
147
}
148             randomizer.setSeed(md5.digest(bos.toByteArray()));
149
150             // Set the alarm to its next wakeup time.
151
alarmVector[i] = now + intervalVector[i];
152         }
153
154         // Find the next scheduled alarm.
155
if (alarmVector[i] < least) {
156             least = alarmVector[i];
157                 }
158         }
159
160         // Wait for the next scheduled alarm.
161
interval = least - now;
162         if (interval <= 0) {
163         interval = 1;
164             }
165         try {
166         sleep(interval);
167         } catch (InterruptedException JavaDoc e) {
168                 // Don't throw interrupts.
169
}
170     }
171     }
172
173     /**
174      * Increment the random counter. Used for randomization, so doesn't
175      * have to be completely accurate and is not sychronized. The normal
176      * way to use this is to increment it on requests generated by external
177      * sources.
178      */

179     public void incrementRandomCounter() {
180         randomCounter++;
181     }
182
183     /**
184      * Generates a new random key to identify a session.
185      * This key represents a random integer that is large and sparse
186      * enough to make it highly unlikely that a valid session key can
187      * be guessed by an intruder. The <code>randomizer</code> object is
188      * used to generate this key.<P>
189      *
190      * This function is reentrant and does not need synchronization.
191      *
192      * @return A string representing a random key. The characters
193      * in this key are constrained to [A-Za-z0-9_-]. The
194      * encoding is more or less Base 64, but instead of '+'
195      * and '/' as defined in RFC1521, the characters '_' and
196      * '-' are used because they are safe in URLs and file names.
197      */

198     public String JavaDoc newSessionKey() {
199     try {
200         byte[] rand32 = new byte[32];
201         byte[] rand2 = new byte[2];
202         byte[] md5result;
203         long now = System.currentTimeMillis();
204         ByteArrayOutputStream JavaDoc bos = new ByteArrayOutputStream JavaDoc();
205         DataOutputStream JavaDoc dos = new DataOutputStream JavaDoc(bos);
206         MessageDigest JavaDoc md5 = MessageDigest.getInstance("MD5");
207         randomizer.nextBytes(rand32);
208         randomizer.nextBytes(rand2);
209         dos.write(rand32, 0, rand32.length);
210         dos.writeLong(now);
211         dos.flush();
212         md5result = md5.digest(bos.toByteArray());
213         bos.reset();
214         dos = new DataOutputStream JavaDoc(bos);
215         dos.write(md5result, 0, md5result.length);
216         dos.write(rand2, 0, rand2.length);
217         return Base64Encoder.toBase64SessionKeyString(bos.toByteArray());
218     } catch (IOException JavaDoc e) {
219             // Byte stream; should never happen.
220
throw new FatalExceptionError(e);
221         } catch (NoSuchAlgorithmException JavaDoc e) {
222             // JDK 1.1 has MD5m, should never happen.
223
throw new FatalExceptionError(e);
224         }
225     }
226
227     /**
228      * Shutdown the thread associated with this object.
229      */

230     public void shutdown() {
231         stop();
232     }
233 }
234
235
Popular Tags