diff --git a/pom.xml b/pom.xml index bcc1d115d..a290a1a8b 100644 --- a/pom.xml +++ b/pom.xml @@ -409,6 +409,11 @@ + + org.passay + passay + 1.6.1 + redis.clients diff --git a/src/main/java/com/commafeed/backend/service/UserService.java b/src/main/java/com/commafeed/backend/service/UserService.java index e51ba915e..64743fd1d 100644 --- a/src/main/java/com/commafeed/backend/service/UserService.java +++ b/src/main/java/com/commafeed/backend/service/UserService.java @@ -92,19 +92,9 @@ public User register(String name, String password, String email, Collection roles, boolean forceRegistration) { - Preconditions.checkNotNull(name); - Preconditions.checkArgument(StringUtils.length(name) <= 32, "Name too long (32 characters maximum)"); - Preconditions.checkNotNull(password); - if (!forceRegistration) { Preconditions.checkState(config.getApplicationSettings().getAllowRegistrations(), "Registrations are closed on this CommaFeed instance"); - - Preconditions.checkNotNull(email); - Preconditions.checkArgument(StringUtils.length(name) >= 3, "Name too short (3 characters minimum)"); - Preconditions.checkArgument(forceRegistration || StringUtils.length(password) >= 6, - "Password too short (6 characters maximum)"); - Preconditions.checkArgument(StringUtils.contains(email, "@"), "Invalid email address"); } Preconditions.checkArgument(userDAO.findByName(name) == null, "Name already taken"); diff --git a/src/main/java/com/commafeed/frontend/auth/PasswordConstraintValidator.java b/src/main/java/com/commafeed/frontend/auth/PasswordConstraintValidator.java new file mode 100644 index 000000000..534be510c --- /dev/null +++ b/src/main/java/com/commafeed/frontend/auth/PasswordConstraintValidator.java @@ -0,0 +1,54 @@ +package com.commafeed.frontend.auth; + +import java.util.List; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +import org.passay.CharacterRule; +import org.passay.EnglishCharacterData; +import org.passay.LengthRule; +import org.passay.PasswordData; +import org.passay.PasswordValidator; +import org.passay.RuleResult; +import org.passay.WhitespaceRule; + +public class PasswordConstraintValidator implements ConstraintValidator { + + @Override + public void initialize(ValidPassword constraintAnnotation) { + // nothing to do + } + + @Override + public boolean isValid(String value, ConstraintValidatorContext context) { + PasswordValidator validator = buildPasswordValidator(); + RuleResult result = validator.validate(new PasswordData(value)); + + if (result.isValid()) { + return true; + } + + List messages = validator.getMessages(result); + String message = String.join(System.lineSeparator(), messages); + context.buildConstraintViolationWithTemplate(message).addConstraintViolation().disableDefaultConstraintViolation(); + return false; + } + + private PasswordValidator buildPasswordValidator() { + return new PasswordValidator( + // length + new LengthRule(8, 128), + // 1 uppercase char + new CharacterRule(EnglishCharacterData.UpperCase, 1), + // 1 lowercase char + new CharacterRule(EnglishCharacterData.LowerCase, 1), + // 1 digit + new CharacterRule(EnglishCharacterData.Digit, 1), + // 1 special char + new CharacterRule(EnglishCharacterData.Special, 1), + // no whitespace + new WhitespaceRule()); + } + +} diff --git a/src/main/java/com/commafeed/frontend/auth/ValidPassword.java b/src/main/java/com/commafeed/frontend/auth/ValidPassword.java new file mode 100644 index 000000000..8123dac30 --- /dev/null +++ b/src/main/java/com/commafeed/frontend/auth/ValidPassword.java @@ -0,0 +1,23 @@ +package com.commafeed.frontend.auth; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; + +@Documented +@Constraint(validatedBy = PasswordConstraintValidator.class) +@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.ANNOTATION_TYPE }) +@Retention(RetentionPolicy.RUNTIME) +public @interface ValidPassword { + + String message() default "Invalid Password"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/src/main/java/com/commafeed/frontend/model/request/ProfileModificationRequest.java b/src/main/java/com/commafeed/frontend/model/request/ProfileModificationRequest.java index 96c59eb53..47c469511 100644 --- a/src/main/java/com/commafeed/frontend/model/request/ProfileModificationRequest.java +++ b/src/main/java/com/commafeed/frontend/model/request/ProfileModificationRequest.java @@ -2,6 +2,8 @@ import java.io.Serializable; +import com.commafeed.frontend.auth.ValidPassword; + import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -15,6 +17,7 @@ public class ProfileModificationRequest implements Serializable { private String email; @ApiModelProperty(value = "changes password of the user, if specified") + @ValidPassword private String password; @ApiModelProperty(value = "generate a new api key") diff --git a/src/main/java/com/commafeed/frontend/model/request/RegistrationRequest.java b/src/main/java/com/commafeed/frontend/model/request/RegistrationRequest.java index b93af520b..08a52266d 100644 --- a/src/main/java/com/commafeed/frontend/model/request/RegistrationRequest.java +++ b/src/main/java/com/commafeed/frontend/model/request/RegistrationRequest.java @@ -6,6 +6,8 @@ import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.NotEmpty; +import com.commafeed.frontend.auth.ValidPassword; + import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -21,7 +23,7 @@ public class RegistrationRequest implements Serializable { private String name; @ApiModelProperty(value = "password, minimum 6 characters", required = true) - @Length(min = 6) + @ValidPassword @NotEmpty private String password; diff --git a/src/main/java/com/commafeed/frontend/resource/UserREST.java b/src/main/java/com/commafeed/frontend/resource/UserREST.java index e05c80c2a..3ded1ab4a 100644 --- a/src/main/java/com/commafeed/frontend/resource/UserREST.java +++ b/src/main/java/com/commafeed/frontend/resource/UserREST.java @@ -192,8 +192,7 @@ public Response getUserProfile(@ApiParam(hidden = true) @SecurityCheck User user @ApiOperation(value = "Save user's profile") @Timed public Response saveUserProfile(@ApiParam(hidden = true) @SecurityCheck User user, - @ApiParam(required = true) ProfileModificationRequest request) { - Preconditions.checkArgument(StringUtils.isBlank(request.getPassword()) || request.getPassword().length() >= 6); + @Valid @ApiParam(required = true) ProfileModificationRequest request) { if (StringUtils.isNotBlank(request.getEmail())) { User u = userDAO.findByEmail(request.getEmail()); Preconditions.checkArgument(u == null || user.getId().equals(u.getId()));