Remove PasswordEncoder from core

Issue: gh-4674
This commit is contained in:
Rob Winch 2017-10-22 15:58:56 -05:00
parent 6c69333df6
commit 4529e09339
5 changed files with 9 additions and 191 deletions

View File

@ -74,23 +74,6 @@ abstract class AbstractDaoAuthenticationConfigurer<B extends ProviderManagerBuil
return (C) this;
}
/**
* Allows specifying the
* {@link org.springframework.security.authentication.encoding.PasswordEncoder} to use
* with the {@link DaoAuthenticationProvider}. The default is to use plain text.
*
* @param passwordEncoder The
* {@link org.springframework.security.authentication.encoding.PasswordEncoder} to
* use.
* @return the {@link SecurityConfigurer} for further customizations
*/
@SuppressWarnings("unchecked")
public C passwordEncoder(
org.springframework.security.authentication.encoding.PasswordEncoder passwordEncoder) {
provider.setPasswordEncoder(passwordEncoder);
return (C) this;
}
@Override
public void configure(B builder) throws Exception {
provider = postProcess(provider);

View File

@ -20,12 +20,12 @@ import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.Assert;
/**
@ -41,7 +41,7 @@ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthentication
/**
* The plaintext password used to perform
* {@link PasswordEncoder#isPasswordValid(String, String, Object)} on when the user is
* PasswordEncoder#matches(CharSequence, String)} on when the user is
* not found to avoid SEC-2056.
*/
private static final String USER_NOT_FOUND_PASSWORD = "userNotFoundPassword";
@ -53,7 +53,7 @@ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthentication
/**
* The password used to perform
* {@link PasswordEncoder#isPasswordValid(String, String, Object)} on when the user is
* {@link PasswordEncoder#matches(CharSequence, String)} on when the user is
* not found to avoid SEC-2056. This is necessary, because some
* {@link PasswordEncoder} implementations will short circuit if the password is not
* in a valid format.
@ -91,8 +91,7 @@ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthentication
String presentedPassword = authentication.getCredentials().toString();
if (!passwordEncoder.isPasswordValid(userDetails.getPassword(),
presentedPassword, salt)) {
if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
logger.debug("Authentication failed: password does not match stored value");
throw new BadCredentialsException(messages.getMessage(
@ -116,8 +115,7 @@ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthentication
catch (UsernameNotFoundException notFound) {
if (authentication.getCredentials() != null) {
String presentedPassword = authentication.getCredentials().toString();
passwordEncoder.isPasswordValid(userNotFoundEncodedPassword,
presentedPassword, null);
passwordEncoder.matches(presentedPassword, userNotFoundEncodedPassword);
}
throw notFound;
}
@ -146,45 +144,10 @@ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthentication
* @param passwordEncoder must be an instance of one of the {@code PasswordEncoder}
* types.
*/
public void setPasswordEncoder(Object passwordEncoder) {
public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
Assert.notNull(passwordEncoder, "passwordEncoder cannot be null");
if (passwordEncoder instanceof PasswordEncoder) {
setPasswordEncoder((PasswordEncoder) passwordEncoder);
return;
}
if (passwordEncoder instanceof org.springframework.security.crypto.password.PasswordEncoder) {
final org.springframework.security.crypto.password.PasswordEncoder delegate = (org.springframework.security.crypto.password.PasswordEncoder) passwordEncoder;
setPasswordEncoder(new PasswordEncoder() {
public String encodePassword(String rawPass, Object salt) {
checkSalt(salt);
return delegate.encode(rawPass);
}
public boolean isPasswordValid(String encPass, String rawPass, Object salt) {
checkSalt(salt);
return delegate.matches(rawPass, encPass);
}
private void checkSalt(Object salt) {
Assert.isNull(salt,
"Salt value must be null when used with crypto module PasswordEncoder");
}
});
return;
}
throw new IllegalArgumentException(
"passwordEncoder must be a PasswordEncoder instance");
}
private void setPasswordEncoder(PasswordEncoder passwordEncoder) {
Assert.notNull(passwordEncoder, "passwordEncoder cannot be null");
this.userNotFoundEncodedPassword = passwordEncoder.encodePassword(
USER_NOT_FOUND_PASSWORD, null);
this.userNotFoundEncodedPassword = passwordEncoder.encode(USER_NOT_FOUND_PASSWORD);
this.passwordEncoder = passwordEncoder;
}

View File

@ -1,91 +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.encoding;
/**
* Interface for performing authentication operations on a password.
*
* @author colin sampaleanu
* @deprecated It is recommended to use
* {@link org.springframework.security.crypto.password.PasswordEncoder} instead which
* better accommodates best practice of randomly generated salt that is included with the
* password.
*/
@Deprecated
public interface PasswordEncoder {
// ~ Methods
// ========================================================================================================
/**
* <p>
* Encodes the specified raw password with an implementation specific algorithm.
* </p>
* <P>
* This will generally be a one-way message digest such as MD5 or SHA, but may also be
* a plaintext variant which does no encoding at all, but rather returns the same
* password it was fed. The latter is useful to plug in when the original password
* must be stored as-is.
* </p>
* <p>
* The specified salt will potentially be used by the implementation to "salt" the
* initial value before encoding. A salt is usually a user-specific value which is
* added to the password before the digest is computed. This means that computation of
* digests for common dictionary words will be different than those in the backend
* store, because the dictionary word digests will not reflect the addition of the
* salt. If a per-user salt is used (rather than a system-wide salt), it also means
* users with the same password will have different digest encoded passwords in the
* backend store.
* </p>
* <P>
* If a salt value is provided, the same salt value must be use when calling the
* {@link #isPasswordValid(String, String, Object)} method. Note that a specific
* implementation may choose to ignore the salt value (via <code>null</code>), or
* provide its own.
* </p>
*
* @param rawPass the password to encode
* @param salt optionally used by the implementation to "salt" the raw password before
* encoding. A <code>null</code> value is legal.
*
* @return encoded password
*/
String encodePassword(String rawPass, Object salt);
/**
* <p>
* Validates a specified "raw" password against an encoded password.
* </p>
* <P>
* The encoded password should have previously been generated by
* {@link #encodePassword(String, Object)}. This method will encode the
* <code>rawPass</code> (using the optional <code>salt</code>), and then compared it
* with the presented <code>encPass</code>.
* </p>
* <p>
* For a discussion of salts, please refer to {@link #encodePassword(String, Object)}.
* </p>
*
* @param encPass a pre-encoded password
* @param rawPass a raw password to encode and compare against the pre-encoded
* password
* @param salt optionally used by the implementation to "salt" the raw password before
* encoding. A <code>null</code> value is legal.
*
* @return true if the password is valid , false otherwise
*/
boolean isPasswordValid(String encPass, String rawPass, Object salt);
}

View File

@ -1,26 +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.
*/
/**
* Password encoding implementations. Apart from the "null" implementations, they are all based on
* password hashing using digest functions. See the
* <a href="http://static.springsource.org/spring-security/site/docs/3.0.x/reference/core-services.html#core-services-password-encoding">
* reference manual</a> for more information.
* <p>
* Third part implementations such as those provided by <a href="http://www.jasypt.org/springsecurity.html">Jasypt</a>
* can also be used.
*/
package org.springframework.security.authentication.encoding;

View File

@ -390,9 +390,9 @@ public class DaoAuthenticationProviderTests {
@Test
public void testGettersSetters() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setPasswordEncoder(new PWE());
provider.setPasswordEncoder(new BCryptPasswordEncoder());
assertThat(provider.getPasswordEncoder().getClass()).isEqualTo(
PWE.class);
BCryptPasswordEncoder.class);
provider.setSaltSource(new SystemWideSaltSource());
assertThat(provider.getSaltSource().getClass()).isEqualTo(
@ -407,17 +407,6 @@ public class DaoAuthenticationProviderTests {
assertThat(provider.isForcePrincipalAsString()).isTrue();
}
static class PWE implements org.springframework.security.authentication.encoding.PasswordEncoder {
@Override public String encodePassword(String rawPass, Object salt) {
return null;
}
@Override public boolean isPasswordValid(String encPass, String rawPass,
Object salt) {
return false;
}
}
@Test
public void testGoesBackToAuthenticationDaoToObtainLatestPasswordIfCachedPasswordSeemsIncorrect() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(