SEC-2122: Update namespace to support bcrypt.

password-encoder now supports hash='bcrypt'.
This commit is contained in:
Luke Taylor 2013-05-17 19:17:18 +01:00
parent 896339087f
commit ebba8ac514
5 changed files with 50 additions and 12 deletions

View File

@ -19,6 +19,7 @@ import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.security.authentication.encoding.PlaintextPasswordEncoder;
import org.springframework.security.authentication.encoding.ShaPasswordEncoder;
import org.springframework.security.config.Elements;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
@ -34,6 +35,7 @@ public class PasswordEncoderParser {
static final String ATT_REF = "ref";
public static final String ATT_HASH = "hash";
static final String ATT_BASE_64 = "base64";
static final String OPT_HASH_BCRYPT = "bcrypt";
static final String OPT_HASH_PLAINTEXT = "plaintext";
static final String OPT_HASH_SHA = "sha";
static final String OPT_HASH_SHA256 = "sha-256";
@ -42,11 +44,12 @@ public class PasswordEncoderParser {
static final String OPT_HASH_LDAP_SHA = "{sha}";
static final String OPT_HASH_LDAP_SSHA = "{ssha}";
private static final Map<String, Class<? extends PasswordEncoder>> ENCODER_CLASSES;
private static final Map<String, Class<?>> ENCODER_CLASSES;
static {
ENCODER_CLASSES = new HashMap<String, Class<? extends PasswordEncoder>>();
ENCODER_CLASSES = new HashMap<String, Class<?>>();
ENCODER_CLASSES.put(OPT_HASH_PLAINTEXT, PlaintextPasswordEncoder.class);
ENCODER_CLASSES.put(OPT_HASH_BCRYPT, BCryptPasswordEncoder.class);
ENCODER_CLASSES.put(OPT_HASH_SHA, ShaPasswordEncoder.class);
ENCODER_CLASSES.put(OPT_HASH_SHA256, ShaPasswordEncoder.class);
ENCODER_CLASSES.put(OPT_HASH_MD4, Md4PasswordEncoder.class);
@ -84,12 +87,17 @@ public class PasswordEncoderParser {
Element saltSourceElt = DomUtils.getChildElementByTagName(element, Elements.SALT_SOURCE);
if (saltSourceElt != null) {
saltSource = new SaltSourceBeanDefinitionParser().parse(saltSourceElt, parserContext);
if (OPT_HASH_BCRYPT.equals(hash)) {
parserContext.getReaderContext().error(Elements.SALT_SOURCE + " isn't compatible with bcrypt",
parserContext.extractSource(saltSourceElt));
} else {
saltSource = new SaltSourceBeanDefinitionParser().parse(saltSourceElt, parserContext);
}
}
}
public static BeanDefinition createPasswordEncoderBeanDefinition(String hash, boolean useBase64) {
Class<? extends PasswordEncoder> beanClass = ENCODER_CLASSES.get(hash);
Class<?> beanClass = ENCODER_CLASSES.get(hash);
BeanDefinitionBuilder beanBldr = BeanDefinitionBuilder.rootBeanDefinition(beanClass);
if (OPT_HASH_SHA256.equals(hash)) {

View File

@ -6,8 +6,8 @@ default namespace = "http://www.springframework.org/schema/security"
start = http | ldap-server | authentication-provider | ldap-authentication-provider | any-user-service | ldap-server | ldap-authentication-provider
hash =
## Defines the hashing algorithm used on user passwords. We recommend strongly against using MD4, as it is a very weak hashing algorithm.
attribute hash {"plaintext" | "sha" | "sha-256" | "md5" | "md4" | "{sha}" | "{ssha}"}
## Defines the hashing algorithm used on user passwords. Bcrypt is recommended.
attribute hash {"bcrypt" | "plaintext" | "sha" | "sha-256" | "md5" | "md4" | "{sha}" | "{ssha}"}
base64 =
## Whether a string should be base64 encoded
attribute base64 {xsd:boolean}

View File

@ -6,12 +6,12 @@
<xs:attributeGroup name="hash">
<xs:attribute name="hash" use="required">
<xs:annotation>
<xs:documentation>Defines the hashing algorithm used on user passwords. We recommend strongly against using
MD4, as it is a very weak hashing algorithm.
<xs:documentation>Defines the hashing algorithm used on user passwords. Bcrypt is recommended.
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="bcrypt"/>
<xs:enumeration value="plaintext"/>
<xs:enumeration value="sha"/>
<xs:enumeration value="sha-256"/>
@ -154,12 +154,12 @@
</xs:attribute>
<xs:attribute name="hash">
<xs:annotation>
<xs:documentation>Defines the hashing algorithm used on user passwords. We recommend strongly against using
MD4, as it is a very weak hashing algorithm.
<xs:documentation>Defines the hashing algorithm used on user passwords. Bcrypt is recommended.
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="bcrypt"/>
<xs:enumeration value="plaintext"/>
<xs:enumeration value="sha"/>
<xs:enumeration value="sha-256"/>
@ -537,12 +537,12 @@
</xs:attribute>
<xs:attribute name="hash">
<xs:annotation>
<xs:documentation>Defines the hashing algorithm used on user passwords. We recommend strongly against using
MD4, as it is a very weak hashing algorithm.
<xs:documentation>Defines the hashing algorithm used on user passwords. Bcrypt is recommended.
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="bcrypt"/>
<xs:enumeration value="plaintext"/>
<xs:enumeration value="sha"/>
<xs:enumeration value="sha-256"/>

View File

@ -57,6 +57,35 @@ public class AuthenticationProviderBeanDefinitionParserTests {
getProvider().authenticate(bob);
}
@Test
public void providerWithBCryptPasswordEncoderWorks() throws Exception {
setContext(" <authentication-provider>" +
" <password-encoder hash='bcrypt'/>" +
" <user-service>" +
" <user name='bob' password='$2a$05$dRmjl1T05J7rvCPD2NgsHesCEJHww3pdmesUhjM3PD4m/gaEYyx/G' authorities='ROLE_A' />" +
" </user-service>" +
" </authentication-provider>");
getProvider().authenticate(bob);
}
@Test(expected=BeanDefinitionParsingException.class)
public void bCryptAndSaltSourceRaisesException() throws Exception {
appContext = new InMemoryXmlApplicationContext("" +
" <authentication-manager>" +
" <authentication-provider>" +
" <password-encoder hash='bcrypt'>" +
" <salt-source ref='saltSource'/>" +
" </password-encoder>" +
" <user-service>" +
" <user name='bob' password='$2a$05$dRmjl1T05J7rvCPD2NgsHesCEJHww3pdmesUhjM3PD4m/gaEYyx/G' authorities='ROLE_A' />" +
" </user-service>" +
" </authentication-provider>" +
" </authentication-manager>" +
" <b:bean id='saltSource' class='" + ReflectionSaltSource.class.getName() +"'>" +
" <b:property name='userPropertyToUse' value='username'/>" +
" </b:bean>");
}
@Test
public void providerWithMd5PasswordEncoderWorks() throws Exception {
setContext(" <authentication-provider>" +

View File

@ -14,6 +14,7 @@ Import-Template:
org.springframework.security.access.*;version="${secRange}",
org.springframework.security.authentication.*;version="${secRange}",
org.springframework.security.core.*;version="${secRange}",
org.springframework.security.crypto.bcrypt.*;version="${secRange}",
org.springframework.security.util;version="${secRange}",
org.springframework.security.provisioning;version="${secRange}",
org.springframework.security.web.*;version="${secRange}";resolution:=optional,