Asp.Net MVC password Validation with a Regular Expression

January 19, 2018    Development Asp.Net MVC

Asp.Net MVC Password Validation with a Regular Expression

Originally posted on GeeksWithBlogs.net on May 26th, 2013.

I have requirement (specification) that the password has to be at least 7 characters long and contain a special character ([email protected]#$&*()-_+=) which are all the specials in the number keyboard row. I found that using the RegularExpression DataAnnotations is really slick, but there was a point that caught me for a while.

The problem is that @“.([[email protected]#$&()-+=]+).$” works in the UI, but fails in the unit test. @”[[email protected]#$&()-+=]+” works in the test, but not in the UI (the MVC unobtrusive library wants a full match). When I removed the ‘()’ it works in both. So my solution, after losing some time, is to add the escape before the ‘-’. This works: ^.(?=.[[email protected]#$%^&\(\)_\-+=]).$ (thanks to my co-worker Jason).

Here comes the code:

The Model for the MVC binding. Focus on the RegEx for NewPassword:

public class PasswordResetModel
{
    /// <summary>
    /// Gets or sets the new password.
    /// It must be at least 7 characters and have at least one special character.
    /// </summary>
    /// <value>
    /// The new password.
    /// </value>
    [Required(ErrorMessageResourceType = typeof(AuthenticationModelsResource),
        ErrorMessageResourceName = "NewPasswordRequiredMessage")]
    [StringLength(100, ErrorMessageResourceType = typeof(AuthenticationModelsResource),
        ErrorMessageResourceName = "PasswordTooShortErrorMessage", MinimumLength = 7)]
    [RegularExpression(@"^.*(?=.*[[email protected]#$%^&*\\(\\)_\\-+=\]).*$",
        ErrorMessageResourceType = typeof(AuthenticationModelsResource),
        ErrorMessageResourceName = "PasswordNotStrongEnoughMessage")]
    [DataType(DataType.Password)]
    [Display(ResourceType = typeof(AuthenticationModelsResource), Name = "NewPassword"]
    public string NewPassword { get; set; }

    /// <summary>
    /// Gets or sets the confirm password.
    /// </summary>
    /// <value>
    /// The confirm password.
    /// </value>
    [DataType(DataType.Password)]
    [Display(ResourceType = typeof(AuthenticationModelsResource), Name = "ConfirmNewPassword")]
    [Required(ErrorMessageResourceType = typeof(AuthenticationModelsResource),
       ErrorMessageResourceName = "ConfirmNewPasswordRequiredMessage")]
    [Compare("NewPassword", ErrorMessageResourceType = typeof(AuthenticationModelsResource),
        ErrorMessageResourceName = "PasswordCompareErrorMessage")]
    public string ConfirmPassword { get; set; }
}

The Unit test:

[TestMethod,TestCategory("HomeController")]
public void It_Should_Validate_Password_Doesnt_Have_A_Special_Character()
{
    PasswordResetViewModel vm = new PasswordResetViewModel("match", 10)
                            {
                                PasswordResetModel =
                                {
                                    NewPassword = "test1122",
                                    ConfirmPassword = "test1122"
                                }
                            };
    ((ChangePasswordModel)vm.PasswordResetModel).OldPassword = "test1";
    this.Controller.PasswordReset(vm);

    // assert
    ValidateViewModel(vm.PasswordResetModel, this.Controller);
    Should.BooleanAssertionExtensions.ShouldBeTrue(this.Controller.ModelState.Values.Last()
        .Errors.Any(e => e.ErrorMessage == AuthenticationModelsResource.PasswordNotStrongEnoughMessage));
}

The ValidateViewModel method:

protected static void ValidateViewModel<TVm, TC>(TVm viewModelToValidate, TC controller) where TC : Controller
{
    var modelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => viewModelToValidate, viewModelToValidate.GetType());
    var validator = ModelValidator.GetModelValidator(modelMetadata, controller.ControllerContext);
    var result = validator.Validate(viewModelToValidate);
    foreach (var validationResult in result)
    {
        if (!string.IsNullOrWhiteSpace(validationResult.MemberName))
        {
            controller.ModelState.AddModelError(validationResult.MemberName, validationResult.Message);
        }
        else
        {
            controller.ModelState.AddModelError(string.Empty, validationResult.Message);
        }
    }
}

The MVC Unobtrusive Validation library wants a complete match (from the source code):

$jQval.addMethod("regex", function (value, element, params) {
    var match;
    if (this.optional(element)) {
        return true;
    }

    match = new RegExp(params).exec(value);
    return (match && (match.index === 0) && (match\[0\].length === value.length));
});


comments powered by Disqus

Please consider using Brave and adding me to your payment ledger. Then you won't have to see ads!

Support me and download Brave!

Use Brave