Browse Source

SEC-2122: Update namespace to support bcrypt.

password-encoder now supports hash='bcrypt'.
Luke Taylor 12 years ago
parent
commit
ebba8ac514

+ 12 - 4
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<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)) {

+ 2 - 2
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}

+ 6 - 6
config/src/main/resources/org/springframework/security/config/spring-security-3.2.xsd

@@ -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"/>

+ 29 - 0
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(" <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>" +

+ 1 - 0
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,