Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AYS-582 | Restrict Non-Active Users from Sending Password Reset Requests #415

Merged
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.ays.auth.exception;

import org.ays.auth.model.enums.AysUserStatus;
import org.ays.common.exception.AysAuthException;

import java.io.Serial;
Expand All @@ -24,4 +25,13 @@ public AysUserNotActiveException(String userId) {
super("user is not active! userId:" + userId);
}

/**
* Constructs a new UserNotActiveException with the specified user status.
*
* @param status the status of the user that is not active
*/
public AysUserNotActiveException(AysUserStatus status) {
super("user is not active! currentStatus: " + status.name());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import lombok.RequiredArgsConstructor;
import org.ays.auth.exception.AysEmailAddressNotValidException;
import org.ays.auth.exception.AysUserNotActiveException;
import org.ays.auth.exception.AysUserDoesNotAccessPageException;
import org.ays.auth.exception.AysUserPasswordCannotChangedException;
import org.ays.auth.exception.AysUserPasswordDoesNotExistException;
Expand Down Expand Up @@ -44,12 +45,15 @@ class AysUserPasswordServiceImpl implements AysUserPasswordService {
/**
* Handles the forgot password request by sending an email to the user with instructions to create a new password.
* <p>
* This method checks if the user exists based on the provided email address. If the user is found,
* it sets or updates the user's password with a temporary value and the current time as the forgotten password timestamp.
* An email is then sent to the user with instructions to create a new password.
* This method checks if the user exists based on the provided email address and verifies whether the user is active.
* If the user is found and active, it validates whether the user has the necessary permissions to access the source page.
* If the user has permission, it sets or updates the user's password with a temporary value and the current
* time as the forgotten password timestamp. An email is then sent to the user with instructions to create a new password.
*
* @param forgotPasswordRequest the request containing the user's email address.
* @throws AysEmailAddressNotValidException if the email address does not correspond to any existing user.
* @throws AysUserNotActiveException if the user status is not active.
* @throws AysUserDoesNotAccessPageException if the user lacks permission to access the source page.
*/
@Override
@Transactional
Expand All @@ -59,6 +63,10 @@ public void forgotPassword(final AysPasswordForgotRequest forgotPasswordRequest)
final AysUser user = userReadPort.findByEmailAddress(emailAddress)
.orElseThrow(() -> new AysEmailAddressNotValidException(emailAddress));

if(!user.isActive()) {
throw new AysUserNotActiveException(user.getStatus());
}

this.validateUserSourcePagePermission(user);

final var passwordBuilder = AysUser.Password.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

import org.ays.AysUnitTest;
import org.ays.auth.exception.AysEmailAddressNotValidException;
import org.ays.auth.exception.AysUserNotActiveException;
import org.ays.auth.exception.AysUserDoesNotAccessPageException;
import org.ays.auth.exception.AysUserPasswordCannotChangedException;
import org.ays.auth.exception.AysUserPasswordDoesNotExistException;
import org.ays.auth.model.AysRole;
import org.ays.auth.model.AysRoleBuilder;
import org.ays.auth.model.AysUser;
import org.ays.auth.model.AysUserBuilder;
import org.ays.auth.model.enums.AysUserStatus;
import org.ays.auth.model.request.AysForgotPasswordRequestBuilder;
import org.ays.auth.model.request.AysPasswordCreateRequest;
import org.ays.auth.model.request.AysPasswordCreateRequestBuilder;
Expand Down Expand Up @@ -185,6 +187,40 @@ void givenValidForgotPasswordRequest_whenEmailDoesNotExist_thenThrowAysEmailAddr
.sendPasswordCreateEmail(Mockito.any(AysUser.class));
}

@Test
void givenValidForgotPasswordRequest_whenUserStatusNotActive_thenThrowUserNotActiveException() {
// Given
AysPasswordForgotRequest mockForgotPasswordRequest = new AysForgotPasswordRequestBuilder()
.withValidValues()
.build();

// When
AysUser mockUser = new AysUserBuilder()
.withValidValues()
.withEmailAddress(mockForgotPasswordRequest.getEmailAddress())
.withStatus(AysUserStatus.PASSIVE)
.build();

Mockito.when(userReadPort.findByEmailAddress(Mockito.anyString()))
.thenReturn(Optional.of(mockUser));

// Then
Assertions.assertThrows(
AysUserNotActiveException.class,
() -> userPasswordService.forgotPassword(mockForgotPasswordRequest)
);

// Verify
Mockito.verify(userReadPort, Mockito.times(1))
.findByEmailAddress(Mockito.anyString());

Mockito.verify(userSavePort, Mockito.never())
.save(Mockito.any(AysUser.class));

Mockito.verify(userMailService, Mockito.never())
.sendPasswordCreateEmail(Mockito.any(AysUser.class));
}

@Test
void givenValidForgotPasswordRequest_whenUserHasNotInstitutionPagePermission_thenThrowUserDoesNotAccessPageException() {
// Given
Expand Down
Loading