Skip to content

Commit

Permalink
Improve PasswordEncoder Error Messaging
Browse files Browse the repository at this point in the history
Closes gh-14880
  • Loading branch information
abimaelrsergio authored and jzheaux committed Apr 26, 2024
1 parent c35e107 commit 6f1e1d4
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -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");
* you may not use this file except in compliance with the License.
Expand All @@ -19,6 +19,8 @@
import java.util.HashMap;
import java.util.Map;

import org.springframework.util.StringUtils;

/**
* A password encoder that delegates to another PasswordEncoder based upon a prefixed
* identifier.
Expand Down Expand Up @@ -129,6 +131,10 @@ public class DelegatingPasswordEncoder implements PasswordEncoder {

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 idSuffix;
Expand Down Expand Up @@ -286,7 +292,10 @@ public String encode(CharSequence rawPassword) {
@Override
public boolean matches(CharSequence rawPassword, String 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);
}

}
Expand Down
Original file line number Diff line number Diff line change
@@ -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");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -43,6 +43,8 @@
@ExtendWith(MockitoExtension.class)
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
private PasswordEncoder bcrypt;

Expand Down Expand Up @@ -201,23 +203,23 @@ public void matchesWhenUnMappedThenIllegalArgumentException() {
public void matchesWhenNoClosingPrefixStringThenIllegalArgumentException() {
assertThatIllegalArgumentException()
.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);
}

@Test
public void matchesWhenNoStartingPrefixStringThenFalse() {
assertThatIllegalArgumentException()
.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);
}

@Test
public void matchesWhenNoIdStringThenFalse() {
assertThatIllegalArgumentException()
.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);
}

Expand All @@ -226,7 +228,7 @@ public void matchesWhenPrefixInMiddleThenFalse() {
assertThatIllegalArgumentException()
.isThrownBy(() -> this.passwordEncoder.matches(this.rawPassword, "invalid" + this.bcryptEncodedPassword))
.isInstanceOf(IllegalArgumentException.class)
.withMessage("There is no PasswordEncoder mapped for the id \"null\"");
.withMessage(NO_PASSWORD_ENCODER);
verifyNoMoreInteractions(this.bcrypt, this.noop);
}

Expand All @@ -236,7 +238,7 @@ public void matchesWhenIdIsNullThenFalse() {
DelegatingPasswordEncoder passwordEncoder = new DelegatingPasswordEncoder(this.bcryptId, this.delegates);
assertThatIllegalArgumentException()
.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);
}

Expand Down Expand Up @@ -289,4 +291,14 @@ public void upgradeEncodingWhenDifferentIdThenTrue() {
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);

}

}

0 comments on commit 6f1e1d4

Please sign in to comment.