Skip to content

Commit

Permalink
AYS-421 | @Password Validation Annotation Has Been Created and Anno…
Browse files Browse the repository at this point in the history
…tation Has Been Used for Length Limitation (#371)
  • Loading branch information
agitrubard authored Sep 5, 2024
1 parent 74acff1 commit 7b2d2c8
Show file tree
Hide file tree
Showing 21 changed files with 313 additions and 132 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.ays.common.model.request.AysPhoneNumberRequest;
import org.ays.common.util.validation.EmailAddress;
import org.ays.common.util.validation.Name;
import org.ays.common.util.validation.Password;

/**
* Represents a complete registration request for an admin user.
Expand Down Expand Up @@ -42,6 +43,7 @@ public class AdminRegistrationApplicationCompleteRequest {
private String emailAddress;

@NotBlank
@Password
private String password;

@Valid
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/org/ays/auth/model/request/AysLoginRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import lombok.Setter;
import org.ays.auth.model.enums.AysSourcePage;
import org.ays.common.util.validation.EmailAddress;
import org.ays.common.util.validation.Password;

/**
* Represents a login request of the Ays application.
Expand All @@ -25,6 +26,7 @@ public class AysLoginRequest {
private String emailAddress;

@NotBlank
@Password
private String password;

@NotNull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.ays.common.util.validation.Password;

@Getter
@Setter
public class AysPasswordCreateRequest {

@NotBlank
@Password
private String password;

@NotBlank
@Password
private String passwordRepeat;


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,21 +143,21 @@ public static AysErrorResponse.AysErrorResponseBuilder subErrors(final List<Fiel
final List<SubError> subErrorErrors = new ArrayList<>();

fieldErrors.forEach(fieldError -> {
final SubError.SubErrorBuilder sisSubErrorBuilder = SubError.builder();
final SubError.SubErrorBuilder subErrorBuilder = SubError.builder();

List<String> codes = List.of(Objects.requireNonNull(fieldError.getCodes()));
if (!codes.isEmpty()) {

sisSubErrorBuilder.field(StringUtils.substringAfterLast(codes.get(0), "."));
subErrorBuilder.field(StringUtils.substringAfterLast(codes.get(0), "."));

if (!"AssertTrue".equals(codes.get(codes.size() - 1))) {
sisSubErrorBuilder.type(StringUtils.substringAfterLast(codes.get(codes.size() - 2), ".").replace('$', '.'));
subErrorBuilder.type(StringUtils.substringAfterLast(codes.get(codes.size() - 2), ".").replace('$', '.'));
}
}
sisSubErrorBuilder.value(fieldError.getRejectedValue() != null ? fieldError.getRejectedValue().toString() : null);
sisSubErrorBuilder.message(fieldError.getDefaultMessage());
subErrorBuilder.value(fieldError.getRejectedValue() != null ? fieldError.getRejectedValue().toString() : null);
subErrorBuilder.message(fieldError.getDefaultMessage());

subErrorErrors.add(sisSubErrorBuilder.build());
subErrorErrors.add(subErrorBuilder.build());
});

return AysErrorResponse.builder().subErrors(subErrorErrors);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
* Validates whether the provided reason invalid domain
* specified regular expression.
*/
class SpecialCharacterValidator implements ConstraintValidator<NoSpecialCharacters, String> {
class NoSpecialCharacterValidator implements ConstraintValidator<NoSpecialCharacters, String> {

/**
* Regular expression pattern to match valid text with special characters, including Turkish characters.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
import java.lang.annotation.Target;

/**
* Annotation to validate reason using {@link SpecialCharacterValidator}.
* Annotation to validate reason using {@link NoSpecialCharacterValidator}.
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = SpecialCharacterValidator.class)
@Constraint(validatedBy = NoSpecialCharacterValidator.class)
public @interface NoSpecialCharacters {

/**
Expand Down
40 changes: 40 additions & 0 deletions src/main/java/org/ays/common/util/validation/Password.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.ays.common.util.validation;

import jakarta.validation.Constraint;
import jakarta.validation.Payload;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Annotation to validate password using {@link PasswordValidator}.
*/
@Target(value = ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PasswordValidator.class)
public @interface Password {

/**
* Returns the error message when password does not valid.
*
* @return the error message
*/
String message() default "must be valid";

/**
* Returns the validation groups to which this constraint belongs.
*
* @return the validation groups
*/
Class<?>[] groups() default {};

/**
* Returns the payload associated to this constraint.
*
* @return the payload
*/
Class<? extends Payload>[] payload() default {};

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package org.ays.common.util.validation;

import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import org.springframework.util.StringUtils;

/**
* Validator for password fields. This validator ensures that a password meets the minimum length requirement.
*/
class PasswordValidator implements ConstraintValidator<Password, String> {

/**
* Validates the provided password based on predefined rules.
*
* @param password the password to validate.
* @param constraintValidatorContext context in which the constraint is evaluated.
* @return {@code true} if the password is valid, {@code false} otherwise.
*/
@Override
public boolean isValid(String password, ConstraintValidatorContext constraintValidatorContext) {

if (!StringUtils.hasText(password)) {
return true;
}

if (password.length() < 6) {
constraintValidatorContext.disableDefaultConstraintViolation();
constraintValidatorContext.buildConstraintViolationWithTemplate("size must be at least 6 characters")
.addConstraintViolation();
return false;
}

return true;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
import org.ays.common.model.response.AysResponse;
import org.ays.common.model.response.AysResponseBuilder;
import org.ays.common.util.AysRandomUtil;
import org.ays.common.util.exception.model.AysErrorBuilder;
import org.ays.common.util.exception.model.response.AysErrorResponseBuilder;
import org.ays.institution.model.Institution;
import org.ays.institution.model.InstitutionBuilder;
import org.ays.util.AysMockMvcRequestBuilders;
Expand Down Expand Up @@ -118,7 +118,7 @@ void givenValidAdminRegisterApplicationListRequest_whenUnauthorizedForListing_th
MockHttpServletRequestBuilder mockHttpServletRequestBuilder = AysMockMvcRequestBuilders
.post(endpoint, mockUserToken.getAccessToken(), mockListRequest);

AysErrorResponse mockErrorResponse = AysErrorBuilder.FORBIDDEN;
AysErrorResponse mockErrorResponse = AysErrorResponseBuilder.FORBIDDEN;

aysMockMvc.perform(mockHttpServletRequestBuilder, mockErrorResponse)
.andExpect(AysMockResultMatchersBuilders.status()
Expand Down Expand Up @@ -177,7 +177,7 @@ void givenValidAdminRegisterApplicationId_whenUnauthorizedForGettingAdminRegiste
MockHttpServletRequestBuilder mockHttpServletRequestBuilder = AysMockMvcRequestBuilders
.get(endpoint, mockUserToken.getAccessToken());

AysErrorResponse mockErrorResponse = AysErrorBuilder.FORBIDDEN;
AysErrorResponse mockErrorResponse = AysErrorResponseBuilder.FORBIDDEN;

aysMockMvc.perform(mockHttpServletRequestBuilder, mockErrorResponse)
.andExpect(AysMockResultMatchersBuilders.status()
Expand Down Expand Up @@ -264,7 +264,7 @@ void givenInvalidAdminRegisterApplicationCreateRequest_whenCreatingAdminRegister
MockHttpServletRequestBuilder mockHttpServletRequestBuilder = AysMockMvcRequestBuilders
.post(endpoint, mockUserToken.getAccessToken(), createRequest);

AysErrorResponse mockErrorResponse = AysErrorBuilder.VALIDATION_ERROR;
AysErrorResponse mockErrorResponse = AysErrorResponseBuilder.VALIDATION_ERROR;

aysMockMvc.perform(mockHttpServletRequestBuilder, mockErrorResponse)
.andExpect(AysMockResultMatchersBuilders.status()
Expand All @@ -291,7 +291,7 @@ void givenValidAdminRegisterApplicationCreateRequest_whenUnauthorizedForCreating
MockHttpServletRequestBuilder mockHttpServletRequestBuilder = AysMockMvcRequestBuilders
.post(endpoint, mockUserToken.getAccessToken(), mockRequest);

AysErrorResponse mockErrorResponse = AysErrorBuilder.FORBIDDEN;
AysErrorResponse mockErrorResponse = AysErrorResponseBuilder.FORBIDDEN;

aysMockMvc.perform(mockHttpServletRequestBuilder, mockErrorResponse)
.andExpect(AysMockResultMatchersBuilders.status()
Expand Down Expand Up @@ -380,7 +380,7 @@ void givenPhoneNumberWithAlphanumericCharacter_whenPhoneNumberIsNotValid_thenRet
MockHttpServletRequestBuilder mockHttpServletRequestBuilder = AysMockMvcRequestBuilders
.post(endpoint, mockRequest);

AysErrorResponse mockErrorResponse = AysErrorBuilder.VALIDATION_ERROR;
AysErrorResponse mockErrorResponse = AysErrorResponseBuilder.VALIDATION_ERROR;

aysMockMvc.perform(mockHttpServletRequestBuilder, mockErrorResponse)
.andExpect(AysMockResultMatchersBuilders.status()
Expand Down Expand Up @@ -410,7 +410,7 @@ void givenPhoneNumberWithInvalidLength_whenPhoneNumberIsNotValid_thenReturnValid
MockHttpServletRequestBuilder mockHttpServletRequestBuilder = AysMockMvcRequestBuilders
.post(endpoint, mockRequest);

AysErrorResponse mockErrorResponse = AysErrorBuilder.VALIDATION_ERROR;
AysErrorResponse mockErrorResponse = AysErrorResponseBuilder.VALIDATION_ERROR;

aysMockMvc.perform(mockHttpServletRequestBuilder, mockErrorResponse)
.andExpect(AysMockResultMatchersBuilders.status()
Expand Down Expand Up @@ -441,7 +441,7 @@ void givenPhoneNumberWithInvalidOperator_whenPhoneNumberIsNotValid_thenReturnVal
MockHttpServletRequestBuilder mockHttpServletRequestBuilder = AysMockMvcRequestBuilders
.post(endpoint, mockRequest);

AysErrorResponse mockErrorResponse = AysErrorBuilder.VALIDATION_ERROR;
AysErrorResponse mockErrorResponse = AysErrorResponseBuilder.VALIDATION_ERROR;

aysMockMvc.perform(mockHttpServletRequestBuilder, mockErrorResponse)
.andExpect(AysMockResultMatchersBuilders.status()
Expand Down Expand Up @@ -477,7 +477,7 @@ void givenInvalidAdminRegisterApplicationCompleteRequestWithParametrizedInvalidN
MockHttpServletRequestBuilder mockHttpServletRequestBuilder = AysMockMvcRequestBuilders
.post(endpoint, mockRequest);

AysErrorResponse mockErrorResponse = AysErrorBuilder.VALIDATION_ERROR;
AysErrorResponse mockErrorResponse = AysErrorResponseBuilder.VALIDATION_ERROR;

aysMockMvc.perform(mockHttpServletRequestBuilder, mockErrorResponse)
.andExpect(AysMockResultMatchersBuilders.status()
Expand All @@ -504,15 +504,15 @@ void givenInvalidAdminRegisterApplicationCompleteRequestWithParametrizedInvalidE
String mockId = AysRandomUtil.generateUUID();
AdminRegistrationApplicationCompleteRequest mockRequest = new AdminRegistrationApplicationCompleteRequestBuilder()
.withValidValues()
.withEmail(invalidEmail)
.withEmailAddress(invalidEmail)
.build();

// Then
String endpoint = BASE_PATH.concat("/admin-registration-application/").concat(mockId).concat("/complete");
MockHttpServletRequestBuilder mockHttpServletRequestBuilder = AysMockMvcRequestBuilders
.post(endpoint, mockRequest);

AysErrorResponse mockErrorResponse = AysErrorBuilder.VALIDATION_ERROR;
AysErrorResponse mockErrorResponse = AysErrorResponseBuilder.VALIDATION_ERROR;

aysMockMvc.perform(mockHttpServletRequestBuilder, mockErrorResponse)
.andExpect(AysMockResultMatchersBuilders.status()
Expand All @@ -539,7 +539,7 @@ void givenValidAdminRegisterApplicationCompleteRequestWithParametrizedValidEmail
String mockId = AysRandomUtil.generateUUID();
AdminRegistrationApplicationCompleteRequest mockRequest = new AdminRegistrationApplicationCompleteRequestBuilder()
.withValidValues()
.withEmail(validEmail)
.withEmailAddress(validEmail)
.build();

// When
Expand All @@ -563,6 +563,38 @@ void givenValidAdminRegisterApplicationCompleteRequestWithParametrizedValidEmail
.complete(Mockito.anyString(), Mockito.any());
}

@ParameterizedTest
@ValueSource(strings = {
"g",
"gfh2j"
})
void givenInvalidAdminRegisterApplicationCompleteRequestWithInvalidPassword_whenPasswordDoesNotValid_thenReturnValidationError(String mockPassword) throws Exception {

// Given
String mockId = AysRandomUtil.generateUUID();
AdminRegistrationApplicationCompleteRequest mockRequest = new AdminRegistrationApplicationCompleteRequestBuilder()
.withValidValues()
.withPassword(mockPassword)
.build();

// Then
String endpoint = BASE_PATH.concat("/admin-registration-application/").concat(mockId).concat("/complete");
MockHttpServletRequestBuilder mockHttpServletRequestBuilder = AysMockMvcRequestBuilders
.post(endpoint, mockRequest);

AysErrorResponse mockErrorResponse = AysErrorResponseBuilder.VALIDATION_ERROR;

aysMockMvc.perform(mockHttpServletRequestBuilder, mockErrorResponse)
.andExpect(AysMockResultMatchersBuilders.status()
.isBadRequest())
.andExpect(AysMockResultMatchersBuilders.subErrors()
.isNotEmpty());

// Verify
Mockito.verify(adminRegistrationCompleteService, Mockito.never())
.complete(Mockito.anyString(), Mockito.any());
}

@Test
void givenValidAdminRegisterApplicationId_whenApproveAdminRegisterApplication_thenReturnNothing() throws Exception {
// Given
Expand Down Expand Up @@ -601,7 +633,7 @@ void givenValidAdminRegisterApplicationId_whenUnauthorizedForApprovingAdminRegis
MockHttpServletRequestBuilder mockHttpServletRequestBuilder = AysMockMvcRequestBuilders
.post(endpoint, mockUserToken.getAccessToken());

AysErrorResponse mockErrorResponse = AysErrorBuilder.FORBIDDEN;
AysErrorResponse mockErrorResponse = AysErrorResponseBuilder.FORBIDDEN;

aysMockMvc.perform(mockHttpServletRequestBuilder, mockErrorResponse)
.andExpect(AysMockResultMatchersBuilders.status()
Expand Down Expand Up @@ -659,7 +691,7 @@ void givenValidAdminRegisterApplicationRejectRequest_whenUnauthorizedForRejectin
MockHttpServletRequestBuilder mockHttpServletRequestBuilder = AysMockMvcRequestBuilders
.post(endpoint, mockUserToken.getAccessToken(), mockRequest);

AysErrorResponse mockErrorResponse = AysErrorBuilder.FORBIDDEN;
AysErrorResponse mockErrorResponse = AysErrorResponseBuilder.FORBIDDEN;

aysMockMvc.perform(mockHttpServletRequestBuilder, mockErrorResponse)
.andExpect(AysMockResultMatchersBuilders.status()
Expand Down
Loading

0 comments on commit 7b2d2c8

Please sign in to comment.