001: /*
002: * JOSSO: Java Open Single Sign-On
003: *
004: * Copyright 2004-2008, Atricore, Inc.
005: *
006: * This is free software; you can redistribute it and/or modify it
007: * under the terms of the GNU Lesser General Public License as
008: * published by the Free Software Foundation; either version 2.1 of
009: * the License, or (at your option) any later version.
010: *
011: * This software is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this software; if not, write to the Free
018: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
019: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
020: */
021:
022: package org.josso.util.id;
023:
024: import org.apache.commons.logging.Log;
025: import org.apache.commons.logging.LogFactory;
026:
027: import java.security.MessageDigest;
028: import java.security.NoSuchAlgorithmException;
029: import java.util.Random;
030:
031: /**
032: * This is an implementation of an id generator based on Jakarta Tomcat 5.0
033: * Assertion id generation.
034: * This implementation is thread safe.
035: *
036: * @author <a href="mailto:gbrigand@josso.org">Gianluca Brigandi</a>
037: * @version $Id$
038: */
039:
040: public abstract class AbstractIdGenerator implements IdGenerator {
041:
042: private static final Log logger = LogFactory
043: .getLog(AbstractIdGenerator.class);
044:
045: /**
046: * The default message digest algorithm to use if we cannot use
047: * the requested one.
048: */
049: protected static final String DEFAULT_ALGORITHM = "MD5";
050:
051: /**
052: * The message digest algorithm to be used when generating Assertion
053: * identifiers. This must be an algorithm supported by the
054: * <code>java.security.MessageDigest</code> class on your platform.
055: */
056: private String _algorithm = DEFAULT_ALGORITHM;
057:
058: private int _assertionIdLength = 16;
059: private String _entropy;
060: private Random _random;
061:
062: /**
063: * The Java class name of the random number generator class to be used
064: * when generating assertion identifiers.
065: */
066: protected String _randomClass = "java.security.SecureRandom";
067:
068: /**
069: * Return the random number generator instance we should use for
070: * generating assertion identifiers. If there is no such generator
071: * currently defined, construct and seed a new one.
072: */
073: public synchronized Random getRandom() {
074:
075: if (_random == null) {
076: synchronized (this ) {
077: if (_random == null) {
078: // Calculate the new random number generator seed
079: long seed = System.currentTimeMillis();
080: long t1 = seed;
081: char entropy[] = getEntropy().toCharArray();
082: for (int i = 0; i < entropy.length; i++) {
083: long update = ((byte) entropy[i]) << ((i % 8) * 8);
084: seed ^= update;
085: }
086: try {
087: // Construct and seed a new random number generator
088: Class clazz = Class.forName(_randomClass);
089: _random = (Random) clazz.newInstance();
090: _random.setSeed(seed);
091: } catch (Exception e) {
092: // Can't instantiate random class, fall back to the simple case
093: logger.error("Can't use random class : "
094: + _randomClass
095: + ", fall back to the simple case.", e);
096: _random = new java.util.Random();
097: _random.setSeed(seed);
098: }
099: // Log a debug msg if this is taking too long ...
100: long t2 = System.currentTimeMillis();
101: if ((t2 - t1) > 100)
102: logger
103: .debug("Delay getting Random with class : "
104: + _randomClass
105: + " [getRandom()] "
106: + (t2 - t1)
107: + " ms.");
108: }
109: }
110: }
111:
112: return (_random);
113:
114: }
115:
116: /**
117: * Return the MessageDigest object to be used for calculating
118: * assertion identifiers. If none has been created yet, initialize
119: * one the first time this method is called.
120: */
121: public synchronized MessageDigest getDigest() {
122:
123: MessageDigest digest = null;
124: if (_algorithm != null) {
125:
126: try {
127: digest = MessageDigest.getInstance(_algorithm);
128: logger.debug("Using hash algorithm/encoding : "
129: + _algorithm);
130: } catch (NoSuchAlgorithmException e) {
131: logger.error("Algorithm not supported : " + _algorithm,
132: e);
133: try {
134: digest = MessageDigest
135: .getInstance(DEFAULT_ALGORITHM);
136: } catch (NoSuchAlgorithmException f) {
137: logger.error("Algorithm not supported : "
138: + DEFAULT_ALGORITHM, e);
139: digest = null;
140: }
141: }
142: }
143:
144: return digest;
145:
146: }
147:
148: /**
149: * Generate a byte array containing a assertion identifier
150: */
151: protected void getRandomBytes(byte[] bytes) {
152: // TODO : Performance may be improved by using O.S. Specific devices like /dev/urandom (see tomcat 5.0)
153: Random random = getRandom();
154: random.nextBytes(bytes);
155: }
156:
157: /**
158: * Return the entropy increaser value, or compute a semi-useful value
159: * if this String has not yet been set.
160: */
161: public String getEntropy() {
162:
163: // Calculate a semi-useful value if this has not been set
164: if (_entropy == null)
165: setEntropy(this .toString());
166:
167: return (_entropy);
168:
169: }
170:
171: /**
172: * Set the entropy increaser value.
173: *
174: * @param entropy The new entropy increaser value
175: */
176: public void setEntropy(String entropy) {
177: // String oldEntropy = entropy;
178: _entropy = entropy;
179:
180: }
181:
182: /**
183: * Return the digest algorithm for the id generator.
184: *
185: * @return String the algorithm name (i.e. MD5).
186: */
187: public String getAlgorithm() {
188: return _algorithm;
189: }
190:
191: /**
192: * Set the message digest algorithm for the id generator.
193: *
194: * @param algorithm The new message digest algorithm
195: */
196: public void setAlgorithm(String algorithm) {
197: _algorithm = algorithm;
198: }
199:
200: /**
201: * Gets the assertion id length (in bytes) for Assertions created by this
202: * Generator
203: */
204: public int getAssertionIdLength() {
205: return _assertionIdLength;
206: }
207:
208: /**
209: * Sets the assertion id length (in bytes) for Assertions created by this
210: * Generator
211: *
212: * @param idLength The assertion id length
213: */
214: public void setAssertionIdLength(int idLength) {
215: _assertionIdLength = idLength;
216: }
217:
218: /**
219: * Gets the random number generator class name.
220: */
221: public String getRandomClass() {
222: return _randomClass;
223: }
224:
225: /**
226: * Sets the random number generator class name.
227: */
228: public void setRandomClass(String randomClass) {
229: _randomClass = randomClass;
230: _random = null;
231: }
232:
233: }
|