vt-middleware / passay

Password policy enforcement for Java.
http://www.passay.org
Other
281 stars 64 forks source link

Issue with spring-boot unit tests #144

Closed Sanady closed 1 year ago

Sanady commented 1 year ago

Hello guys, I am facing issues with the unit tests, when I try to fill in the request object and afterward I sent that same request to the service layer, I am getting a false flag from the password validator. Here is the code: Test:

@ExtendWith(MockitoExtension.class)
class AuthenticationServiceTests {
    @Mock
    private UserRepository userRepository;

    @Mock
    private RoleRepository roleRepository;

    @Mock
    private PasswordEncoder passwordEncoder;

    @Mock
    private JwtService jwtService;

    @Mock
    private AuthenticationManager authenticationManager;

    @Mock
    private ApplicationConfig applicationConfig;

    @InjectMocks
    private AuthenticationService authenticationService;

    @Test
    @DisplayName("Register - register new user successfully - returns message response")
    void register_registerNewUserSuccessfully_returnsMessageResponse() {
        // Prepare
        RegisterRequest request = new RegisterRequest(
                Randomizer.alphabeticGenerator(1).toUpperCase() + Randomizer.alphabeticGenerator(10),
                Randomizer.alphabeticGenerator(1).toUpperCase() + Randomizer.alphabeticGenerator(10),
                Randomizer.alphabeticGenerator(10) + "@gmail.com",
                Randomizer.alphabeticGenerator(1).toUpperCase() +
                        Randomizer.alphabeticGenerator(5) +
                        "@" +
                        Randomizer.numericGenerator(2),
                Set.of("ROLE_USER")
        );
        System.out.println(request);
        // Act
        MessageResponse response = authenticationService.register(request);
        // Assert
        Assertions.assertEquals("User registered successfully!", response.message());
    }
}

isPasswordValid method:

    public boolean isPasswordValid(String password) {
        PasswordValidator passwordValidator = new PasswordValidator(
                Arrays.asList(
                        new LengthRule(8, 64),
                        new CharacterRule(EnglishCharacterData.UpperCase, 1),
                        new CharacterRule(EnglishCharacterData.LowerCase, 1),
                        new CharacterRule(EnglishCharacterData.Digit, 1),
                        new CharacterRule(EnglishCharacterData.Special, 1),
                        new WhitespaceRule()
                )
        );
        RuleResult result = passwordValidator.validate(new PasswordData(password));
        return result.isValid();
    }

Service:

@Service
@RequiredArgsConstructor
public class AuthenticationService {
    private final UserRepository userRepository;
    private final RoleRepository roleRepository;
    private final PasswordEncoder passwordEncoder;
    private final JwtService jwtService;
    private final AuthenticationManager authenticationManager;
    private final ApplicationConfig applicationConfig;

    @Transactional
    public MessageResponse register(RegisterRequest request) {
        if(Boolean.TRUE.equals(userRepository.existsByEmail(request.getEmail()))) {
            throw new UserEmailConflictException(ErrorMessages.USER_ALREADY_EXISTS_IN_SYSTEM.getValue());
        }

        if(Boolean.TRUE.equals(userRepository.existsByFirstnameAndLastname(request.getFirstname(),
                request.getLastname()))) {
            throw new UserFirstNameAndLastNameConflictException(ErrorMessages.USER_ALREADY_EXISTS_IN_SYSTEM.getValue());
        }

        if(request.getPassword() == null ||
                Boolean.FALSE.equals(applicationConfig.isPasswordValid(request.getPassword()))) {
            throw new IllegalArgumentException("Password does not meet minimum requirements to be accepted.");
        }

        Set<String> strRoles = request.getRoles();
        Set<Role> roles = new HashSet<>();

        if (strRoles == null) {
            Role userRole = roleRepository.findByName(RoleEnum.ROLE_USER)
                    .orElseThrow(() -> new IllegalArgumentException(ErrorMessages.ROLE_NOT_FOUND.getValue()));
            roles.add(userRole);
        } else {
            strRoles.forEach(role -> {
                switch (role) {
                    case "admin" -> {
                        Role adminRole = roleRepository.findByName(RoleEnum.ROLE_ADMIN)
                                .orElseThrow(() -> new IllegalArgumentException(ErrorMessages.ROLE_NOT_FOUND.getValue()));
                        roles.add(adminRole);
                    }
                    case "mod" -> {
                        Role modRole = roleRepository.findByName(RoleEnum.ROLE_MODERATOR)
                                .orElseThrow(() -> new IllegalArgumentException(ErrorMessages.ROLE_NOT_FOUND.getValue()));
                        roles.add(modRole);
                    }
                    default -> {
                        Role userRole = roleRepository.findByName(RoleEnum.ROLE_USER)
                                .orElseThrow(() -> new IllegalArgumentException(ErrorMessages.ROLE_NOT_FOUND.getValue()));
                        roles.add(userRole);
                    }
                }
            });
        }

        var user = User.builder()
                .firstname(request.getFirstname())
                .lastname(request.getLastname())
                .email(request.getEmail())
                .password(passwordEncoder.encode(request.getPassword()))
                .roles(roles)
                .createdAt(LocalDateTime.now())
                .updatedAt(LocalDateTime.now())
                .build();
        userRepository.save(user);
        return MessageResponse.builder()
                .message("User has been successfully registered!")
                .build();
    }
}

Assuming that something is wrong with the Passay dependency... could you please check it out? Thank you in advanced.

dfish3r commented 1 year ago

Emit a log from isPasswordValid containing the RuleResult. The list of RuleResultDetail should tell you why the password isn't valid.

dfish3r commented 1 year ago

No response from reporter. Feel free to reopen if you have further questions.