Skip to content

DelegatingPasswordEncoder.upgradeEncoding() ignores the delegate's implementation #6134

Closed
@eugenevd

Description

@eugenevd

Summary

When using DelegatingPasswordEncoder to which is provided a custom PasswordEncoder implementation in which upgradeEncoding() is overridden, neither DaoAuthenticationProvider.createSuccessAuthentication() nor the called DelegatingPasswordEncoder.upgradeEncoding() consults the overridden PasswordEncoder.upgradeEncoding()

Actual Behavior

DaoAuthenticationProvider.createSuccessAuthentication() reencodes the password if it has a different encoding than what DelegatingPasswordEncoder was created with (idForEncode).
It consults DelegatingPasswordEncoder.upgradeEncoding() but ignores PasswordEncoder.upgradeEncoding()

Expected Behavior

DelegatingPasswordEncoder.upgradeEncoding() should check with the delegate (for the {id})
if it should upgrade the encoding.
Similar to how DelegatingPasswordEncoder.matches(CharSequence,String) does it.

Version

spring-security-core:5.1.1.RELEASE

Sample

I create an instance of DelegatingPasswordEncoder to which I specify encoders
that should handle the different types of encoded passwords it might come across.

@Bean
public PasswordEncoder delegatingPasswordEncoder() {
    PasswordEncoder defaultEncoder = new StandardPasswordEncoder();
    Map<String, PasswordEncoder> encoders = new HashMap<>();
    encoders.put("bcrypt", new BCryptPasswordEncoder());
    encoders.put("scrypt", new SCryptPasswordEncoder());
    encoders.put("sha1", new MySHA1PasswordEncoder());
 
    DelegatingPasswordEncoder passworEncoder = new DelegatingPasswordEncoder(
      "bcrypt", encoders);
    passworEncoder.setDefaultPasswordEncoderForMatches(defaultEncoder);
 
    return passworEncoder;
}

For whatever reason, I might want to re-encode passwords, but not when they're 'sha1'. Thus, return false:

class MySHA1PasswordEncoder implements PasswordEncoder

@Override String encode() {..}
@Override boolean matches() {..}
@Override boolean upgradeEncoding() {
  return false;
}

But this has no effect. After successful auth:
DaoAuthenticationProvider.createSuccessAuthentication() doesn't consult MySHA1PasswordEncoder.upgradeEncoding():

protected Authentication createSuccessAuthentication(Object principal,
			Authentication authentication, UserDetails user) {
     boolean upgradeEncoding = this.userDetailsPasswordService != null
				&& this.passwordEncoder.upgradeEncoding(user.getPassword());

'this.passwordEncoder' is the DelegatingPasswordEncoder created earlier, and its impl:

	@Override
	public boolean upgradeEncoding(String encodedPassword) {
		String id = extractId(encodedPassword);
		return !this.idForEncode.equalsIgnoreCase(id);
	}

I would expect either of these to check with the delegate, eg MySHA1PasswordEncoder.upgradeEncoding()
if the re-encoding should happen.
DelegatingPasswordEncoder.upgradeEncoding() seems to assume I definitely want it to happen, even though I had to option to override PasswordEncoder.upgradeEncoding()

--
There are examples where people use AuthenticationSuccessEvent, but seems unncessary given the ability to override upgradeEncoding()

--
Any insight would be valued.

Metadata

Metadata

Assignees

Labels

in: cryptoAn issue in spring-security-cryptostatus: invalidAn issue that we don't feel is valid

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions