Pārlūkot izejas kodu

SEC-1432: Convert map keys to lower-case in UserMap.setUsers().

Otherwise the lookup on mixed-case fails, since the lookup is performed with a lower-case key.
Luke Taylor 15 gadi atpakaļ
vecāks
revīzija
b38b8e55ac

+ 1 - 1
config/src/main/java/org/springframework/security/config/authentication/UserServiceBeanDefinitionParser.java

@@ -58,7 +58,7 @@ public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceB
             return;
         }
 
-        if(CollectionUtils.isEmpty(userElts)) {
+        if (CollectionUtils.isEmpty(userElts)) {
             throw new BeanDefinitionStoreException("You must supply user definitions, either with <" + ELT_USER + "> child elements or a " +
                 "properties file (using the '" + ATT_PROPERTIES + "' attribute)" );
         }

+ 1 - 1
config/src/main/resources/org/springframework/security/config/spring-security-3.1.rnc

@@ -560,7 +560,7 @@ ap.attlist &=
     user-service-ref?
 
 user-service =
-    ## Creates an in-memory UserDetailsService from a properties file or a list of "user" child elements.
+    ## Creates an in-memory UserDetailsService from a properties file or a list of "user" child elements. Usernames are converted to lower-case internally to allow for case-insensitive lookups, so this should not be used if case-sensitivity is required.
     element user-service {id? & (properties-file | (user*))}
 properties-file =
     attribute properties {xsd:token}?

+ 15 - 2
config/src/test/java/org/springframework/security/config/authentication/UserServiceBeanDefinitionParserTests.java

@@ -72,21 +72,34 @@ public class UserServiceBeanDefinitionParserTests {
         Long.parseLong(joe.getPassword());
     }
 
+    @Test
+    public void worksWithOpenIDUrlsAsNames() {
+        setContext(
+                "<user-service id='service'>" +
+                "    <user name='http://joe.myopenid.com/' authorities='ROLE_A'/>" +
+                "    <user name='https://www.google.com/accounts/o8/id?id=MPtOaenBIk5yzW9n7n9' authorities='ROLE_A'/>" +
+                "</user-service>");
+        UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
+        assertEquals("http://joe.myopenid.com/", userService.loadUserByUsername("http://joe.myopenid.com/").getUsername());
+        assertEquals("https://www.google.com/accounts/o8/id?id=MPtOaenBIk5yzW9n7n9",
+                userService.loadUserByUsername("https://www.google.com/accounts/o8/id?id=MPtOaenBIk5yzW9n7n9").getUsername());
+    }
+
     @Test
     public void disabledAndEmbeddedFlagsAreSupported() {
         setContext(
                 "<user-service id='service'>" +
                 "    <user name='joe' password='joespassword' authorities='ROLE_A' locked='true'/>" +
-                "    <user name='bob' password='bobspassword' authorities='ROLE_A' disabled='true'/>" +
+                "    <user name='Bob' password='bobspassword' authorities='ROLE_A' disabled='true'/>" +
                 "</user-service>");
         UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
         UserDetails joe = userService.loadUserByUsername("joe");
         assertFalse(joe.isAccountNonLocked());
+        // Check case-sensitive lookup SEC-1432
         UserDetails bob = userService.loadUserByUsername("bob");
         assertFalse(bob.isEnabled());
     }
 
-
     @Test(expected=FatalBeanException.class)
     public void userWithBothPropertiesAndEmbeddedUsersThrowsException() {
         setContext(

+ 10 - 4
core/src/main/java/org/springframework/security/core/userdetails/memory/UserMap.java

@@ -18,15 +18,18 @@ package org.springframework.security.core.userdetails.memory;
 import java.util.HashMap;
 import java.util.Map;
 
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
 import org.springframework.util.Assert;
 
 
 /**
  * Used by {@link InMemoryDaoImpl} to store a list of users and their corresponding granted authorities.
+ * <p>
+ * Usernames are used as the lookup key and are stored in lower case, to allow case-insensitive lookups. So this class
+ * should not be used if usernames need to be case-sensitive.
  *
  * @author Ben Alex
  */
@@ -37,7 +40,7 @@ public class UserMap {
 
     //~ Instance fields ================================================================================================
 
-    private Map<String, UserDetails> userMap = new HashMap<String, UserDetails>();
+    private final Map<String, UserDetails> userMap = new HashMap<String, UserDetails>();
 
     //~ Methods ========================================================================================================
 
@@ -90,6 +93,9 @@ public class UserMap {
      * @since 1.1
      */
     public void setUsers(Map<String, UserDetails> users) {
-        this.userMap = users;
+        userMap.clear();
+        for (Map.Entry<String, UserDetails> entry : users.entrySet()) {
+            userMap.put(entry.getKey().toLowerCase(), entry.getValue());
+        }
     }
 }