001: package org.acegisecurity.providers.encoding;
002:
003: import org.apache.commons.codec.binary.Base64;
004: import org.apache.commons.codec.binary.Hex;
005:
006: import java.security.MessageDigest;
007: import java.security.NoSuchAlgorithmException;
008:
009: /**
010: * Base for digest password encoders.
011: * <p>This class can be used stand-alone, or one of the subclasses can be used for compatiblity and convenience.
012: * When using this class directly you must specify a
013: * <a href="http://java.sun.com/j2se/1.4.2/docs/guide/security/CryptoSpec.html#AppA">
014: * Message Digest Algorithm</a> to use as a constructor arg</p>
015: *
016: * <p>The encoded password hash is normally returned as Hex (32 char) version of the hash bytes.
017: * Setting the <tt>encodeHashAsBase64</tt> property to <tt>true</tt> will cause the encoded pass to be returned
018: * as Base64 text, which will consume 24 characters.
019: * See {@link BaseDigestPasswordEncoder#setEncodeHashAsBase64(boolean)}
020: * </p>
021: * <p>
022: * This PasswordEncoder can be used directly as in the following example:<br/>
023: * <pre>
024: * <bean id="passwordEncoder" class="org.acegisecurity.providers.encoding.MessageDigestPasswordEncoder">
025: * <constructor-arg value="MD5"/>
026: * </bean>
027: * </pre>
028: * </p>
029: *
030: * @author Ray Krueger
031: * @since 1.0.1
032: */
033: public class MessageDigestPasswordEncoder extends
034: BaseDigestPasswordEncoder {
035:
036: private final String algorithm;
037:
038: /**
039: * The digest algorithm to use
040: * Supports the named <a href="http://java.sun.com/j2se/1.4.2/docs/guide/security/CryptoSpec.html#AppA">
041: * Message Digest Algorithms</a> in the Java environment.
042: *
043: * @param algorithm
044: */
045: public MessageDigestPasswordEncoder(String algorithm) {
046: this (algorithm, false);
047: }
048:
049: /**
050: * Convenience constructor for specifying the algorithm and whether or not to enable base64 encoding
051: *
052: * @param algorithm
053: * @param encodeHashAsBase64
054: * @throws IllegalArgumentException if an unknown
055: */
056: public MessageDigestPasswordEncoder(String algorithm,
057: boolean encodeHashAsBase64) throws IllegalArgumentException {
058: this .algorithm = algorithm;
059: setEncodeHashAsBase64(encodeHashAsBase64);
060: //Validity Check
061: getMessageDigest();
062: }
063:
064: /**
065: * Encodes the rawPass using a MessageDigest.
066: * If a salt is specified it will be merged with the password before encoding.
067: *
068: * @param rawPass The plain text password
069: * @param salt The salt to sprinkle
070: * @return Hex string of password digest (or base64 encoded string if encodeHashAsBase64 is enabled.
071: */
072: public String encodePassword(String rawPass, Object salt) {
073: String saltedPass = mergePasswordAndSalt(rawPass, salt, false);
074:
075: MessageDigest messageDigest = getMessageDigest();
076:
077: byte[] digest = messageDigest.digest(saltedPass.getBytes());
078:
079: if (getEncodeHashAsBase64()) {
080: return new String(Base64.encodeBase64(digest));
081: } else {
082: return new String(Hex.encodeHex(digest));
083: }
084: }
085:
086: /**
087: * Get a MessageDigest instance for the given algorithm.
088: * Throws an IllegalArgumentException if <i>algorithm</i> is unknown
089: *
090: * @return MessageDigest instance
091: * @throws IllegalArgumentException if NoSuchAlgorithmException is thrown
092: */
093: protected final MessageDigest getMessageDigest()
094: throws IllegalArgumentException {
095: try {
096: return MessageDigest.getInstance(algorithm);
097: } catch (NoSuchAlgorithmException e) {
098: throw new IllegalArgumentException("No such algorithm ["
099: + algorithm + "]");
100: }
101: }
102:
103: /**
104: * Takes a previously encoded password and compares it with a rawpassword after mixing in the salt and
105: * encoding that value
106: *
107: * @param encPass previously encoded password
108: * @param rawPass plain text password
109: * @param salt salt to mix into password
110: * @return true or false
111: */
112: public boolean isPasswordValid(String encPass, String rawPass,
113: Object salt) {
114: String pass1 = "" + encPass;
115: String pass2 = encodePassword(rawPass, salt);
116:
117: return pass1.equals(pass2);
118: }
119:
120: public String getAlgorithm() {
121: return algorithm;
122: }
123: }
|