Merge branch '6.2.x'

This commit is contained in:
Josh Cummings 2024-04-26 17:14:00 -06:00
commit 9f125afc81
No known key found for this signature in database
GPG Key ID: A306A51F43B8E5A5
2 changed files with 29 additions and 8 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2022 the original author or authors. * Copyright 2002-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -19,6 +19,8 @@ package org.springframework.security.crypto.password;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.springframework.util.StringUtils;
/** /**
* A password encoder that delegates to another PasswordEncoder based upon a prefixed * A password encoder that delegates to another PasswordEncoder based upon a prefixed
* identifier. * identifier.
@ -129,6 +131,10 @@ public class DelegatingPasswordEncoder implements PasswordEncoder {
private static final String DEFAULT_ID_SUFFIX = "}"; private static final String DEFAULT_ID_SUFFIX = "}";
public static final String NO_PASSWORD_ENCODER_MAPPED = "There is no PasswordEncoder mapped for the id \"%s\"";
public static final String NO_PASSWORD_ENCODER_PREFIX = "You have entered a password with no PasswordEncoder. If that is your intent, it should be prefixed with `{noop}`.";
private final String idPrefix; private final String idPrefix;
private final String idSuffix; private final String idSuffix;
@ -286,7 +292,10 @@ public class DelegatingPasswordEncoder implements PasswordEncoder {
@Override @Override
public boolean matches(CharSequence rawPassword, String prefixEncodedPassword) { public boolean matches(CharSequence rawPassword, String prefixEncodedPassword) {
String id = extractId(prefixEncodedPassword); String id = extractId(prefixEncodedPassword);
throw new IllegalArgumentException("There is no PasswordEncoder mapped for the id \"" + id + "\""); if (StringUtils.hasText(id)) {
throw new IllegalArgumentException(String.format(NO_PASSWORD_ENCODER_MAPPED, id));
}
throw new IllegalArgumentException(NO_PASSWORD_ENCODER_PREFIX);
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2022 the original author or authors. * Copyright 2002-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -43,6 +43,8 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
public class DelegatingPasswordEncoderTests { public class DelegatingPasswordEncoderTests {
public static final String NO_PASSWORD_ENCODER = "You have entered a password with no PasswordEncoder. If that is your intent, it should be prefixed with `{noop}`.";
@Mock @Mock
private PasswordEncoder bcrypt; private PasswordEncoder bcrypt;
@ -201,7 +203,7 @@ public class DelegatingPasswordEncoderTests {
public void matchesWhenNoClosingPrefixStringThenIllegalArgumentException() { public void matchesWhenNoClosingPrefixStringThenIllegalArgumentException() {
assertThatIllegalArgumentException() assertThatIllegalArgumentException()
.isThrownBy(() -> this.passwordEncoder.matches(this.rawPassword, "{bcrypt" + this.rawPassword)) .isThrownBy(() -> this.passwordEncoder.matches(this.rawPassword, "{bcrypt" + this.rawPassword))
.withMessage("There is no PasswordEncoder mapped for the id \"null\""); .withMessage(NO_PASSWORD_ENCODER);
verifyNoMoreInteractions(this.bcrypt, this.noop); verifyNoMoreInteractions(this.bcrypt, this.noop);
} }
@ -209,7 +211,7 @@ public class DelegatingPasswordEncoderTests {
public void matchesWhenNoStartingPrefixStringThenFalse() { public void matchesWhenNoStartingPrefixStringThenFalse() {
assertThatIllegalArgumentException() assertThatIllegalArgumentException()
.isThrownBy(() -> this.passwordEncoder.matches(this.rawPassword, "bcrypt}" + this.rawPassword)) .isThrownBy(() -> this.passwordEncoder.matches(this.rawPassword, "bcrypt}" + this.rawPassword))
.withMessage("There is no PasswordEncoder mapped for the id \"null\""); .withMessage(NO_PASSWORD_ENCODER);
verifyNoMoreInteractions(this.bcrypt, this.noop); verifyNoMoreInteractions(this.bcrypt, this.noop);
} }
@ -217,7 +219,7 @@ public class DelegatingPasswordEncoderTests {
public void matchesWhenNoIdStringThenFalse() { public void matchesWhenNoIdStringThenFalse() {
assertThatIllegalArgumentException() assertThatIllegalArgumentException()
.isThrownBy(() -> this.passwordEncoder.matches(this.rawPassword, "{}" + this.rawPassword)) .isThrownBy(() -> this.passwordEncoder.matches(this.rawPassword, "{}" + this.rawPassword))
.withMessage("There is no PasswordEncoder mapped for the id \"\""); .withMessage(NO_PASSWORD_ENCODER);
verifyNoMoreInteractions(this.bcrypt, this.noop); verifyNoMoreInteractions(this.bcrypt, this.noop);
} }
@ -226,7 +228,7 @@ public class DelegatingPasswordEncoderTests {
assertThatIllegalArgumentException() assertThatIllegalArgumentException()
.isThrownBy(() -> this.passwordEncoder.matches(this.rawPassword, "invalid" + this.bcryptEncodedPassword)) .isThrownBy(() -> this.passwordEncoder.matches(this.rawPassword, "invalid" + this.bcryptEncodedPassword))
.isInstanceOf(IllegalArgumentException.class) .isInstanceOf(IllegalArgumentException.class)
.withMessage("There is no PasswordEncoder mapped for the id \"null\""); .withMessage(NO_PASSWORD_ENCODER);
verifyNoMoreInteractions(this.bcrypt, this.noop); verifyNoMoreInteractions(this.bcrypt, this.noop);
} }
@ -236,7 +238,7 @@ public class DelegatingPasswordEncoderTests {
DelegatingPasswordEncoder passwordEncoder = new DelegatingPasswordEncoder(this.bcryptId, this.delegates); DelegatingPasswordEncoder passwordEncoder = new DelegatingPasswordEncoder(this.bcryptId, this.delegates);
assertThatIllegalArgumentException() assertThatIllegalArgumentException()
.isThrownBy(() -> passwordEncoder.matches(this.rawPassword, this.rawPassword)) .isThrownBy(() -> passwordEncoder.matches(this.rawPassword, this.rawPassword))
.withMessage("There is no PasswordEncoder mapped for the id \"null\""); .withMessage(NO_PASSWORD_ENCODER);
verifyNoMoreInteractions(this.bcrypt, this.noop); verifyNoMoreInteractions(this.bcrypt, this.noop);
} }
@ -289,4 +291,14 @@ public class DelegatingPasswordEncoderTests {
verifyNoMoreInteractions(this.bcrypt); verifyNoMoreInteractions(this.bcrypt);
} }
@Test
void matchesShouldThrowIllegalArgumentExceptionWhenNoPasswordEncoderIsMappedForTheId() {
assertThatIllegalArgumentException()
.isThrownBy(() -> this.passwordEncoder.matches("rawPassword", "prefixEncodedPassword"))
.isInstanceOf(IllegalArgumentException.class)
.withMessage(NO_PASSWORD_ENCODER);
verifyNoMoreInteractions(this.bcrypt, this.noop);
}
} }