2

I'm trying to validate user input in password form using razor pages. I have the following model

    public class UserPassword
    {
        public Guid? Id{ get; set; }
        public string Code { get; set; }
        [StringLength(32, MinimumLength = 8, ErrorMessage = "The password must at least be 8 characters")]
        [RegularExpression("[A-Z]", ErrorMessage = "The password Must contain atleast one uppercase character")]
        public string Password { get; set; }
        [Compare("Password")]
        public string ConfirmedPassword { get; set; }
    }

With the generated .cshtlm

@page "{id}/{code}"
@model AuthenticationService.Pages.UserPasswordModel

@{
    ViewData["Title"] = "UserPassword";
}

<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="UserPassword.Password" class="control-label"></label>
                <input asp-for="UserPassword.Password" class="form-control" />
                <span asp-validation-for="UserPassword.Password" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="UserPassword.ConfirmedPassword" class="control-label"></label>
                <input asp-for="UserPassword.ConfirmedPassword" class="form-control" />
                <span asp-validation-for="UserPassword.ConfirmedPassword" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

Additionally the OnGet() and OnPostAsync() methods can be seen below

 public IActionResult OnGet()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }
            return Page();
        }

        [BindProperty]
        public UserPassword UserPassword { get; set; }

        public async Task<IActionResult> OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }
            UserPassword.Id = Guid.Parse(RouteData.Values["id"].ToString());
            UserPassword.Code = Base64Utility.UrlSafeDecode(RouteData.Values["code"].ToString());
            var user = await _userManager.FindByIdAsync(UserPassword.Id.ToString());
            var result = await _userManager.ConfirmEmailAsync(user, UserPassword.Code);
            if (result.Succeeded)
            {
                await _userManager.RemovePasswordAsync(user);
                await _userManager.AddPasswordAsync(user, UserPassword.ConfirmedPassword);
                return RedirectToPage("./Confirmation");
            }
            return RedirectToPage("./Error");
        }

My problem is with the Data annotation regular expression. The regular expression only matches the first character of the input form, and when additional characters are added to the input form the ErrorMessage "Must contain an uppercase character" are shown, even when there are multiple uppercase character as seen in the image below. Example of <code>ErrorMessage</code>

Jakobo06
  • 65
  • 5
  • [A-Z] means "Match one character in the set 'A to Z' You probably want [A-Z]{8,} – Duston Aug 22 '19 at 20:34
  • 1
    It seems like you do not know how to build a password regex pattern. Well, lucky for you are not the only one. Look at this answer and find the best pattern that works for you https://stackoverflow.com/a/21456918/6938368 – M.Hazara Aug 22 '19 at 20:46
  • Thanks A lot @M.Hazara it was of course a problem with the regex – Jakobo06 Aug 22 '19 at 20:49

2 Answers2

2

Your regex pattern only matches one character, you will have to add a regex pattern to match the whole string. See examples here: https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.regularexpressionattribute?view=netcore-2.2

Tiago
  • 68
  • 6
  • The * (0 or more) wouldn't work because OP's requirements are minimum of 8 characters. – Duston Aug 22 '19 at 20:38
  • The password requirement is at least one uppercase character. When I use the suggested pattern: `@"[A-Z]*"`the entirety of the string has the be uppercase otherwise the ErrorMessage shows up – Jakobo06 Aug 22 '19 at 20:44
1

For a working pattern, you could try "(?=.*[A-Z]).*".

For understandable pattern, you could try ".*[A-Z]+.*" which means that:

  • .* there is any chacter
  • [A-Z]+ there is one or more uppercase.
Edward
  • 28,296
  • 11
  • 76
  • 121