Search code examples
c#asp.netvalidationasp.net-identityidentityserver4

How to use IdentityServer4 with Custom password validation with ASP.NET Microsoft Identity


I am working with IdentityServer4 and using ASP.NET Identity, and would like to do custom password validation so that I can add validation for password expiration (such as if password is older than 90 days then make the user change the password, etc...).

I ran across the method .AddPasswordValidator<> when setting the services.AddIdentity in the ConfigureServices() method of the Startup.cs, but am unable to find any clear documentation on how to implement it.

Can anyone help with implementation or point me toward some example code of something similar? (Or possibly help with understanding where / how I could implement some custom validation of users/passwords with IdentityServer4)?


Solution

  • I don't think that a password validator is what you need but since you've asked -
    An example of a custom password validator (not my code, link to the article below) :

    public class SameCharacterPasswordValidator<TUser>: IPasswordValidator<TUser> 
           where TUser : class
    {
        public Task<IdentityResult> ValidateAsync(UserManager<TUser> manager, 
                                                  TUser user, 
                                                  string password)
        {
            return Task.FromResult(password.Distinct().Count() == 1 ? 
                IdentityResult.Failed(new IdentityError
                {
                    Code = "SameChar",
                    Description = "Passwords cannot be all the same character."
                }) : 
                IdentityResult.Success);
        }
    }
    

    You can apply your custom validator within the ConfigureServices method

    services.AddIdentity<ApplicationUser, IdentityRole>(options =>
    {
        // Basic built in validations
        options.Password.RequireDigit = true;
        options.Password.RequireLowercase = true;
        options.Password.RequireNonLetterOrDigit = true;
        options.Password.RequireUppercase = true;
        options.Password.RequiredLength = 6;
    })
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders()
        // Your custom validator here
        .AddPasswordValidator<SameCharacterPasswordValidator<ApplicationUser>>();
    

    Here's a good article about ASP.NET Identity's password validator: https://elanderson.net/2016/03/asp-net-core-password-options-and-custom-validators/

    Note that the password validators are meant to check that the password stands in the format you want it to be (something like a regular expression). Therefore, expiration of a password has nothing to do with it. That's metadata on your password, has nothing to do with the password's format.
    For that use case, you could add a field to your AspNetUsers table (you'll be able to do it by extending the class inheriting from IdentityUser (probably called ApplicationUser) of PasswordChangedAt Date field.
    Then, every time the user logs in you should check for that validation yourself.

    P.S: It's important to realize that password's strength or anything that has to do with your user store actually has nothing to do with IdentityServer. IdentityServer acts as your STS (Security Token Service).
    It took me some time to realize it myself, and that's why I think it's worth mentioning, even though it might be obvious to you.