Browse Source

SEC-1890: Add checks for validity of stored bcrypt hash

When checking for a match, the BCryptPasswordEncoder validates
the stored hash against a pattern to check that it actually is
a bcrypt value.
pull/4/merge
Luke Taylor 14 years ago
parent
commit
3760d792ea
  1. 11
      crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoder.java
  2. 42
      crypto/src/test/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoderTests.java

11
crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoder.java

@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
package org.springframework.security.crypto.bcrypt;
import java.security.SecureRandom;
import java.util.regex.Pattern;
import org.springframework.security.crypto.password.PasswordEncoder;
@ -28,6 +29,7 @@ import org.springframework.security.crypto.password.PasswordEncoder; @@ -28,6 +29,7 @@ import org.springframework.security.crypto.password.PasswordEncoder;
*
*/
public class BCryptPasswordEncoder implements PasswordEncoder {
private Pattern BCRYPT_PATTERN = Pattern.compile("\\A\\$2a?\\$\\d\\d\\$[./0-9A-Za-z]{53}");
private final int strength;
@ -71,7 +73,14 @@ public class BCryptPasswordEncoder implements PasswordEncoder { @@ -71,7 +73,14 @@ public class BCryptPasswordEncoder implements PasswordEncoder {
}
public boolean matches(CharSequence rawPassword, String encodedPassword) {
if (encodedPassword == null || encodedPassword.length() == 0) {
throw new IllegalArgumentException("Encoded password cannot be null or empty");
}
if (!BCRYPT_PATTERN.matcher(encodedPassword).matches()) {
throw new IllegalArgumentException("Encoded password does not look like BCrypt");
}
return BCrypt.checkpw(rawPassword.toString(), encodedPassword);
}
}

42
crypto/src/test/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoderTests.java

@ -20,6 +20,8 @@ import static org.junit.Assert.assertTrue; @@ -20,6 +20,8 @@ import static org.junit.Assert.assertTrue;
import org.junit.Test;
import java.security.SecureRandom;
/**
* @author Dave Syer
@ -44,17 +46,49 @@ public class BCryptPasswordEncoderTests { @@ -44,17 +46,49 @@ public class BCryptPasswordEncoderTests {
}
@Test
public void matchesLengthChecked() {
public void notMatches() {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
String result = encoder.encode("password");
assertFalse(encoder.matches("password", result.substring(0,result.length()-2)));
assertFalse(encoder.matches("bogus", result));
}
@Test
public void notMatches() {
public void customStrength() {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(8);
String result = encoder.encode("password");
assertTrue(encoder.matches("password", result));
}
@Test
public void customRandom() {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(8, new SecureRandom());
String result = encoder.encode("password");
assertTrue(encoder.matches("password", result));
}
@Test(expected = IllegalArgumentException.class)
public void barfsOnNullEncodedValue() {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
assertFalse(encoder.matches("password", null));
}
@Test(expected = IllegalArgumentException.class)
public void barfsOnEmptyEncodedValue() {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
assertFalse(encoder.matches("password", ""));
}
@Test(expected = IllegalArgumentException.class)
public void barfsOnShortEncodedValue() {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
String result = encoder.encode("password");
assertFalse(encoder.matches("bogus", result));
assertFalse(encoder.matches("password", result.substring(0, 4)));
}
@Test(expected = IllegalArgumentException.class)
public void barfsOnBogusEncodedValue() {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
assertFalse(encoder.matches("password", "012345678901234567890123456789"));
}
}

Loading…
Cancel
Save