diff --git a/config/src/main/java/org/springframework/security/config/authentication/PasswordEncoderParser.java b/config/src/main/java/org/springframework/security/config/authentication/PasswordEncoderParser.java index 5f8eb06423..c9b221636c 100644 --- a/config/src/main/java/org/springframework/security/config/authentication/PasswordEncoderParser.java +++ b/config/src/main/java/org/springframework/security/config/authentication/PasswordEncoderParser.java @@ -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> ENCODER_CLASSES; + private static final Map> ENCODER_CLASSES; static { - ENCODER_CLASSES = new HashMap>(); + ENCODER_CLASSES = new HashMap>(); 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 beanClass = ENCODER_CLASSES.get(hash); + Class beanClass = ENCODER_CLASSES.get(hash); BeanDefinitionBuilder beanBldr = BeanDefinitionBuilder.rootBeanDefinition(beanClass); if (OPT_HASH_SHA256.equals(hash)) { diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-3.2.rnc b/config/src/main/resources/org/springframework/security/config/spring-security-3.2.rnc index 2dbf05803a..1c79bac818 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-3.2.rnc +++ b/config/src/main/resources/org/springframework/security/config/spring-security-3.2.rnc @@ -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} diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-3.2.xsd b/config/src/main/resources/org/springframework/security/config/spring-security-3.2.xsd index 719d9a3569..cfd12a6618 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-3.2.xsd +++ b/config/src/main/resources/org/springframework/security/config/spring-security-3.2.xsd @@ -6,12 +6,12 @@ - Defines the hashing algorithm used on user passwords. We recommend strongly against using - MD4, as it is a very weak hashing algorithm. + Defines the hashing algorithm used on user passwords. Bcrypt is recommended. + @@ -154,12 +154,12 @@ - Defines the hashing algorithm used on user passwords. We recommend strongly against using - MD4, as it is a very weak hashing algorithm. + Defines the hashing algorithm used on user passwords. Bcrypt is recommended. + @@ -537,12 +537,12 @@ - Defines the hashing algorithm used on user passwords. We recommend strongly against using - MD4, as it is a very weak hashing algorithm. + Defines the hashing algorithm used on user passwords. Bcrypt is recommended. + diff --git a/config/src/test/java/org/springframework/security/config/authentication/AuthenticationProviderBeanDefinitionParserTests.java b/config/src/test/java/org/springframework/security/config/authentication/AuthenticationProviderBeanDefinitionParserTests.java index d99d146a93..ea6496ed89 100644 --- a/config/src/test/java/org/springframework/security/config/authentication/AuthenticationProviderBeanDefinitionParserTests.java +++ b/config/src/test/java/org/springframework/security/config/authentication/AuthenticationProviderBeanDefinitionParserTests.java @@ -57,6 +57,35 @@ public class AuthenticationProviderBeanDefinitionParserTests { getProvider().authenticate(bob); } + @Test + public void providerWithBCryptPasswordEncoderWorks() throws Exception { + setContext(" " + + " " + + " " + + " " + + " " + + " "); + + getProvider().authenticate(bob); + } + + @Test(expected=BeanDefinitionParsingException.class) + public void bCryptAndSaltSourceRaisesException() throws Exception { + appContext = new InMemoryXmlApplicationContext("" + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " "); + } @Test public void providerWithMd5PasswordEncoderWorks() throws Exception { setContext(" " + diff --git a/config/template.mf b/config/template.mf index cc76467216..df0bd3a577 100644 --- a/config/template.mf +++ b/config/template.mf @@ -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,