mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-07-05 18:22:26 +00:00
Remove PasswordEncoder from core
Issue: gh-4674
This commit is contained in:
parent
6c69333df6
commit
4529e09339
@ -74,23 +74,6 @@ abstract class AbstractDaoAuthenticationConfigurer<B extends ProviderManagerBuil
|
|||||||
return (C) this;
|
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
|
@Override
|
||||||
public void configure(B builder) throws Exception {
|
public void configure(B builder) throws Exception {
|
||||||
provider = postProcess(provider);
|
provider = postProcess(provider);
|
||||||
|
@ -20,12 +20,12 @@ import org.springframework.security.authentication.AuthenticationProvider;
|
|||||||
import org.springframework.security.authentication.BadCredentialsException;
|
import org.springframework.security.authentication.BadCredentialsException;
|
||||||
import org.springframework.security.authentication.InternalAuthenticationServiceException;
|
import org.springframework.security.authentication.InternalAuthenticationServiceException;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.authentication.encoding.PasswordEncoder;
|
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
|
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,7 +41,7 @@ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthentication
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The plaintext password used to perform
|
* 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.
|
* not found to avoid SEC-2056.
|
||||||
*/
|
*/
|
||||||
private static final String USER_NOT_FOUND_PASSWORD = "userNotFoundPassword";
|
private static final String USER_NOT_FOUND_PASSWORD = "userNotFoundPassword";
|
||||||
@ -53,7 +53,7 @@ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthentication
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The password used to perform
|
* 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
|
* not found to avoid SEC-2056. This is necessary, because some
|
||||||
* {@link PasswordEncoder} implementations will short circuit if the password is not
|
* {@link PasswordEncoder} implementations will short circuit if the password is not
|
||||||
* in a valid format.
|
* in a valid format.
|
||||||
@ -91,8 +91,7 @@ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthentication
|
|||||||
|
|
||||||
String presentedPassword = authentication.getCredentials().toString();
|
String presentedPassword = authentication.getCredentials().toString();
|
||||||
|
|
||||||
if (!passwordEncoder.isPasswordValid(userDetails.getPassword(),
|
if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
|
||||||
presentedPassword, salt)) {
|
|
||||||
logger.debug("Authentication failed: password does not match stored value");
|
logger.debug("Authentication failed: password does not match stored value");
|
||||||
|
|
||||||
throw new BadCredentialsException(messages.getMessage(
|
throw new BadCredentialsException(messages.getMessage(
|
||||||
@ -116,8 +115,7 @@ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthentication
|
|||||||
catch (UsernameNotFoundException notFound) {
|
catch (UsernameNotFoundException notFound) {
|
||||||
if (authentication.getCredentials() != null) {
|
if (authentication.getCredentials() != null) {
|
||||||
String presentedPassword = authentication.getCredentials().toString();
|
String presentedPassword = authentication.getCredentials().toString();
|
||||||
passwordEncoder.isPasswordValid(userNotFoundEncodedPassword,
|
passwordEncoder.matches(presentedPassword, userNotFoundEncodedPassword);
|
||||||
presentedPassword, null);
|
|
||||||
}
|
}
|
||||||
throw notFound;
|
throw notFound;
|
||||||
}
|
}
|
||||||
@ -146,45 +144,10 @@ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthentication
|
|||||||
* @param passwordEncoder must be an instance of one of the {@code PasswordEncoder}
|
* @param passwordEncoder must be an instance of one of the {@code PasswordEncoder}
|
||||||
* types.
|
* types.
|
||||||
*/
|
*/
|
||||||
public void setPasswordEncoder(Object passwordEncoder) {
|
public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
|
||||||
Assert.notNull(passwordEncoder, "passwordEncoder cannot be null");
|
Assert.notNull(passwordEncoder, "passwordEncoder cannot be null");
|
||||||
|
|
||||||
if (passwordEncoder instanceof PasswordEncoder) {
|
this.userNotFoundEncodedPassword = passwordEncoder.encode(USER_NOT_FOUND_PASSWORD);
|
||||||
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.passwordEncoder = passwordEncoder;
|
this.passwordEncoder = passwordEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
|
||||||
}
|
|
@ -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;
|
|
||||||
|
|
@ -390,9 +390,9 @@ public class DaoAuthenticationProviderTests {
|
|||||||
@Test
|
@Test
|
||||||
public void testGettersSetters() {
|
public void testGettersSetters() {
|
||||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||||
provider.setPasswordEncoder(new PWE());
|
provider.setPasswordEncoder(new BCryptPasswordEncoder());
|
||||||
assertThat(provider.getPasswordEncoder().getClass()).isEqualTo(
|
assertThat(provider.getPasswordEncoder().getClass()).isEqualTo(
|
||||||
PWE.class);
|
BCryptPasswordEncoder.class);
|
||||||
|
|
||||||
provider.setSaltSource(new SystemWideSaltSource());
|
provider.setSaltSource(new SystemWideSaltSource());
|
||||||
assertThat(provider.getSaltSource().getClass()).isEqualTo(
|
assertThat(provider.getSaltSource().getClass()).isEqualTo(
|
||||||
@ -407,17 +407,6 @@ public class DaoAuthenticationProviderTests {
|
|||||||
assertThat(provider.isForcePrincipalAsString()).isTrue();
|
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
|
@Test
|
||||||
public void testGoesBackToAuthenticationDaoToObtainLatestPasswordIfCachedPasswordSeemsIncorrect() {
|
public void testGoesBackToAuthenticationDaoToObtainLatestPasswordIfCachedPasswordSeemsIncorrect() {
|
||||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
|
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user