*/ public static function tooShort(): array { return [ 'empty' => [''], 'one short' => ['sevench'], 'a few chars' => ['abc'], ]; } /** * @dataProvider commonPasswords */ public function testRejectsAWellKnownPassword(string $password): void { self::assertStringContainsString('commonly used', (string) PasswordPolicy::validate($password)); } /** @return array */ public static function commonPasswords(): array { return [ 'password123' => ['password123'], 'shouting' => ['PASSWORD123'], 'mixed case' => ['PassWord123'], 'a keyboard walk' => ['qwertyuiop'], 'digits in a row' => ['123456789'], 'the classic' => ['iloveyou'], ]; } /** * @dataProvider tooFewDistinctCharacters */ public function testRejectsAPasswordBuiltFromAlmostNoDistinctCharacters(string $password): void { self::assertStringContainsString('repeated characters', (string) PasswordPolicy::validate($password)); } /** @return array */ public static function tooFewDistinctCharacters(): array { return [ 'one character' => ['aaaaaaaaaa'], 'two alternating' => ['abababababab'], 'three' => ['abcabcabcabc'], ]; } /** * @dataProvider identityEchoes */ public function testRejectsAPasswordContainingTheUsersOwnDetails(string $password, string $email, string $name): void { self::assertStringContainsString('name or email', (string) PasswordPolicy::validate($password, $email, $name)); } /** @return array */ public static function identityEchoes(): array { return [ 'the whole email' => ['grace@studio.test!', 'grace@studio.test', 'Grace'], 'the local part' => ['grace-hopper-1906', 'grace@studio.test', ''], 'the display name' => ['xxhopperxx-2019', 'someone@studio.test', 'Hopper'], 'differing in case' => ['MyGRACEpassword', 'grace@studio.test', ''], ]; } /** * A two- or three-letter overlap with a name is coincidence, not a weakness, * and refusing it would be baffling to the person typing. */ public function testShortIdentityFragmentsDoNotTripTheCheck(): void { self::assertNull(PasswordPolicy::validate('bramble-thicket', 'bo@studio.test', 'Bo')); } public function testAnEmptyIdentityIsNotTreatedAsContainedInEverything(): void { self::assertNull(PasswordPolicy::validate('bramble-thicket', '', '')); } }