@ -29,7 +29,8 @@ import java.security.MessageDigest;
@@ -29,7 +29,8 @@ import java.security.MessageDigest;
/ * *
* A version of { @link ShaPasswordEncoder } which supports Ldap SHA and SSHA ( salted - SHA ) encodings . The values are
* base - 64 encoded and have the label "{SHA}" ( or "{SSHA}" ) prepended to the encoded hash .
* base - 64 encoded and have the label "{SHA}" ( or "{SSHA}" ) prepended to the encoded hash . These can be made lower - case
* in the encoded password , if required , by setting the < tt > forceLowerCasePrefix < / tt > property to true .
*
* @author Luke Taylor
* @version $Id$
@ -40,7 +41,12 @@ public class LdapShaPasswordEncoder implements PasswordEncoder {
@@ -40,7 +41,12 @@ public class LdapShaPasswordEncoder implements PasswordEncoder {
/** The number of bytes in a SHA hash */
private static final int SHA_LENGTH = 20 ;
private static final String SSHA_PREFIX = "{SSHA}" ;
private static final String SSHA_PREFIX_LC = SSHA_PREFIX . toLowerCase ( ) ;
private static final String SHA_PREFIX = "{SHA}" ;
private static final String SHA_PREFIX_LC = SHA_PREFIX . toLowerCase ( ) ;
//~ Instance fields ================================================================================================
private boolean forceLowerCasePrefix ;
//~ Constructors ===================================================================================================
@ -76,7 +82,7 @@ public class LdapShaPasswordEncoder implements PasswordEncoder {
@@ -76,7 +82,7 @@ public class LdapShaPasswordEncoder implements PasswordEncoder {
try {
sha = MessageDigest . getInstance ( "SHA" ) ;
} catch ( java . security . NoSuchAlgorithmException e ) {
throw new LdapDataAccessException ( "No SHA implementation available!" ) ;
throw new LdapDataAccessException ( "No SHA implementation available!" , e ) ;
}
sha . update ( rawPass . getBytes ( ) ) ;
@ -88,7 +94,15 @@ public class LdapShaPasswordEncoder implements PasswordEncoder {
@@ -88,7 +94,15 @@ public class LdapShaPasswordEncoder implements PasswordEncoder {
byte [ ] hash = combineHashAndSalt ( sha . digest ( ) , ( byte [ ] ) salt ) ;
return ( ( salt = = null ) ? SHA_PREFIX : SSHA_PREFIX ) + new String ( Base64 . encodeBase64 ( hash ) ) ;
String prefix ;
if ( salt = = null ) {
prefix = forceLowerCasePrefix ? SHA_PREFIX_LC : SHA_PREFIX ;
} else {
prefix = forceLowerCasePrefix ? SSHA_PREFIX_LC : SSHA_PREFIX ;
}
return prefix + new String ( Base64 . encodeBase64 ( hash ) ) ;
}
private byte [ ] extractSalt ( String encPass ) {
@ -106,19 +120,28 @@ public class LdapShaPasswordEncoder implements PasswordEncoder {
@@ -106,19 +120,28 @@ public class LdapShaPasswordEncoder implements PasswordEncoder {
* Checks the validity of an unencoded password against an encoded one in the form
* "{SSHA}sQuQF8vj8Eg2Y1hPdh3bkQhCKQBgjhQI" .
*
* @param encPass the SSHA or SHA encoded password
* @param encPass the actual SSHA or SHA encoded password
* @param rawPass unencoded password to be verified .
* @param salt ignored . If the format is SSHA the salt bytes will be extracted from the encoded password .
*
* @return true if they match .
* @return true if they match ( independent of the case of the prefix ) .
* /
public boolean isPasswordValid ( String encPass , String rawPass , Object salt ) {
if ( encPass . startsWith ( SSHA_PREFIX ) ) {
String encPassWithoutPrefix ;
if ( encPass . startsWith ( SSHA_PREFIX ) | | encPass . startsWith ( SSHA_PREFIX_LC ) ) {
encPassWithoutPrefix = encPass . substring ( 6 ) ;
salt = extractSalt ( encPass ) ;
} else {
encPassWithoutPrefix = encPass . substring ( 5 ) ;
salt = null ;
}
return encPass . equals ( encodePassword ( rawPass , salt ) ) ;
// Compare the encoded passwords without the prefix
return encodePassword ( rawPass , salt ) . endsWith ( encPassWithoutPrefix ) ;
}
public void setForceLowerCasePrefix ( boolean forceLowerCasePrefix ) {
this . forceLowerCasePrefix = forceLowerCasePrefix ;
}
}