diff --git a/pom.xml b/pom.xml index 7663bb3e6e6..c0b66a47115 100644 --- a/pom.xml +++ b/pom.xml @@ -200,11 +200,18 @@ omnifaces 3.8 + + + jakarta.validation + jakarta.validation-api + provided + org.hibernate.validator hibernate-validator + provided - + org.glassfish jakarta.el provided diff --git a/src/main/java/ValidationMessages.properties b/src/main/java/ValidationMessages.properties index 877f76b0f9b..7245c0841c7 100644 --- a/src/main/java/ValidationMessages.properties +++ b/src/main/java/ValidationMessages.properties @@ -2,7 +2,7 @@ user.firstName=Please enter your first name. user.lastName=Please enter your last name. user.invalidEmail=Please enter a valid email address. user.enterUsername=Please enter a username. -user.usernameLength=Username must be between 2 and 60 characters. +user.usernameLength=Username must be between {min} and {max} characters. user.illegalCharacters=Found an illegal character(s). Valid characters are a-Z, 0-9, '_', '-', and '.'. user.enterNickname=Please enter a nickname. @@ -42,3 +42,6 @@ password.validate=Password reset page default email message. guestbook.name=Enter a name for the guestbook guestbook.response.nameLength=Please limit response to 255 characters + +email.invalid=is not a valid email address. +url.invalid=is not a valid URL. diff --git a/src/main/java/edu/harvard/iq/dataverse/DatasetFieldValueValidator.java b/src/main/java/edu/harvard/iq/dataverse/DatasetFieldValueValidator.java index 08f30343ad8..8b807f78bca 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DatasetFieldValueValidator.java +++ b/src/main/java/edu/harvard/iq/dataverse/DatasetFieldValueValidator.java @@ -15,6 +15,9 @@ import java.util.regex.Pattern; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; + +import edu.harvard.iq.dataverse.validation.EMailValidator; +import edu.harvard.iq.dataverse.validation.URLValidator; import org.apache.commons.lang3.StringUtils; import org.apache.commons.validator.routines.UrlValidator; @@ -165,29 +168,19 @@ public boolean isValid(DatasetFieldValue value, ConstraintValidatorContext conte // Note, length validation for FieldType.TEXT was removed to accommodate migrated data that is greater than 255 chars. if (fieldType.equals(FieldType.URL) && !lengthOnly) { - - String[] schemes = {"http","https", "ftp"}; - UrlValidator urlValidator = new UrlValidator(schemes); - - try { - if (urlValidator.isValid(value.getValue())) { - } else { - context.buildConstraintViolationWithTemplate(dsfType.getDisplayName() + " " + value.getValue() + " is not a valid URL.").addConstraintViolation(); - return false; - } - } catch (NullPointerException npe) { + boolean isValidUrl = URLValidator.isURLValid(value.getValue()); + if (!isValidUrl) { + context.buildConstraintViolationWithTemplate(dsfType.getDisplayName() + " " + value.getValue() + " {url.invalid}").addConstraintViolation(); return false; } - } if (fieldType.equals(FieldType.EMAIL) && !lengthOnly) { - if(value.getDatasetField().isRequired() && value.getValue()==null){ + boolean isValidMail = EMailValidator.isEmailValid(value.getValue()); + if (!isValidMail) { + context.buildConstraintViolationWithTemplate(dsfType.getDisplayName() + " " + value.getValue() + " {email.invalid}").addConstraintViolation(); return false; } - - return EMailValidator.isEmailValid(value.getValue(), context); - } return true; diff --git a/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java b/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java index 29f08d885cd..c0235c512fe 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java @@ -56,6 +56,7 @@ import edu.harvard.iq.dataverse.util.StringUtil; import edu.harvard.iq.dataverse.util.SystemConfig; +import edu.harvard.iq.dataverse.validation.URLValidator; import edu.harvard.iq.dataverse.workflows.WorkflowComment; import java.io.File; diff --git a/src/main/java/edu/harvard/iq/dataverse/DataverseContact.java b/src/main/java/edu/harvard/iq/dataverse/DataverseContact.java index d19f20d5ebd..46021ddbc9b 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DataverseContact.java +++ b/src/main/java/edu/harvard/iq/dataverse/DataverseContact.java @@ -16,7 +16,8 @@ import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; -import org.hibernate.validator.constraints.Email; + +import edu.harvard.iq.dataverse.validation.ValidateEmail; import org.hibernate.validator.constraints.NotBlank; /** diff --git a/src/main/java/edu/harvard/iq/dataverse/EMailValidator.java b/src/main/java/edu/harvard/iq/dataverse/EMailValidator.java deleted file mode 100644 index 4091c9dfee9..00000000000 --- a/src/main/java/edu/harvard/iq/dataverse/EMailValidator.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package edu.harvard.iq.dataverse; - -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; - -import edu.harvard.iq.dataverse.util.BundleUtil; -import org.apache.commons.validator.routines.EmailValidator; - -/** - * - * @author skraffmi - */ -public class EMailValidator implements ConstraintValidator { - - @Override - public void initialize(ValidateEmail constraintAnnotation) { - - } - - @Override - public boolean isValid(String value, ConstraintValidatorContext context) { - - return isEmailValid(value, context); - - - } - - public static boolean isEmailValid(String value, ConstraintValidatorContext context) { - //this null check is not needed any more as the null check is done in datasetfieldvaluevalidator -// if (value == null) { -// //A null email id is not valid, as email is a required field. -// return false; -// } - boolean isValid = EmailValidator.getInstance().isValid(value); - if (!isValid) { - if (context != null) { - context.buildConstraintViolationWithTemplate(value + " " + BundleUtil.getStringFromBundle("email.invalid")).addConstraintViolation(); - } - return false; - } - return true; - } -} diff --git a/src/main/java/edu/harvard/iq/dataverse/MailServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/MailServiceBean.java index 04956ccc756..bd5f27b9e83 100644 --- a/src/main/java/edu/harvard/iq/dataverse/MailServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/MailServiceBean.java @@ -38,6 +38,8 @@ import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; + +import edu.harvard.iq.dataverse.validation.EMailValidator; import org.apache.commons.lang3.StringUtils; /** @@ -188,7 +190,7 @@ public void sendMail(String reply, String to, String subject, String messageText logger.severe(ex.getMessage()); } msg.setFrom(fromAddress); - if (EMailValidator.isEmailValid(reply, null)) { + if (EMailValidator.isEmailValid(reply)) { // But set the reply-to address to direct replies to the requested 'from' party if it is a valid email address msg.setReplyTo(new Address[] {new InternetAddress(reply)}); } else { diff --git a/src/main/java/edu/harvard/iq/dataverse/Shib.java b/src/main/java/edu/harvard/iq/dataverse/Shib.java index b71fe3cd566..324f6e185a6 100644 --- a/src/main/java/edu/harvard/iq/dataverse/Shib.java +++ b/src/main/java/edu/harvard/iq/dataverse/Shib.java @@ -15,6 +15,7 @@ import edu.harvard.iq.dataverse.util.BundleUtil; import edu.harvard.iq.dataverse.util.JsfHelper; import edu.harvard.iq.dataverse.util.SystemConfig; +import edu.harvard.iq.dataverse.validation.EMailValidator; import org.apache.commons.lang3.StringUtils; import java.io.IOException; @@ -190,12 +191,12 @@ public void init() { } } - if (!EMailValidator.isEmailValid(emailAddressInAssertion, null)) { + if (!EMailValidator.isEmailValid(emailAddressInAssertion)) { String msg = "The SAML assertion contained an invalid email address: \"" + emailAddressInAssertion + "\"."; logger.info(msg); msg=BundleUtil.getStringFromBundle("shib.invalidEmailAddress", Arrays.asList(emailAddressInAssertion)); String singleEmailAddress = ShibUtil.findSingleValue(emailAddressInAssertion); - if (EMailValidator.isEmailValid(singleEmailAddress, null)) { + if (EMailValidator.isEmailValid(singleEmailAddress)) { msg = "Multiple email addresses were asserted by the Identity Provider (" + emailAddressInAssertion + " ). These were sorted and the first was chosen: " + singleEmailAddress; logger.info(msg); emailAddress = singleEmailAddress; diff --git a/src/main/java/edu/harvard/iq/dataverse/URLValidator.java b/src/main/java/edu/harvard/iq/dataverse/URLValidator.java deleted file mode 100644 index ac8620b0123..00000000000 --- a/src/main/java/edu/harvard/iq/dataverse/URLValidator.java +++ /dev/null @@ -1,50 +0,0 @@ -package edu.harvard.iq.dataverse; -import edu.harvard.iq.dataverse.util.BundleUtil; -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; -import org.apache.commons.validator.routines.UrlValidator; - -/** - * - * @author skraffmi - */ -public class URLValidator implements ConstraintValidator { - - @Override - public void initialize(ValidateURL constraintAnnotation) { - - } - - @Override - public boolean isValid(String value, ConstraintValidatorContext context) { - - boolean valid = isURLValid(value); - if (context != null && !valid) { - context.buildConstraintViolationWithTemplate(value + " " + BundleUtil.getStringFromBundle("url.invalid")).addConstraintViolation(); - } - return valid; - } - - public static boolean isURLValid(String value) { - if (value == null || value.isEmpty()) { - return true; - } - - String[] schemes = {"http","https", "ftp"}; - UrlValidator urlValidator = new UrlValidator(schemes); - - try { - if (urlValidator.isValid(value)) { - } else { - return false; - } - } catch (NullPointerException npe) { - return false; - } - - return true; - - } - - -} diff --git a/src/main/java/edu/harvard/iq/dataverse/UserNameValidator.java b/src/main/java/edu/harvard/iq/dataverse/UserNameValidator.java deleted file mode 100644 index a86f95f6a3f..00000000000 --- a/src/main/java/edu/harvard/iq/dataverse/UserNameValidator.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package edu.harvard.iq.dataverse; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; - -/** - * - * @author sarahferry - * Modeled after PasswordValidator and EMailValidator - */ - -public class UserNameValidator implements ConstraintValidator { - @Override - public void initialize(ValidateUserName constraintAnnotation) { - - } - - // note: while the ConstraintValidatorContext is not used in this method, - // it is required in order to impelement the ConstraintValidator interface - @Override - public boolean isValid(String value, ConstraintValidatorContext context) { - return isUserNameValid(value); - } - - /** - * Here we will validate the username - * - * @param username - * @return boolean - */ - public static boolean isUserNameValid(final String username) { - if (username == null) { - return false; - } - //TODO: What other characters do we need to support? - String validCharacters = "[a-zA-Z0-9\\_\\-\\."; - /* - * if you would like to support accents or chinese characters, uncomment this - * - //support accents - validCharacters += "À-ÿ\\u00C0-\\u017F"; - //support chinese characters - validCharacters += "\\x{4e00}-\\x{9fa5}"; - * - */ - //end - validCharacters += "]"; - validCharacters += "{2,60}"; //must be between 2 and 60 characters for user name - Pattern p = Pattern.compile(validCharacters); - Matcher m = p.matcher(username); - return m.matches(); - } - -} - - - diff --git a/src/main/java/edu/harvard/iq/dataverse/ValidateUserName.java b/src/main/java/edu/harvard/iq/dataverse/ValidateUserName.java deleted file mode 100644 index 0cd8fcb4443..00000000000 --- a/src/main/java/edu/harvard/iq/dataverse/ValidateUserName.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package edu.harvard.iq.dataverse; - -import java.lang.annotation.Documented; -import static java.lang.annotation.ElementType.FIELD; -import java.lang.annotation.Retention; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import java.lang.annotation.Target; -import javax.validation.Constraint; -import javax.validation.Payload; - -/** - * - * @author sarahferry - */ - -@Target({FIELD}) -@Retention(RUNTIME) -@Constraint(validatedBy = {UserNameValidator.class}) -@Documented -public @interface ValidateUserName { - String message() default "Failed Validation Username"; - - Class[] groups() default {}; - - Class[] payload() default {}; - -} - diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java index 4085b504578..101cd570ccd 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java @@ -13,7 +13,7 @@ import edu.harvard.iq.dataverse.DataverseRequestServiceBean; import edu.harvard.iq.dataverse.DataverseSession; import edu.harvard.iq.dataverse.DvObject; -import edu.harvard.iq.dataverse.EMailValidator; +import edu.harvard.iq.dataverse.validation.EMailValidator; import edu.harvard.iq.dataverse.EjbDataverseEngine; import edu.harvard.iq.dataverse.GlobalId; import edu.harvard.iq.dataverse.UserServiceBean; @@ -97,7 +97,7 @@ import java.io.IOException; import java.io.OutputStream; -import edu.harvard.iq.dataverse.util.json.JsonPrinter; + import static edu.harvard.iq.dataverse.util.json.JsonPrinter.json; import static edu.harvard.iq.dataverse.util.json.JsonPrinter.rolesToJson; import static edu.harvard.iq.dataverse.util.json.JsonPrinter.toJsonArray; @@ -659,7 +659,7 @@ public Response builtin2shib(String content) { String overwriteEmail = randomUser.get("email"); overwriteEmail = newEmailAddressToUse; logger.info("overwriteEmail: " + overwriteEmail); - boolean validEmail = EMailValidator.isEmailValid(overwriteEmail, null); + boolean validEmail = EMailValidator.isEmailValid(overwriteEmail); if (!validEmail) { // See https://github.com/IQSS/dataverse/issues/2998 return error(Response.Status.BAD_REQUEST, "invalid email: " + overwriteEmail); @@ -816,7 +816,7 @@ public Response builtin2oauth(String content) { String overwriteEmail = randomUser.get("email"); overwriteEmail = newEmailAddressToUse; logger.info("overwriteEmail: " + overwriteEmail); - boolean validEmail = EMailValidator.isEmailValid(overwriteEmail, null); + boolean validEmail = EMailValidator.isEmailValid(overwriteEmail); if (!validEmail) { // See https://github.com/IQSS/dataverse/issues/2998 return error(Response.Status.BAD_REQUEST, "invalid email: " + overwriteEmail); diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/groups/impl/builtin/BuiltInGroupsProvider.java b/src/main/java/edu/harvard/iq/dataverse/authorization/groups/impl/builtin/BuiltInGroupsProvider.java index af9ab080443..d67d3caa24c 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/groups/impl/builtin/BuiltInGroupsProvider.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/groups/impl/builtin/BuiltInGroupsProvider.java @@ -9,7 +9,6 @@ import edu.harvard.iq.dataverse.engine.command.DataverseRequest; import java.util.Collections; import java.util.Set; -import org.hibernate.validator.internal.util.CollectionHelper; /** * Provider for the built-in, hard coded groups. This class is a singleton (no @@ -56,7 +55,7 @@ public Set groupsFor(DataverseRequest req) { @Override public Set groupsFor(RoleAssignee ra) { if (ra instanceof AuthenticatedUser){ - return CollectionHelper.asSet(AllUsers.get(), AuthenticatedUsers.get()); + return Set.of(AllUsers.get(), AuthenticatedUsers.get()); } else if ( ra instanceof User) { return Collections.singleton(AllUsers.get()); } else { @@ -72,6 +71,6 @@ public Group get(String groupAlias) { @Override public Set findGlobalGroups() { - return CollectionHelper.asSet(AllUsers.get(), AuthenticatedUsers.get()); + return Set.of(AllUsers.get(), AuthenticatedUsers.get()); } } diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/BuiltinUser.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/BuiltinUser.java index 9ae4e4b0e87..c2510b8b043 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/BuiltinUser.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/BuiltinUser.java @@ -1,10 +1,9 @@ package edu.harvard.iq.dataverse.authorization.providers.builtin; -import edu.harvard.iq.dataverse.ValidateEmail; -import edu.harvard.iq.dataverse.ValidateUserName; +import edu.harvard.iq.dataverse.validation.ValidateUserName; import edu.harvard.iq.dataverse.authorization.AuthenticatedUserDisplayInfo; import edu.harvard.iq.dataverse.passwordreset.PasswordResetData; -import static edu.harvard.iq.dataverse.util.StringUtil.nonEmpty; + import java.io.Serializable; import javax.persistence.CascadeType; import javax.persistence.Column; @@ -18,8 +17,8 @@ import javax.persistence.OneToOne; import javax.persistence.Table; import javax.persistence.Transient; +import javax.validation.constraints.NotBlank; import javax.validation.constraints.Size; -import org.hibernate.validator.constraints.NotBlank; /** * @@ -42,10 +41,8 @@ public class BuiltinUser implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - - @NotBlank(message = "{user.enterUsername}") - @Size(min=2, max=60, message = "{user.usernameLength}") - @ValidateUserName(message = "{user.illegalCharacters}") + + @ValidateUserName @Column(nullable = false, unique=true) private String userName; diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/DataverseUserPage.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/DataverseUserPage.java index 177c59c5873..da0500c734d 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/DataverseUserPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/DataverseUserPage.java @@ -10,12 +10,12 @@ import edu.harvard.iq.dataverse.DataverseServiceBean; import edu.harvard.iq.dataverse.DataverseSession; import edu.harvard.iq.dataverse.DvObject; -import edu.harvard.iq.dataverse.EMailValidator; +import edu.harvard.iq.dataverse.validation.EMailValidator; import edu.harvard.iq.dataverse.PermissionServiceBean; import edu.harvard.iq.dataverse.PermissionsWrapper; import edu.harvard.iq.dataverse.RoleAssignment; import edu.harvard.iq.dataverse.SettingsWrapper; -import edu.harvard.iq.dataverse.UserNameValidator; +import edu.harvard.iq.dataverse.validation.UserNameValidator; import edu.harvard.iq.dataverse.UserNotification; import edu.harvard.iq.dataverse.UserNotificationServiceBean; import edu.harvard.iq.dataverse.UserServiceBean; @@ -225,7 +225,7 @@ public void validateUserName(FacesContext context, UIComponent toValidate, Objec public void validateUserEmail(FacesContext context, UIComponent toValidate, Object value) { String userEmail = (String) value; - boolean emailValid = EMailValidator.isEmailValid(userEmail, null); + boolean emailValid = EMailValidator.isEmailValid(userEmail); if (!emailValid) { ((UIInput) toValidate).setValid(false); FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, BundleUtil.getStringFromBundle("oauth2.newAccount.emailInvalid"), null); diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2FirstLoginPage.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2FirstLoginPage.java index 4c0170a906b..54ba3ec6a05 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2FirstLoginPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2FirstLoginPage.java @@ -1,11 +1,11 @@ package edu.harvard.iq.dataverse.authorization.providers.oauth2; import edu.harvard.iq.dataverse.DataverseSession; -import edu.harvard.iq.dataverse.EMailValidator; +import edu.harvard.iq.dataverse.validation.EMailValidator; import edu.harvard.iq.dataverse.UserNotification; import edu.harvard.iq.dataverse.UserNotificationServiceBean; -import edu.harvard.iq.dataverse.ValidateEmail; -import edu.harvard.iq.dataverse.UserNameValidator; +import edu.harvard.iq.dataverse.validation.ValidateEmail; +import edu.harvard.iq.dataverse.validation.UserNameValidator; import edu.harvard.iq.dataverse.authorization.AuthTestDataServiceBean; import edu.harvard.iq.dataverse.authorization.AuthUtil; import edu.harvard.iq.dataverse.authorization.AuthenticatedUserDisplayInfo; @@ -259,7 +259,7 @@ public void validateUserName(FacesContext context, UIComponent toValidate, Objec */ public void validateUserEmail(FacesContext context, UIComponent toValidate, Object value) { String userEmail = (String) value; - boolean emailValid = EMailValidator.isEmailValid(userEmail, null); + boolean emailValid = EMailValidator.isEmailValid(userEmail); if (!emailValid) { ((UIInput) toValidate).setValid(false); FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, BundleUtil.getStringFromBundle("oauth2.newAccount.emailInvalid"), null); diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/shib/ShibUtil.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/shib/ShibUtil.java index 8d34bed4f2f..8d523ceae2f 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/shib/ShibUtil.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/shib/ShibUtil.java @@ -4,7 +4,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import edu.harvard.iq.dataverse.EMailValidator; +import edu.harvard.iq.dataverse.validation.EMailValidator; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -151,7 +151,7 @@ public static String generateFriendlyLookingUserIdentifer(String usernameAsserti logger.fine(ex + " parsing " + email); } } else { - boolean passedValidation = EMailValidator.isEmailValid(email, null); + boolean passedValidation = EMailValidator.isEmailValid(email); logger.fine("Odd email address. No @ sign ('" + email + "'). Passed email validation: " + passedValidation); } } else { diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java b/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java index 9d76ce0e47c..65e62debf76 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java @@ -3,8 +3,7 @@ import edu.harvard.iq.dataverse.Cart; import edu.harvard.iq.dataverse.DatasetLock; import edu.harvard.iq.dataverse.UserNotification; -import edu.harvard.iq.dataverse.ValidateEmail; -import edu.harvard.iq.dataverse.authorization.AccessRequest; +import edu.harvard.iq.dataverse.validation.ValidateEmail; import edu.harvard.iq.dataverse.authorization.AuthenticatedUserDisplayInfo; import edu.harvard.iq.dataverse.authorization.AuthenticatedUserLookup; import edu.harvard.iq.dataverse.authorization.providers.oauth2.OAuth2TokenData; diff --git a/src/main/java/edu/harvard/iq/dataverse/passwordreset/PasswordResetPage.java b/src/main/java/edu/harvard/iq/dataverse/passwordreset/PasswordResetPage.java index 4ef4fd51737..b9eabf45159 100644 --- a/src/main/java/edu/harvard/iq/dataverse/passwordreset/PasswordResetPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/passwordreset/PasswordResetPage.java @@ -3,7 +3,7 @@ import edu.harvard.iq.dataverse.DataverseServiceBean; import edu.harvard.iq.dataverse.DataverseSession; import edu.harvard.iq.dataverse.SettingsWrapper; -import edu.harvard.iq.dataverse.ValidateEmail; +import edu.harvard.iq.dataverse.validation.ValidateEmail; import edu.harvard.iq.dataverse.actionlogging.ActionLogRecord; import edu.harvard.iq.dataverse.actionlogging.ActionLogServiceBean; import edu.harvard.iq.dataverse.authorization.AuthenticationServiceBean; diff --git a/src/main/java/edu/harvard/iq/dataverse/validation/EMailValidator.java b/src/main/java/edu/harvard/iq/dataverse/validation/EMailValidator.java new file mode 100644 index 00000000000..5050aad5bf7 --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/validation/EMailValidator.java @@ -0,0 +1,28 @@ +package edu.harvard.iq.dataverse.validation; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +import org.apache.commons.validator.routines.EmailValidator; + +/** + * + * @author skraffmi + */ +public class EMailValidator implements ConstraintValidator { + + @Override + public boolean isValid(String value, ConstraintValidatorContext context) { + return isEmailValid(value); + } + + /** + * Validate an email address in a null safe way (null = valid). + * (Null is valid to allow for optional values - use @NotNull to enforce!) + * @param value The email address to validate + * @return true when valid, false when invalid (null = valid!) + */ + public static boolean isEmailValid(String value) { + return value == null || EmailValidator.getInstance().isValid(value); + } +} diff --git a/src/main/java/edu/harvard/iq/dataverse/validation/URLValidator.java b/src/main/java/edu/harvard/iq/dataverse/validation/URLValidator.java new file mode 100644 index 00000000000..846ae48783a --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/validation/URLValidator.java @@ -0,0 +1,50 @@ +package edu.harvard.iq.dataverse.validation; +import edu.harvard.iq.dataverse.util.BundleUtil; +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import org.apache.commons.validator.routines.UrlValidator; + +/** + * + * @author skraffmi + */ +public class URLValidator implements ConstraintValidator { + + private String[] allowedSchemes; + @Override + public void initialize(ValidateURL constraintAnnotation) { + this.allowedSchemes = constraintAnnotation.schemes(); + } + + @Override + public boolean isValid(String value, ConstraintValidatorContext context) { + return isURLValid(value, this.allowedSchemes); + } + + /** + * Check if a URL is valid in a nullsafe way. (null = valid to allow optional values). + * Empty values are no valid URLs. This variant allows default schemes HTTP, HTTPS and FTP. + * + * @param value The URL to validate + * @return true when valid (null is also valid) or false + */ + public static boolean isURLValid(String value) { + // default schemes == ValidateURL schemes() default + return isURLValid(value, new String[]{"http", "https", "ftp"}); + } + + /** + * Check if a URL is valid in a nullsafe way. (null = valid to allow optional values). + * Empty values are no valid URLs. This variant allows any schemes you hand over. + * + * @param value The URL to validate + * @param schemes The list of allowed schemes + * @return true when valid (null is also valid) or false + */ + public static boolean isURLValid(String value, String[] schemes) { + UrlValidator urlValidator = new UrlValidator(schemes); + return value == null || urlValidator.isValid(value); + } + + +} diff --git a/src/main/java/edu/harvard/iq/dataverse/validation/UserNameValidator.java b/src/main/java/edu/harvard/iq/dataverse/validation/UserNameValidator.java new file mode 100644 index 00000000000..873512299ea --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/validation/UserNameValidator.java @@ -0,0 +1,49 @@ +package edu.harvard.iq.dataverse.validation; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * This class is not implementing the ConstraintValidatorMatcher interface, as this is not necessary any more. + * It serves as the storage for the annotation configuration and convenient interface to a programmatic + * validation of usernames. + */ +public class UserNameValidator { + + public static final int MIN_CHARS = 2; + public static final int MAX_CHARS = 60; + + // NOTE: the size is checked by either the @Size annotation of @ValidateUserName or programmatically below! + public static final String USERNAME_PATTERN = "[a-zA-Z0-9\\_\\-\\.]*"; + + /* + * If you would like to support accents or chinese characters in usernames, choose one of the below. + * + * With support for accents: + private static final String USERNAME_PATTERN = "[a-zA-Z0-9\\_\\-\\.À-ÿ\\u00C0-\\u017F]"; + * + * With support for chinese characters: + private static final String USERNAME_PATTERN = "[a-zA-Z0-9\\_\\-\\.\\x{4e00}-\\x{9fa5}]"; + */ + + private static final Matcher usernameMatcher = Pattern.compile(USERNAME_PATTERN).matcher(""); + + /** + * Validate a username against the pattern in {@link #USERNAME_PATTERN} + * and check for length: min {@link #MIN_CHARS} chars, max {@link #MAX_CHARS} chars. + * Nullsafe - null is considered invalid (as is empty). + * + * @param username The username to validate + * @return true if matching, false otherwise + */ + public static boolean isUserNameValid(final String username) { + return username != null && + username.length() >= MIN_CHARS && + username.length() <= MAX_CHARS && + usernameMatcher.reset(username).matches(); + } + +} + + + diff --git a/src/main/java/edu/harvard/iq/dataverse/ValidateEmail.java b/src/main/java/edu/harvard/iq/dataverse/validation/ValidateEmail.java similarity index 82% rename from src/main/java/edu/harvard/iq/dataverse/ValidateEmail.java rename to src/main/java/edu/harvard/iq/dataverse/validation/ValidateEmail.java index cadbbbf1407..310dc950858 100644 --- a/src/main/java/edu/harvard/iq/dataverse/ValidateEmail.java +++ b/src/main/java/edu/harvard/iq/dataverse/validation/ValidateEmail.java @@ -3,7 +3,7 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package edu.harvard.iq.dataverse; +package edu.harvard.iq.dataverse.validation; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.*; @@ -21,8 +21,8 @@ @Retention(RUNTIME) @Constraint(validatedBy = {EMailValidator.class}) @Documented -public @interface ValidateEmail { - String message() default "Failed Validation Email Address"; +public @interface ValidateEmail { + String message() default "'${validatedValue}' {email.invalid}"; Class[] groups() default {}; diff --git a/src/main/java/edu/harvard/iq/dataverse/ValidateURL.java b/src/main/java/edu/harvard/iq/dataverse/validation/ValidateURL.java similarity index 75% rename from src/main/java/edu/harvard/iq/dataverse/ValidateURL.java rename to src/main/java/edu/harvard/iq/dataverse/validation/ValidateURL.java index 106876e423e..5aaab0c2e8e 100644 --- a/src/main/java/edu/harvard/iq/dataverse/ValidateURL.java +++ b/src/main/java/edu/harvard/iq/dataverse/validation/ValidateURL.java @@ -1,5 +1,5 @@ -package edu.harvard.iq.dataverse; +package edu.harvard.iq.dataverse.validation; import java.lang.annotation.Documented; import static java.lang.annotation.ElementType.FIELD; @@ -14,8 +14,8 @@ @Constraint(validatedBy = {URLValidator.class}) @Documented public @interface ValidateURL { - - String message() default "Failed Validation for Validate URL"; + String message() default "'${validatedValue}' {url.invalid}"; + String[] schemes() default {"http", "https", "ftp"}; Class[] groups() default {}; diff --git a/src/main/java/edu/harvard/iq/dataverse/validation/ValidateUserName.java b/src/main/java/edu/harvard/iq/dataverse/validation/ValidateUserName.java new file mode 100644 index 00000000000..0583b70df49 --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/validation/ValidateUserName.java @@ -0,0 +1,41 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package edu.harvard.iq.dataverse.validation; + +import java.lang.annotation.Documented; +import static java.lang.annotation.ElementType.FIELD; +import java.lang.annotation.Retention; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.annotation.Target; +import javax.validation.Constraint; +import javax.validation.Payload; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; +import javax.validation.constraints.Pattern; + +/** + * + * @author sarahferry + */ + +@Target({FIELD}) +@Retention(RUNTIME) +// This is empty by intention - we are just recombining existing bean validation here. +// The class UserNameValidator is just for convenience and historic reasons. +@Constraint(validatedBy = {}) + +@NotBlank(message = "{user.enterUsername}") +@Size(min = UserNameValidator.MIN_CHARS, max = UserNameValidator.MAX_CHARS, message = "{user.usernameLength}") +@Pattern(regexp = UserNameValidator.USERNAME_PATTERN, message = "{user.illegalCharacters}") + +@Documented +public @interface ValidateUserName { + String message() default ""; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/src/main/java/propertyFiles/Bundle.properties b/src/main/java/propertyFiles/Bundle.properties index 9895cffe0e7..5035325ee8d 100644 --- a/src/main/java/propertyFiles/Bundle.properties +++ b/src/main/java/propertyFiles/Bundle.properties @@ -2293,12 +2293,6 @@ dataset.file.uploadWarning=upload warning dataset.file.uploadWorked=upload worked dataset.file.upload.popup.explanation.tip=For more information, please refer to the Duplicate Files section of the User Guide. -#EmailValidator.java -email.invalid=is not a valid email address. - -#URLValidator.java -url.invalid=is not a valid URL. - #HarvestingClientsPage.java harvest.start.error=Sorry, harvest could not be started for the selected harvesting client configuration (unknown server error). harvest.delete.error=Selected harvesting client cannot be deleted; unknown exception: diff --git a/src/test/java/edu/harvard/iq/dataverse/DatasetFieldValueValidatorTest.java b/src/test/java/edu/harvard/iq/dataverse/DatasetFieldValueValidatorTest.java index 7e3f326923a..ceaa69ade4e 100644 --- a/src/test/java/edu/harvard/iq/dataverse/DatasetFieldValueValidatorTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/DatasetFieldValueValidatorTest.java @@ -5,42 +5,27 @@ */ package edu.harvard.iq.dataverse; +import java.util.Set; import java.util.regex.Pattern; import javax.validation.ConstraintValidatorContext; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import static org.junit.Assert.*; +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; import org.mockito.Mockito; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; + /** * * @author skraffmi */ public class DatasetFieldValueValidatorTest { - - - public DatasetFieldValueValidatorTest() { - } - - @BeforeClass - public static void setUpClass() { - } - - @AfterClass - public static void tearDownClass() { - } - - @Before - public void setUp() { - } - - @After - public void tearDown() { - } - /** * Test of isValid method, of class DatasetFieldValueValidator. @@ -124,33 +109,6 @@ public void testIsValid() { value.setValue("12.14"); result = instance.isValid(value, ctx); assertEquals(false, result); - - //URL - dft.setFieldType(DatasetFieldType.FieldType.URL); - value.setValue("https://www.google.com"); - result = instance.isValid(value, ctx); - assertEquals(true, result); - - value.setValue("http://google.com"); - result = instance.isValid(value, ctx); - assertEquals(true, result); - - value.setValue("https://do-not-exist-123-123.com/"); // does not exist - result = instance.isValid(value, ctx); - assertEquals(true, result); - - value.setValue("ftp://somesite.com"); - result = instance.isValid(value, ctx); - assertEquals(true, result); - - value.setValue("google.com"); - result = instance.isValid(value, ctx); - assertEquals(false, result); - - value.setValue("git@github.com:IQSS/dataverse.git"); - result = instance.isValid(value, ctx); - assertEquals(false, result); - } @Test @@ -199,4 +157,60 @@ public void testIsValidAuthorIdentifierGnd() { assertFalse(validator.isValidAuthorIdentifier("junk", pattern)); } + final Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); + + @ParameterizedTest + @CsvSource( + { + "true, https://www.google.com", + "true, http://google.com", + "true, https://do-not-exist-123-123.com/", + "true, ftp://somesite.com", + "false, google.com", + "false, git@github.com:IQSS/dataverse.git" + } + ) + public void testInvalidURL(boolean expected, String url) { + // given + String fieldName = "testField"; + + DatasetField field = new DatasetField(); + field.setDatasetFieldType(new DatasetFieldType(fieldName, DatasetFieldType.FieldType.URL, false)); + DatasetFieldValue sut = new DatasetFieldValue(field); + sut.setValue(url); + + // when + Set> violations = validator.validate(sut); + + // then + assertEquals(expected, violations.size() < 1); + violations.stream().findFirst().ifPresent(c -> { + assertTrue(c.getMessage().startsWith(fieldName + " " + url + " ")); + assertTrue(c.getMessage().contains("not")); + assertTrue(c.getMessage().contains("URL")); + }); + } + + @Test + public void testInvalidEmail() { + // given + String fieldName = "testField"; + String invalidMail = "myinvalidmail"; + + DatasetField field = new DatasetField(); + field.setDatasetFieldType(new DatasetFieldType(fieldName, DatasetFieldType.FieldType.EMAIL, false)); + DatasetFieldValue sut = new DatasetFieldValue(field); + sut.setValue(invalidMail); + + // when + Set> violations = validator.validate(sut); + + // then + assertTrue(violations.size() == 1); + violations.stream().findFirst().ifPresent(c -> { + assertTrue(c.getMessage().startsWith(fieldName + " " + invalidMail + " ")); + assertTrue(c.getMessage().contains("not")); + assertTrue(c.getMessage().contains("email")); + }); + } } diff --git a/src/test/java/edu/harvard/iq/dataverse/EMailValidatorTest.java b/src/test/java/edu/harvard/iq/dataverse/EMailValidatorTest.java deleted file mode 100644 index 2518f6486e3..00000000000 --- a/src/test/java/edu/harvard/iq/dataverse/EMailValidatorTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package edu.harvard.iq.dataverse; - -import org.apache.commons.validator.routines.EmailValidator; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class EMailValidatorTest { - - static EmailValidator validator = EmailValidator.getInstance(); - - @ParameterizedTest - @CsvSource(value = { - "true, 'pete@mailinator.com'", - "false, ' leadingWhitespace@mailinator.com'", - "false, 'trailingWhitespace@mailinator.com '", - - "false, 'elisah.da mota@example.com'", - "false, 'pete1@mailinator.com;pete2@mailinator.com'", - - /** - * These examples are all from https://randomuser.me and seem to be - * valid according to - * http://sphinx.mythic-beasts.com/~pdw/cgi-bin/emailvalidate (except - * رونیکا.محمدخان@example.com). - */ - "true, 'michélle.pereboom@example.com'", - "true, 'begüm.vriezen@example.com'", - "true, 'lótus.gonçalves@example.com'", - "true, 'lótus.gonçalves@éxample.com'", - "true, 'begüm.vriezen@example.cologne'", - "true, 'رونیکا.محمدخان@example.com'", - "false, 'lótus.gonçalves@example.cóm'", - "false, 'dora@.com'", - "false, ''", - "false, NULL", - - // add tests for 4601 - "true, 'blah@wiso.uni-unc.de'", - "true, 'foo@essex.co.uk'", - "true, 'jack@bu.cloud'" - }, nullValues = "NULL") - public void testIsEmailValid(boolean expected, String mail) { - assertEquals(expected, validator.isValid(mail)); - } -} diff --git a/src/test/java/edu/harvard/iq/dataverse/URLValidatorTest.java b/src/test/java/edu/harvard/iq/dataverse/URLValidatorTest.java deleted file mode 100644 index f994809a0c0..00000000000 --- a/src/test/java/edu/harvard/iq/dataverse/URLValidatorTest.java +++ /dev/null @@ -1,55 +0,0 @@ - -package edu.harvard.iq.dataverse; - -import static org.junit.Assert.assertEquals; - -import javax.validation.ConstraintValidatorContext; - -import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorContextImpl; -import org.hibernate.validator.internal.engine.path.PathImpl; -import javax.validation.Validation; -import javax.validation.ValidatorFactory; -import org.junit.Test; - -/** - * - * @author skraffmi - */ -public class URLValidatorTest { - ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory(); - - - @Test - public void testIsURLValid() { - assertEquals(true, URLValidator.isURLValid(null)); - assertEquals(true, URLValidator.isURLValid("")); - assertEquals(true, URLValidator.isURLValid("https://twitter.com/")); - - assertEquals(false, URLValidator.isURLValid("cnn.com")); - - } - - @Test - public void testIsValidWithUnspecifiedContext() { - String value = "https://twitter.com/"; - ConstraintValidatorContext context = null; - assertEquals(true, new URLValidator().isValid(value, context)); - } - - @Test - public void testIsValidWithContextAndValidURL() { - String value = "https://twitter.com/"; - ConstraintValidatorContext context = new ConstraintValidatorContextImpl(validatorFactory.getClockProvider(), PathImpl.createPathFromString(""),null, null); - - assertEquals(true, new URLValidator().isValid(value, context)); - } - - @Test - public void testIsValidWithContextButInvalidURL() { - String value = "cnn.com"; - ConstraintValidatorContext context = new ConstraintValidatorContextImpl(validatorFactory.getClockProvider(), PathImpl.createPathFromString(""),null, null); - - assertEquals(false, new URLValidator().isValid(value, context)); - } - -} diff --git a/src/test/java/edu/harvard/iq/dataverse/UserNameValidatorTest.java b/src/test/java/edu/harvard/iq/dataverse/UserNameValidatorTest.java deleted file mode 100644 index 000651d829a..00000000000 --- a/src/test/java/edu/harvard/iq/dataverse/UserNameValidatorTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package edu.harvard.iq.dataverse; - -import static org.junit.Assert.assertEquals; - -import java.util.Arrays; -import java.util.Collection; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -/** - * - * @author sarahferry - * @author alexscheitlin - */ -@RunWith(Parameterized.class) -public class UserNameValidatorTest { - - public boolean isValid; - public String userName; - - public UserNameValidatorTest(boolean isValid, String userName) { - this.isValid = isValid; - this.userName = userName; - } - - @Parameters - public static Collection parameters() { - return Arrays.asList(new Object[][] { - // good usernames - { true, "sarah" }, - { true, ".-_5Arah_-." }, - - // dont allow accents - { false, "àèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝâêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿÄËÏÖÜŸçÇßØøÅåÆæœ" }, - - // dont allow chinese characters - { false, "谁日吧爸好" }, - - // dont allow middle white space - { false, "sarah f" }, - - // dont allow leading white space - { false, " sarah" }, - - // dont allow trailing white space - { false, "sarah " }, - - // dont allow symbols - { false, "sarah!" }, - { false, "sarah?" }, - { false, "sarah:(" }, - { false, "💲🅰️®️🅰️🚧" }, - - // only allow between 2 and 60 characters - { false, "q" }, - { true, "q2" }, - { false, "q2jsalfhjopiwurtiosfhkdhasjkdhfgkfhkfrhnefcn4cqonroclmooi4oiqwhrfq4jrlqhaskdalwehrlwhflhklasdjfglq0kkajfelirhilwhakjgv" }, - { false, "" }, - { false, null } - }); - } - - @Test - public void testIsUserNameValid() { - assertEquals(isValid, UserNameValidator.isUserNameValid(userName)); - } -} diff --git a/src/test/java/edu/harvard/iq/dataverse/validation/EMailValidatorTest.java b/src/test/java/edu/harvard/iq/dataverse/validation/EMailValidatorTest.java new file mode 100644 index 00000000000..80d848248c0 --- /dev/null +++ b/src/test/java/edu/harvard/iq/dataverse/validation/EMailValidatorTest.java @@ -0,0 +1,85 @@ +package edu.harvard.iq.dataverse.validation; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; + +import java.util.Set; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class EMailValidatorTest { + + private final Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); + + public static Stream emailExamples() { + return Stream.of( + Arguments.of("true", "pete@mailinator.com"), + Arguments.of("false", " leadingWhitespace@mailinator.com"), + Arguments.of("false", "trailingWhitespace@mailinator.com "), + Arguments.of("false", "elisah.da mota@example.com"), + Arguments.of("false", "pete1@mailinator.com;pete2@mailinator.com"), + + /* + * These examples are all from https://randomuser.me and seem to be + * valid according to + * http://sphinx.mythic-beasts.com/~pdw/cgi-bin/emailvalidate (except رونیکا.محمدخان@example.com) + */ + Arguments.of("true", "michélle.pereboom@example.com"), + Arguments.of("true", "begüm.vriezen@example.com"), + Arguments.of("true", "lótus.gonçalves@example.com"), + Arguments.of("true", "lótus.gonçalves@éxample.com"), + Arguments.of("true", "begüm.vriezen@example.cologne"), + Arguments.of("true", "رونیکا.محمدخان@example.com"), + Arguments.of("false", "lótus.gonçalves@example.cóm"), + Arguments.of("false", "dora@.com"), + Arguments.of("false", ""), + // Null means "no value given" - that's valid, you'll need to use @NotNull or similar to enforce a value! + Arguments.of("true", null), + + // add tests for 4601 + Arguments.of("true", "blah@wiso.uni-unc.de"), + Arguments.of("true", "foo@essex.co.uk"), + Arguments.of("true", "jack@bu.cloud") + ); + } + + @ParameterizedTest + @MethodSource("emailExamples") + public void testIsEmailValid(boolean expected, String mail) { + assertEquals(expected, EMailValidator.isEmailValid(mail)); + } + + /** + * This is a simple test class, as we defined the annotation for fields only. + */ + private final class SubjectClass { + @ValidateEmail + String mail; + + SubjectClass(String mail) { + this.mail = mail; + } + } + + @ParameterizedTest + @MethodSource("emailExamples") + public void testConstraint(boolean expected, String mail) { + // given + SubjectClass sut = new SubjectClass(mail); + + //when + Set> violations = validator.validate(sut); + + // then + assertEquals(expected ? 0 : 1, violations.size()); + violations.stream().findFirst().ifPresent( c -> { + assertTrue(c.getMessage().contains(mail)); }); + } +} diff --git a/src/test/java/edu/harvard/iq/dataverse/validation/URLValidatorTest.java b/src/test/java/edu/harvard/iq/dataverse/validation/URLValidatorTest.java new file mode 100644 index 00000000000..3fe8501bbbf --- /dev/null +++ b/src/test/java/edu/harvard/iq/dataverse/validation/URLValidatorTest.java @@ -0,0 +1,107 @@ +package edu.harvard.iq.dataverse.validation; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.Set; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * + * @author skraffmi + */ +public class URLValidatorTest { + + final Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); + + public static Stream stdUrlExamples() { + return Stream.of( + Arguments.of(true, null), + Arguments.of(false, ""), + Arguments.of(true, "https://twitter.com"), + Arguments.of(true, "http://foobar.com:9101"), + Arguments.of(true, "ftp://user@foobar.com"), + Arguments.of(false, "cnn.com"), + Arguments.of(false, "smb://user@foobar.com") + ); + } + + @ParameterizedTest + @MethodSource("stdUrlExamples") + public void testIsURLValid(boolean expected, String url) { + assertEquals(expected, URLValidator.isURLValid(url)); + } + + /** + * This is a simple test class, as we defined the annotation for fields only. + */ + private final class SubjectClass { + @ValidateURL + String url; + + SubjectClass(String url) { + this.url = url; + } + } + + @ParameterizedTest + @MethodSource("stdUrlExamples") + public void testConstraint(boolean expected, String url) { + // given + URLValidatorTest.SubjectClass sut = new URLValidatorTest.SubjectClass(url); + + //when + Set> violations = validator.validate(sut); + + // then + assertEquals(expected ? 0 : 1, violations.size()); + violations.stream().findFirst().ifPresent( c -> { + assertTrue(c.getMessage().contains(url)); }); + } + + public static Stream fancyUrlExamples() { + return Stream.of( + Arguments.of(true, null), + Arguments.of(false, ""), + Arguments.of(false, "https://twitter.com"), + Arguments.of(true, "http://foobar.com:9101"), + Arguments.of(false, "ftp://user@foobar.com"), + Arguments.of(false, "cnn.com"), + Arguments.of(true, "smb://user@foobar.com") + ); + } + + /** + * This is a simple test class like above, but with a scheme given + */ + private final class SubjectSchemeClass { + @ValidateURL(schemes = {"http", "smb"}) + String url; + + SubjectSchemeClass(String url) { + this.url = url; + } + } + + @ParameterizedTest + @MethodSource("fancyUrlExamples") + public void testConstraintWithSchemes(boolean expected, String url) { + // given + URLValidatorTest.SubjectSchemeClass sut = new URLValidatorTest.SubjectSchemeClass(url); + + //when + Set> violations = validator.validate(sut); + + // then + assertEquals(expected ? 0 : 1, violations.size()); + violations.stream().findFirst().ifPresent( c -> { + assertTrue(c.getMessage().contains(url)); }); + } +} diff --git a/src/test/java/edu/harvard/iq/dataverse/validation/UserNameValidatorTest.java b/src/test/java/edu/harvard/iq/dataverse/validation/UserNameValidatorTest.java new file mode 100644 index 00000000000..a9816f81dca --- /dev/null +++ b/src/test/java/edu/harvard/iq/dataverse/validation/UserNameValidatorTest.java @@ -0,0 +1,82 @@ +package edu.harvard.iq.dataverse.validation; + +import java.util.Set; +import java.util.stream.Stream; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class UserNameValidatorTest { + + public static Stream usernameExamples() { + return Stream.of( + // good usernames + Arguments.of(true, "sarah"), + Arguments.of(true, ".-_5Arah_-."), + // dont allow accents + Arguments.of(false, "àèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝâêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿÄËÏÖÜŸçÇßØøÅåÆæœ"), + // dont allow chinese characters + Arguments.of(false, "谁日吧爸好"), + // dont allow middle white space + Arguments.of(false, "sarah f"), + // dont allow leading white space + Arguments.of(false, " sarah"), + // dont allow trailing white space + Arguments.of(false, "sarah "), + // dont allow symbols + Arguments.of(false, "sarah!"), + Arguments.of(false, "sarah?"), + Arguments.of(false, "sarah:("), + Arguments.of(false, "💲🅰️®️🅰️🚧"), + // only allow between 2 and 60 characters + Arguments.of(false, "q"), + Arguments.of(true, "q2"), + Arguments.of(false, "q2jsalfhjopiwurtiosfhkdhasjkdhfgkfhkfrhnefcn4cqonroclmooi4oiqwhrfq4jrlqhaskdalwehrlwhflhklasdjfglq0kkajfelirhilwhakjgv"), + Arguments.of(false, "q2jsalfhjopiwurtiosfhkdhasj!1! !#fhkfrhnefcn4cqonroclmooi4oiqwhrfq4jrlqhaskdalwehrlwhflhklasdjfglq0kkajfelirhilwhakjgv"), + Arguments.of(false, ""), + Arguments.of(false, null) + ); + } + + @ParameterizedTest + @MethodSource("usernameExamples") + public void testUsernames(boolean expected, String username) { + assertEquals(expected, UserNameValidator.isUserNameValid(username)); + } + + /** + * This is a simple test class, as we defined the annotation for fields only. + */ + private final class SubjectClass { + @ValidateUserName + String username; + + SubjectClass(String username) { + this.username = username; + } + } + + private final Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); + + @ParameterizedTest + @MethodSource("usernameExamples") + public void testConstraint(boolean expected, String username) { + // given + UserNameValidatorTest.SubjectClass sut = new UserNameValidatorTest.SubjectClass(username); + + //when + Set> violations = validator.validate(sut); + + // then + assertEquals(expected, violations.size() < 1); + // TODO: one might add tests for the two violations (size and illegal chars) here... + } + +}