Can
Can

Reputation: 709

Dynamically change PasswordValidator settings Asp.net Mvc

I'm managing different customer in my application and all customers are using same mvc application. But i need to change password validation logic based on customer.

I created a default password policy in IdentityConfig.cs Create method as shown below:

public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
    {
        var manager = new ApplicationUserManager(context.Get<ApplicationDbContext>());
        // Configure validation logic for usernames
        manager.UserValidator = new UserValidator<ApplicationUser>(manager)
        {
            AllowOnlyAlphanumericUserNames = false,
            RequireUniqueEmail = true
        };

        // Configure validation logic for passwords
        manager.PasswordValidator = new PasswordValidator
        {
            RequiredLength = 6,
            RequireNonLetterOrDigit = true,
            RequireDigit = true,
            RequireLowercase = true,
            RequireUppercase = true,
        };

        // Configure user lockout defaults
        manager.UserLockoutEnabledByDefault = true;
        manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
        manager.MaxFailedAccessAttemptsBeforeLockout = 5;

        return manager;
    }

But i need to mmanage PasswordValidator customer specific. I am getting current customer from subdomain i mean if my url is http://example.com/customer1 , then i know this is customer1 and get password policy settings from database. I take these settings into Session variable. Can i use Session variables in IdentityConfig Create method, or how can i override PasswordValidator properties after session is created ?

Upvotes: 1

Views: 1205

Answers (2)

Gambit
Gambit

Reputation: 223

I encountered a similar problem when defining my validators in the manager. Once that's done, they don't seem like they can be adjusted anymore.

In the end I made a separate function where I get the policies and applied them to the IdentityOpions. After that, I can create my validators with those options and add it to the manager. It seems like the validators take the Options into account as default values rather than allowing you to adjust them on the fly.

public class ApplicationUserManager : UserManager<ApplicationUser>
{
   internal void SetPolicies(Dictionary<string, string> passwordPolicies)
   { // do stuff in a loop, like getting the policies like this:
   Options.Password.RequireDigit = policy.value;

   // Then create and add the validator with the new policies in place.
    _passwordValidator = new PasswordValidator<ApplicationUser>();
   this.PasswordValidators.Add(_passwordValidator);
   }
}

Upvotes: 0

Hooman Bahreini
Hooman Bahreini

Reputation: 15559

You can create your own custom password validator by extending IIdentityValidator:

// your first validator logic
public class CustomPasswordValidator1: IIdentityValidator<string>
{
    public CustomPasswordValidator1(int length)
    {
        RequiredLength = length;
    }

    public int RequiredLength { get; set; }

    public Task<IdentityResult> ValidateAsync(string password)
    {
        // write your own validation logic here
        if (string.IsNullOrEmpty(password) || password.Length < RequiredLength)
        {
            return Task.FromResult(IdentityResult.Failed("bad password"));
        }

        // good password            
        return Task.FromResult(IdentityResult.Success);
    }
}

// your second validator logic
public class CustomPasswordValidator2: IIdentityValidator<string>
{
    public CustomPasswordValidator2(int length)
    {
        RequiredLength = length;
    }

    public int RequiredLength { get; set; }

    public Task<IdentityResult> ValidateAsync(string password)
    {
        // write some other validation logic
    }
}

See here for more info on how to extend IIdentityValidator


Now, that you have CustomPasswordValidator1 and CustomPasswordValidator2, you can change your ApplicationUserManager code, and use the correct validator logic:

 public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
 {
    var manager = new ApplicationUserManager(new CustomUserStore(context.Get<ApplicationDbContext>()));

    manager.UserValidator = new UserValidator<ApplicationUser, long>(manager)
    {
        AllowOnlyAlphanumericUserNames = false,
        RequireUniqueEmail = true
    };
    if (/* some condition */)
    {
        manager.PasswordValidator = new CustomPasswordValidator1(6 /*min length*/ );
    }
    else 
    {
        manager.PasswordValidator = new CustomPasswordValidator2(12 /*min length*/);
    }
    // more code...

Upvotes: 1

Related Questions