From cdc992b132d34c0e119040a09ad6c0b939b9e7e1 Mon Sep 17 00:00:00 2001 From: Rob Winch Date: Sun, 22 Oct 2017 20:55:56 -0500 Subject: [PATCH] Remove SaltSource Fixes gh-4681 --- .../security/config/Elements.java | 1 - ...nticationProviderBeanDefinitionParser.java | 5 - .../authentication/PasswordEncoderParser.java | 23 ---- .../SaltSourceBeanDefinitionParser.java | 74 ----------- .../LdapProviderBeanDefinitionParser.java | 6 - .../security/config/spring-security-5.0.rnc | 12 +- .../security/config/spring-security-5.0.xsd | 78 ----------- ...tionProviderBeanDefinitionParserTests.java | 20 --- .../dao/DaoAuthenticationProvider.java | 28 ---- .../dao/ReflectionSaltSource.java | 122 ------------------ .../authentication/dao/SaltSource.java | 38 ------ .../dao/SystemWideSaltSource.java | 70 ---------- .../dao/DaoAuthenticationProviderTests.java | 4 - .../dao/salt/ReflectionSaltSourceTests.java | 68 ---------- .../dao/salt/SystemWideSaltSourceTests.java | 76 ----------- docs/manual/src/docs/asciidoc/index.adoc | 47 +------ 16 files changed, 2 insertions(+), 670 deletions(-) delete mode 100644 config/src/main/java/org/springframework/security/config/authentication/SaltSourceBeanDefinitionParser.java delete mode 100644 core/src/main/java/org/springframework/security/authentication/dao/ReflectionSaltSource.java delete mode 100644 core/src/main/java/org/springframework/security/authentication/dao/SaltSource.java delete mode 100644 core/src/main/java/org/springframework/security/authentication/dao/SystemWideSaltSource.java delete mode 100644 core/src/test/java/org/springframework/security/authentication/dao/salt/ReflectionSaltSourceTests.java delete mode 100644 core/src/test/java/org/springframework/security/authentication/dao/salt/SystemWideSaltSourceTests.java diff --git a/config/src/main/java/org/springframework/security/config/Elements.java b/config/src/main/java/org/springframework/security/config/Elements.java index 5b18cc73c9..f551483668 100644 --- a/config/src/main/java/org/springframework/security/config/Elements.java +++ b/config/src/main/java/org/springframework/security/config/Elements.java @@ -55,7 +55,6 @@ public abstract class Elements { public static final String FILTER_CHAIN = "filter-chain"; public static final String GLOBAL_METHOD_SECURITY = "global-method-security"; public static final String PASSWORD_ENCODER = "password-encoder"; - public static final String SALT_SOURCE = "salt-source"; public static final String PORT_MAPPINGS = "port-mappings"; public static final String PORT_MAPPING = "port-mapping"; public static final String CUSTOM_FILTER = "custom-filter"; diff --git a/config/src/main/java/org/springframework/security/config/authentication/AuthenticationProviderBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/authentication/AuthenticationProviderBeanDefinitionParser.java index 762f1046fd..a044afdff6 100644 --- a/config/src/main/java/org/springframework/security/config/authentication/AuthenticationProviderBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/authentication/AuthenticationProviderBeanDefinitionParser.java @@ -47,11 +47,6 @@ public class AuthenticationProviderBeanDefinitionParser implements BeanDefinitio PasswordEncoderParser pep = new PasswordEncoderParser(passwordEncoderElt, pc); authProvider.getPropertyValues().addPropertyValue("passwordEncoder", pep.getPasswordEncoder()); - - if (pep.getSaltSource() != null) { - authProvider.getPropertyValues().addPropertyValue("saltSource", - pep.getSaltSource()); - } } Element userServiceElt = DomUtils.getChildElementByTagName(element, 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 9872aa7844..1f2c766364 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 @@ -14,7 +14,6 @@ * limitations under the License. */ package org.springframework.security.config.authentication; - import java.util.HashMap; import java.util.Map; @@ -35,8 +34,6 @@ import org.w3c.dom.Element; /** * Stateful parser for the <password-encoder> element. * - * Will produce a PasswordEncoder and (optionally) a SaltSource. - * * @author Luke Taylor */ public class PasswordEncoderParser { @@ -55,7 +52,6 @@ public class PasswordEncoderParser { private static final Log logger = LogFactory.getLog(PasswordEncoderParser.class); private BeanMetadataElement passwordEncoder; - private BeanMetadataElement saltSource; public PasswordEncoderParser(Element element, ParserContext parserContext) { parse(element, parserContext); @@ -79,21 +75,6 @@ public class PasswordEncoderParser { ((RootBeanDefinition) passwordEncoder).setSource(parserContext .extractSource(element)); } - - Element saltSourceElt = DomUtils.getChildElementByTagName(element, - Elements.SALT_SOURCE); - - if (saltSourceElt != null) { - 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, @@ -107,8 +88,4 @@ public class PasswordEncoderParser { public BeanMetadataElement getPasswordEncoder() { return passwordEncoder; } - - public BeanMetadataElement getSaltSource() { - return saltSource; - } } diff --git a/config/src/main/java/org/springframework/security/config/authentication/SaltSourceBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/authentication/SaltSourceBeanDefinitionParser.java deleted file mode 100644 index 97ba2eec3a..0000000000 --- a/config/src/main/java/org/springframework/security/config/authentication/SaltSourceBeanDefinitionParser.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2002-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.security.config.authentication; - -import org.springframework.beans.BeanMetadataElement; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.RuntimeBeanReference; -import org.springframework.beans.factory.support.RootBeanDefinition; -import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.security.authentication.dao.ReflectionSaltSource; -import org.springframework.security.authentication.dao.SystemWideSaltSource; -import org.springframework.security.config.Elements; -import org.springframework.util.StringUtils; -import org.w3c.dom.Element; - -/** - * @author Luke Taylor - * @since 2.0 - */ -class SaltSourceBeanDefinitionParser { - private static final String ATT_USER_PROPERTY = "user-property"; - private static final String ATT_REF = "ref"; - private static final String ATT_SYSTEM_WIDE = "system-wide"; - - public BeanMetadataElement parse(Element element, ParserContext parserContext) { - String ref = element.getAttribute(ATT_REF); - - if (StringUtils.hasText(ref)) { - return new RuntimeBeanReference(ref); - } - - String userProperty = element.getAttribute(ATT_USER_PROPERTY); - RootBeanDefinition saltSource; - - if (StringUtils.hasText(userProperty)) { - saltSource = new RootBeanDefinition(ReflectionSaltSource.class); - saltSource.getPropertyValues().addPropertyValue("userPropertyToUse", - userProperty); - saltSource.setSource(parserContext.extractSource(element)); - saltSource.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - - return saltSource; - } - - String systemWideSalt = element.getAttribute(ATT_SYSTEM_WIDE); - - if (StringUtils.hasText(systemWideSalt)) { - saltSource = new RootBeanDefinition(SystemWideSaltSource.class); - saltSource.getPropertyValues().addPropertyValue("systemWideSalt", - systemWideSalt); - saltSource.setSource(parserContext.extractSource(element)); - saltSource.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - - return saltSource; - } - - parserContext.getReaderContext().error( - Elements.SALT_SOURCE + " requires an attribute", element); - return null; - } -} diff --git a/config/src/main/java/org/springframework/security/config/ldap/LdapProviderBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/ldap/LdapProviderBeanDefinitionParser.java index 4218a808b5..c11b2b4c31 100644 --- a/config/src/main/java/org/springframework/security/config/ldap/LdapProviderBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/ldap/LdapProviderBeanDefinitionParser.java @@ -103,12 +103,6 @@ public class LdapProviderBeanDefinitionParser implements BeanDefinitionParser { passwordEncoderElement, parserContext); authenticatorBuilder.addPropertyValue("passwordEncoder", pep.getPasswordEncoder()); - - if (pep.getSaltSource() != null) { - parserContext.getReaderContext().warning( - "Salt source information isn't valid when used with LDAP", - passwordEncoderElement); - } } else if (StringUtils.hasText(hash)) { authenticatorBuilder.addPropertyValue("passwordEncoder", diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-5.0.rnc b/config/src/main/resources/org/springframework/security/config/spring-security-5.0.rnc index 012b648f51..7745be394b 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-5.0.rnc +++ b/config/src/main/resources/org/springframework/security/config/spring-security-5.0.rnc @@ -54,20 +54,10 @@ debug = password-encoder = ## element which defines a password encoding strategy. Used by an authentication provider to convert submitted passwords to hashed versions, for example. - element password-encoder {password-encoder.attlist, salt-source?} + element password-encoder {password-encoder.attlist} password-encoder.attlist &= ref | (hash) -salt-source = - ## Password salting strategy. A system-wide constant or a property from the UserDetails object can be used. - element salt-source {user-property | system-wide | ref} -user-property = - ## A property of the UserDetails object which will be used as salt by a password encoder. Typically something like "username" might be used. - attribute user-property {xsd:token} -system-wide = - ## A single value that will be used as the salt for a password encoder. - attribute system-wide {xsd:token} - role-prefix = ## A non-empty string prefix that will be added to role strings loaded from persistent storage (e.g. "ROLE_"). Use the value "none" for no prefix in cases where the default is non-empty. attribute role-prefix {xsd:token} diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-5.0.xsd b/config/src/main/resources/org/springframework/security/config/spring-security-5.0.xsd index f8bf5dd19e..f33766f530 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-5.0.xsd +++ b/config/src/main/resources/org/springframework/security/config/spring-security-5.0.xsd @@ -144,24 +144,6 @@ - - - - - A property of the UserDetails object which will be used as salt by a password encoder. - Typically something like "username" might be used. - - - - - - - - A single value that will be used as the salt for a password encoder. - - - - @@ -2007,36 +1989,6 @@ - - - - Password salting strategy. A system-wide constant or a property from the UserDetails - object can be used. - - - - - - A property of the UserDetails object which will be used as salt by a password encoder. - Typically something like "username" might be used. - - - - - - A single value that will be used as the salt for a password encoder. - - - - - - Defines a reference to a Spring bean Id. - - - - - - @@ -2066,36 +2018,6 @@ - - - - Password salting strategy. A system-wide constant or a property from the UserDetails - object can be used. - - - - - - A property of the UserDetails object which will be used as salt by a password encoder. - Typically something like "username" might be used. - - - - - - A single value that will be used as the salt for a password encoder. - - - - - - Defines a reference to a Spring bean Id. - - - - - - 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 5fcbc7a872..48bab47fc6 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 @@ -18,7 +18,6 @@ package org.springframework.security.config.authentication; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.ProviderManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.authentication.dao.ReflectionSaltSource; import org.springframework.security.config.BeanIds; import org.springframework.security.config.util.InMemoryXmlApplicationContext; import org.springframework.security.crypto.password.LdapShaPasswordEncoder; @@ -80,25 +79,6 @@ public class AuthenticationProviderBeanDefinitionParserTests { getProvider().authenticate(bob); } - @Test(expected = BeanDefinitionParsingException.class) - public void bCryptAndSaltSourceRaisesException() throws Exception { - appContext = new InMemoryXmlApplicationContext( - "" - + " " - + " " - + " " - + " " - + " " - + " " - + " " - + " " + " " - + " " - + " " - + " " - + " "); - } - @Test public void providerWithMd5PasswordEncoderWorks() throws Exception { appContext = new InMemoryXmlApplicationContext( diff --git a/core/src/main/java/org/springframework/security/authentication/dao/DaoAuthenticationProvider.java b/core/src/main/java/org/springframework/security/authentication/dao/DaoAuthenticationProvider.java index dddedc059a..b413b5d4a2 100644 --- a/core/src/main/java/org/springframework/security/authentication/dao/DaoAuthenticationProvider.java +++ b/core/src/main/java/org/springframework/security/authentication/dao/DaoAuthenticationProvider.java @@ -60,8 +60,6 @@ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthentication */ private String userNotFoundEncodedPassword; - private SaltSource saltSource; - private UserDetailsService userDetailsService; public DaoAuthenticationProvider() { @@ -75,12 +73,6 @@ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthentication protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { - Object salt = null; - - if (this.saltSource != null) { - salt = this.saltSource.getSalt(userDetails); - } - if (authentication.getCredentials() == null) { logger.debug("Authentication failed: no credentials provided"); @@ -155,26 +147,6 @@ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthentication return passwordEncoder; } - /** - * The source of salts to use when decoding passwords. null is a valid - * value, meaning the DaoAuthenticationProvider will present - * null to the relevant PasswordEncoder. - *

- * Instead, it is recommended that you use an encoder which uses a random salt and - * combines it with the password field. This is the default approach taken in the - * {@code org.springframework.security.crypto.password} package. - * - * @param saltSource to use when attempting to decode passwords via the - * PasswordEncoder - */ - public void setSaltSource(SaltSource saltSource) { - this.saltSource = saltSource; - } - - protected SaltSource getSaltSource() { - return saltSource; - } - public void setUserDetailsService(UserDetailsService userDetailsService) { this.userDetailsService = userDetailsService; } diff --git a/core/src/main/java/org/springframework/security/authentication/dao/ReflectionSaltSource.java b/core/src/main/java/org/springframework/security/authentication/dao/ReflectionSaltSource.java deleted file mode 100644 index fa1cfc0690..0000000000 --- a/core/src/main/java/org/springframework/security/authentication/dao/ReflectionSaltSource.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.authentication.dao; - -import org.springframework.security.authentication.AuthenticationServiceException; -import org.springframework.security.core.userdetails.UserDetails; - -import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.BeanUtils; -import org.springframework.util.ReflectionUtils; -import org.springframework.util.Assert; - -import java.lang.reflect.Method; -import java.beans.PropertyDescriptor; - -/** - * Obtains a salt from a specified property of the - * {@link org.springframework.security.core.userdetails.User} object. - *

- * This allows you to subclass User and provide an additional bean getter for - * a salt. You should use a synthetic value that does not change, such as a database - * primary key. Do not use username if it is likely to change. - * - * @author Ben Alex - */ -public class ReflectionSaltSource implements SaltSource, InitializingBean { - // ~ Instance fields - // ================================================================================================ - - private String userPropertyToUse; - - // ~ Methods - // ======================================================================================================== - - public void afterPropertiesSet() throws Exception { - Assert.hasText(userPropertyToUse, "A userPropertyToUse must be set"); - } - - /** - * Performs reflection on the passed User to obtain the salt. - *

- * The property identified by userPropertyToUse must be available from - * the passed User object. If it is not available, an - * {@link AuthenticationServiceException} will be thrown. - * - * @param user which contains the method identified by userPropertyToUse - * - * @return the result of invoking user.userPropertyToUse(), or if the method - * doesn't exist, user.getUserPropertyToUse(). - * - * @throws AuthenticationServiceException if reflection fails - */ - public Object getSalt(UserDetails user) { - Method saltMethod = findSaltMethod(user); - - try { - return saltMethod.invoke(user); - } - catch (Exception exception) { - throw new AuthenticationServiceException(exception.getMessage(), exception); - } - } - - private Method findSaltMethod(UserDetails user) { - Method saltMethod = ReflectionUtils.findMethod(user.getClass(), - userPropertyToUse, new Class[0]); - - if (saltMethod == null) { - PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(user.getClass(), - userPropertyToUse); - - if (pd != null) { - saltMethod = pd.getReadMethod(); - } - - if (saltMethod == null) { - throw new AuthenticationServiceException( - "Unable to find salt method on user Object. Does the class '" - + user.getClass().getName() - + "' have a method or getter named '" + userPropertyToUse - + "' ?"); - } - } - - return saltMethod; - } - - protected String getUserPropertyToUse() { - return userPropertyToUse; - } - - /** - * The method name to call to obtain the salt. Can be either a method name or a bean - * property name. If your UserDetails contains a - * UserDetails.getSalt() method, you should set this property to - * "getSalt" or "salt". - * - * @param userPropertyToUse the name of the getter to call to obtain the salt - * from the UserDetails - */ - public void setUserPropertyToUse(String userPropertyToUse) { - this.userPropertyToUse = userPropertyToUse; - } - - public String toString() { - return "ReflectionSaltSource[ userPropertyToUse='" + userPropertyToUse + "'; ]"; - } -} diff --git a/core/src/main/java/org/springframework/security/authentication/dao/SaltSource.java b/core/src/main/java/org/springframework/security/authentication/dao/SaltSource.java deleted file mode 100644 index a800a36844..0000000000 --- a/core/src/main/java/org/springframework/security/authentication/dao/SaltSource.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.authentication.dao; - -import org.springframework.security.core.userdetails.UserDetails; - -/** - * Provides alternative sources of the salt to use for encoding passwords. - * - * @author Ben Alex - */ -public interface SaltSource { - // ~ Methods - // ======================================================================================================== - - /** - * Returns the salt to use for the indicated user. - * - * @param user from the AuthenticationDao - * - * @return the salt to use for this UserDetails - */ - Object getSalt(UserDetails user); -} diff --git a/core/src/main/java/org/springframework/security/authentication/dao/SystemWideSaltSource.java b/core/src/main/java/org/springframework/security/authentication/dao/SystemWideSaltSource.java deleted file mode 100644 index cea85fbb77..0000000000 --- a/core/src/main/java/org/springframework/security/authentication/dao/SystemWideSaltSource.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.authentication.dao; - -import org.springframework.security.core.userdetails.UserDetails; - -import org.springframework.beans.factory.InitializingBean; - -/** - * Uses a static system-wide String as the salt. - *

- * Does not supply a different salt for each - * {@link org.springframework.security.core.userdetails.User}. This means users sharing - * the same password will still have the same digested password. Of benefit is the - * digested passwords will at least be more protected than if stored without any salt. - *

- * - * @author Ben Alex - */ -public class SystemWideSaltSource implements SaltSource, InitializingBean { - // ~ Instance fields - // ================================================================================================ - - private String systemWideSalt; - - // ~ Methods - // ======================================================================================================== - - public void afterPropertiesSet() throws Exception { - if ((this.systemWideSalt == null) || "".equals(this.systemWideSalt)) { - throw new IllegalArgumentException("A systemWideSalt must be set"); - } - } - - public Object getSalt(UserDetails user) { - return this.systemWideSalt; - } - - public String getSystemWideSalt() { - return this.systemWideSalt; - } - - public void setSystemWideSalt(String systemWideSalt) { - this.systemWideSalt = systemWideSalt; - } - - /** - * Displays the system wide salt - * @since 4.0 - * @return - */ - @Override - public String toString() { - return systemWideSalt; - } -} diff --git a/core/src/test/java/org/springframework/security/authentication/dao/DaoAuthenticationProviderTests.java b/core/src/test/java/org/springframework/security/authentication/dao/DaoAuthenticationProviderTests.java index bc360853af..7a6dc2c875 100644 --- a/core/src/test/java/org/springframework/security/authentication/dao/DaoAuthenticationProviderTests.java +++ b/core/src/test/java/org/springframework/security/authentication/dao/DaoAuthenticationProviderTests.java @@ -394,10 +394,6 @@ public class DaoAuthenticationProviderTests { assertThat(provider.getPasswordEncoder().getClass()).isEqualTo( BCryptPasswordEncoder.class); - provider.setSaltSource(new SystemWideSaltSource()); - assertThat(provider.getSaltSource().getClass()).isEqualTo( - SystemWideSaltSource.class); - provider.setUserCache(new EhCacheBasedUserCache()); assertThat(provider.getUserCache().getClass()).isEqualTo( EhCacheBasedUserCache.class); diff --git a/core/src/test/java/org/springframework/security/authentication/dao/salt/ReflectionSaltSourceTests.java b/core/src/test/java/org/springframework/security/authentication/dao/salt/ReflectionSaltSourceTests.java deleted file mode 100644 index 42be12644d..0000000000 --- a/core/src/test/java/org/springframework/security/authentication/dao/salt/ReflectionSaltSourceTests.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.authentication.dao.salt; - -import static org.assertj.core.api.Assertions.*; - -import org.junit.Test; -import org.springframework.security.authentication.AuthenticationServiceException; -import org.springframework.security.authentication.dao.ReflectionSaltSource; -import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetails; - -/** - * Tests {@link ReflectionSaltSource}. - * - * @author Ben Alex - */ -public class ReflectionSaltSourceTests { - private UserDetails user = new User("scott", "wombat", true, true, true, true, - AuthorityUtils.createAuthorityList("HOLDER")); - - // ~ Methods - // ======================================================================================================== - - @Test(expected = IllegalArgumentException.class) - public void detectsMissingUserPropertyToUse() throws Exception { - ReflectionSaltSource saltSource = new ReflectionSaltSource(); - saltSource.afterPropertiesSet(); - } - - @Test(expected = AuthenticationServiceException.class) - public void exceptionIsThrownWhenInvalidPropertyRequested() throws Exception { - ReflectionSaltSource saltSource = new ReflectionSaltSource(); - saltSource.setUserPropertyToUse("getDoesNotExist"); - saltSource.afterPropertiesSet(); - saltSource.getSalt(user); - } - - @Test - public void methodNameAsPropertyToUseReturnsCorrectSaltValue() { - ReflectionSaltSource saltSource = new ReflectionSaltSource(); - saltSource.setUserPropertyToUse("getUsername"); - - assertThat(saltSource.getSalt(user)).isEqualTo("scott"); - } - - @Test - public void propertyNameAsPropertyToUseReturnsCorrectSaltValue() { - ReflectionSaltSource saltSource = new ReflectionSaltSource(); - saltSource.setUserPropertyToUse("password"); - assertThat(saltSource.getSalt(user)).isEqualTo("wombat"); - } -} diff --git a/core/src/test/java/org/springframework/security/authentication/dao/salt/SystemWideSaltSourceTests.java b/core/src/test/java/org/springframework/security/authentication/dao/salt/SystemWideSaltSourceTests.java deleted file mode 100644 index 73e281e004..0000000000 --- a/core/src/test/java/org/springframework/security/authentication/dao/salt/SystemWideSaltSourceTests.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.authentication.dao.salt; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; - -import org.junit.Test; -import org.springframework.security.authentication.dao.SystemWideSaltSource; - -/** - * Tests {@link SystemWideSaltSource}. - * - * @author Ben Alex - */ -public class SystemWideSaltSourceTests { - // ~ Constructors - // =================================================================================================== - - public SystemWideSaltSourceTests() { - super(); - } - - // ~ Methods - // ======================================================================================================== - @Test - public void testDetectsMissingSystemWideSalt() throws Exception { - SystemWideSaltSource saltSource = new SystemWideSaltSource(); - - try { - saltSource.afterPropertiesSet(); - fail("Should have thrown IllegalArgumentException"); - } - catch (IllegalArgumentException expected) { - assertThat(expected.getMessage()).isEqualTo("A systemWideSalt must be set"); - } - } - - @Test - public void testGettersSetters() { - SystemWideSaltSource saltSource = new SystemWideSaltSource(); - saltSource.setSystemWideSalt("helloWorld"); - assertThat(saltSource.getSystemWideSalt()).isEqualTo("helloWorld"); - } - - @Test - public void testNormalOperation() throws Exception { - SystemWideSaltSource saltSource = new SystemWideSaltSource(); - saltSource.setSystemWideSalt("helloWorld"); - saltSource.afterPropertiesSet(); - assertThat(saltSource.getSalt(null)).isEqualTo("helloWorld"); - } - - // SEC-2173 - @Test - public void testToString() { - String systemWideSalt = "helloWorld"; - SystemWideSaltSource saltSource = new SystemWideSaltSource(); - saltSource.setSystemWideSalt(systemWideSalt); - assertThat(saltSource.toString()).isEqualTo(systemWideSalt); - } -} diff --git a/docs/manual/src/docs/asciidoc/index.adoc b/docs/manual/src/docs/asciidoc/index.adoc index df8d3d9416..728947ba5c 100644 --- a/docs/manual/src/docs/asciidoc/index.adoc +++ b/docs/manual/src/docs/asciidoc/index.adoc @@ -2515,11 +2515,6 @@ One potential problem with the use of password hashes that it is relatively easy Bcrypt automatically generates a random salt value for each password when it is encoded, and stores it in the bcrypt string in a standard format. -[NOTE] -==== -The legacy approach to handling salt was to inject a `SaltSource` into the `DaoAuthenticationProvider`, which would obtain a salt value for a particular user and pass it to the `PasswordEncoder`. Using bcrypt means you don't have worry about the details of salt handling (such as where the value is stored), as it is all done internally. So we'd strongly recommend you use bcrypt unless you already have a system in place which stores the salt separately. -==== - ==== Hashing and Authentication When an authentication provider (such as Spring Security's `DaoAuthenticationProvider`) needs to check the password in a submitted authentication request against the known value for a user, and the stored password is encoded in some way, then the submitted value must be encoded using exactly the same algorithm. It's up to you to check that these are compatible as Spring Security has no control over the persistent values. If you add password hashing to your authentication configuration in Spring Security, and your database contains plaintext passwords, then there is no way authentication can succeed. Even if you are aware that your database is using MD5 to encode the passwords, for example, and your application is configured to use Spring Security's `Md5PasswordEncoder`, there are still things that can go wrong. The database may have the passwords encoded in Base 64, for example while the encoder is using hexadecimal strings (the default). Alternatively your database may be using upper-case while the output from the encoder is lower-case. Make sure you write a test to check the output from your configured password encoder with a known password and salt combination and check that it matches the database value before going further and attempting to authenticate through your application. Using a standard like bcrypt will avoid these issues. @@ -9169,7 +9164,7 @@ select username, password, enabled from users where username = ? [[nsa-password-encoder]] ==== -Authentication providers can optionally be configured to use a password encoder as described in the <>. This will result in the bean being injected with the appropriate `PasswordEncoder` instance, potentially with an accompanying `SaltSource` bean to provide salt values for hashing. +Authentication providers can optionally be configured to use a password encoder as described in the <>. This will result in the bean being injected with the appropriate `PasswordEncoder` instance. [[nsa-password-encoder-parents]] @@ -9195,46 +9190,6 @@ Defines the hashing algorithm used on user passwords. We recommend strongly agai Defines a reference to a Spring bean that implements `PasswordEncoder`. -[[nsa-password-encoder-children]] -===== Child Elements of - - -* <> - - - -[[nsa-salt-source]] -==== -Password salting strategy. A system-wide constant or a property from the UserDetails object can be used. - - -[[nsa-salt-source-parents]] -===== Parent Elements of - - -* <> - - - -[[nsa-salt-source-attributes]] -===== Attributes - - -[[nsa-salt-source-ref]] -* **ref** -Defines a reference to a Spring bean Id. - - -[[nsa-salt-source-system-wide]] -* **system-wide** -A single value that will be used as the salt for a password encoder. - - -[[nsa-salt-source-user-property]] -* **user-property** -A property of the UserDetails object which will be used as salt by a password encoder. Typically something like "username" might be used. - - [[nsa-user-service]] ==== 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.