From feadaca27fca9d518b7436299e23da523eb15d4b Mon Sep 17 00:00:00 2001 From: Lucas Werkmeister Date: Sun, 14 Jan 2018 15:12:56 +0100 Subject: [PATCH] add: DelegatingPasswordChecker implementation MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This PasswordChecker implementation delegates to several other checkers, which lets us use a series of checkers (e. g. one which rates the password’s strength and one that checks against a list of known weak passwords) in place of one. In theory, this would also let us split up the existing PasswordStrengthChecker into two checkers, one grading the password strength in general and one checking whether the password contains parts of the name or the email address. However, this would remove the current behavior where a password that contains part of the name or email can be “redeemed” by being otherwise strong enough: DelegatingPasswordChecker does not support any such kind of interoperation of checkers. Change-Id: I1066ab11cac8c756a2972128257a65d29cd2d365 --- .../passwords/DelegatingPasswordChecker.java | 32 ++++++++ .../TestDelegatingPasswordChecker.java | 77 +++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 src/club/wpia/gigi/passwords/DelegatingPasswordChecker.java create mode 100644 tests/club/wpia/gigi/passwords/TestDelegatingPasswordChecker.java diff --git a/src/club/wpia/gigi/passwords/DelegatingPasswordChecker.java b/src/club/wpia/gigi/passwords/DelegatingPasswordChecker.java new file mode 100644 index 00000000..3d6c9d9f --- /dev/null +++ b/src/club/wpia/gigi/passwords/DelegatingPasswordChecker.java @@ -0,0 +1,32 @@ +package club.wpia.gigi.passwords; + +import club.wpia.gigi.GigiApiException; + +/** + * A {@link PasswordChecker} that delegates checks to several other PasswordCheckers + * and merges their error messages. + */ +public class DelegatingPasswordChecker implements PasswordChecker { + + private final PasswordChecker[] checkers; + + public DelegatingPasswordChecker(PasswordChecker[] checkers) { + this.checkers = checkers; + } + + @Override + public GigiApiException checkPassword(String password, String[] nameParts, String email) { + GigiApiException exception = new GigiApiException(); + for (PasswordChecker checker : checkers) { + GigiApiException currentException = checker.checkPassword(password, nameParts, email); + if (currentException != null) { + exception.mergeInto(currentException); + } + } + if (exception.isEmpty()) { + return null; + } else { + return exception; + } + } +} diff --git a/tests/club/wpia/gigi/passwords/TestDelegatingPasswordChecker.java b/tests/club/wpia/gigi/passwords/TestDelegatingPasswordChecker.java new file mode 100644 index 00000000..250758a0 --- /dev/null +++ b/tests/club/wpia/gigi/passwords/TestDelegatingPasswordChecker.java @@ -0,0 +1,77 @@ +package club.wpia.gigi.passwords; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +import org.junit.Test; + +import club.wpia.gigi.GigiApiException; +import club.wpia.gigi.passwords.DelegatingPasswordChecker; +import club.wpia.gigi.passwords.PasswordChecker; + +public class TestDelegatingPasswordChecker { + + @Test + public void testNoCheckers() { + DelegatingPasswordChecker checker = new DelegatingPasswordChecker(new PasswordChecker[0]); + + assertNull(checker.checkPassword("", new String[0], "")); + } + + @Test + public void testOneChecker() { + DelegatingPasswordChecker checker = new DelegatingPasswordChecker(new PasswordChecker[] { + new PasswordChecker() { + @Override + public GigiApiException checkPassword(String password, String[] nameParts, String email) { + return password.isEmpty() ? + new GigiApiException("empty password") : + null; + } + } + }); + + assertNull(checker.checkPassword("a strong password", new String[0], "")); + + GigiApiException exception = checker.checkPassword("", new String[0], ""); + assertNotNull(exception); + assertEquals("empty password", exception.getMessage()); + } + + @Test + public void testTwoCheckers() { + DelegatingPasswordChecker checker = new DelegatingPasswordChecker(new PasswordChecker[] { + new PasswordChecker() { + @Override + public GigiApiException checkPassword(String password, String[] nameParts, String email) { + return password.equals(email) ? + new GigiApiException("password = email") : + null; + } + }, + new PasswordChecker() { + @Override + public GigiApiException checkPassword(String password, String[] nameParts, String email) { + return password.equals("12345") ? + new GigiApiException("12345 is a bad password") : + null; + } + } + }); + + assertNull(checker.checkPassword("a strong password", new String[0], "email")); + + GigiApiException exception1 = checker.checkPassword("email", new String[0], "email"); + assertNotNull(exception1); + assertEquals("password = email", exception1.getMessage()); + + GigiApiException exception2 = checker.checkPassword("12345", new String[0], "email"); + assertNotNull(exception2); + assertEquals("12345 is a bad password", exception2.getMessage()); + + GigiApiException exception3 = checker.checkPassword("12345", new String[0], "12345"); + assertNotNull(exception3); + assertThat(exception3.getMessage(), containsString("password = email")); + assertThat(exception3.getMessage(), containsString("12345 is a bad password")); + } +} -- 2.39.2