Dealing with different password validation schemes in a single app

May 20, 2009 – 3:25 pm Tags: , ,

If your application is well thought out, you would not want to save any data that isn’t valid. So what do you do, when you need different validation schemes, say for passwords, depending on some special case?

For example: Your user passwords need to be at least 8 characters long and contain upper and lower case letters, a number and a special character, but when one of your users forget their password, you would like to generate a new one which does not have to conform to those conditions.

There are some approaches to this, such as using more than one validation function in your user object, or using some boolean flag to enable or disable the validation. These are kind of clunky, though, and there is a better approach: Using a “policy” – Policies can be used for other things than this too, but let’s look at how to use a policy for managing password validation.

An example scenario

First, let’s look at the example scenario of user passwords a bit more closely.

We have a User object, which contains code that will validate a newly set password. The code that’s responsible for saving users to the DB will not allow us to store anything that does not validate, because having invalid data stored is not a very good idea.

The user works something like this:

//set a valid password
$user->setPassword('Xyz123!');
 
//true
$user->isValid();
 
//set an invalid password
$user->setPassword('zxcqwe');
 
//no longer true
$user->isValid();

In the case where we have a simpler, invalid, password it could be generated by some algorithm to create random simple passwords for users when they forget their own.

As mentioned before, we could add some flag to isValid or have a separate method for setting the random password which makes it ignore the validation. While these are easy to implement, they aren’t very obvious: A boolean parameter to isValid could mean a lot more than “ignore password validation”, and using two methods has similar problems. It would also make it a bit more difficult to modify our password validation rules later.

Instead, we’ll create some policy objects and use those.

What is a policy?

In our example, a policy means the rules used to validate a password. We could call it a password validator too, but I think a policy is a quite descriptive word for this, as we only want to set a specific policy like “RandomPasswordPolicy” – we don’t really care how it validates the password, as long as randomly generated passwords validate with it. In fact, it might even just not validate it at all and always return that it’s valid.

The policy object will define a method to call to check if a password validates with the policy. This way we can define a policy, assign it to the user, and then the password will get validated based on the policy.

By default, we can have a policy like this:

//Let's just assume the IPasswordPolicy interface defines the validatePassword method
class ComplexPasswordPolicy implements IPasswordPolicy {
  public function validatePassword($password) {
    //password must be at least 8 chars long
    if(strlen($password) < 8) {
      return false;
    }
 
    //password must contain an upper case letter
    if(preg_match('/[A-Z]/', $password) == 0) {
      return false;
    }
 
    //password must contain a number
    if(preg_match('/[0-9]/', $password) == 0) {
      return false;
    }
 
    //and a special character
    if(preg_match('/[^A-Za-z0-9]/', $password) == 0) {
      return false;
    }
 
    return true;
  }
}

For the randomly generated password, we’ll have this very simple policy:

class RandomPasswordPolicy implements IPasswordPolicy {
  public function validatePassword($password) {
    return true;
  }
}

Using the policy with the user

Now that we have a policy with the validation rules, we will need to change the user’s isValid method to test the password using the policy.
By default, the user object will come with the ComplexPasswordPolicy, so any new user that is created will need a good password and if a user wishes to change their password, it will also need to pass the complex validation.

However, in our code which generates a new password for users who forget theirs, we can now easily swap the validation policy to the simple one:

//We'll assume $user is the user who forgot their password
$user->setPasswordPolicy( new RandomPasswordPolicy() );
 
$user->setPassword($randomPassword);
 
//Now the user will validate even if the randomly generated password isn't very complex
$user->isValid();

Conclusion

Using a swappable policy is useful if you need to be able to change some aspect of your code. This is quite similar to the strategy pattern too, it just has a different name.

Share this:
  1. 6 Responses to “Dealing with different password validation schemes in a single app”

  2. Nice, straight to the point article.
    PS. “policy” is yet another name for “Dependency injection” IMO

    By Orkan on May 20, 2009

  3. Hi Jani

    I need to ask U. Why bound validation with model… or with forms/form->model objects (like sf did)?
    I know that it look easy and nice but it will introduce difficulties later on. Common character of input data (POST, GT, headers in Http or *args in CLI) is that its validable in single point place. Why make your life harder?

    Cheers, Alan

    By Alan on May 20, 2009

  4. I don’t see how separating some validation logic into a policy object will make it more difficult at any point.

    You are correct that often the validation is done in a single point, but not always. For example, you might have a CLI script, unit tests and the actual web page, which all need the validation code to be available, thus it’s best placed into the model or some object usable in the model. Not to mention that it’s a part of the “business logic” so it’s a natural place for it.

    Orkan: I guess you could say “injecting” the validation algorithm like this is a bit like DI, but I would not really call it that.

    By Jani Hartikainen on May 20, 2009

  5. It will be more flexible to make policies as a private array in the class and then use foreach loop to check all of them. In this case you can make the object more universal and define methods like addPolicy() for instance…

    By oleg on May 20, 2009

  6. That is a nice use of the strategy pattern, although I’d argue that you should use dependency injection to specify the policy rather than an out-of-band setPasswordPolicy() call.

    By Alan Pinstein on May 23, 2009

  1. 1 Trackback(s)

  2. May 23, 2009: Jani Hartikainen’s Blog: Dealing with different password validation schemes in a single app | Webs Developer

Post a Comment

You can use some HTML (a, em, strong, etc.). If you want to post code, use <pre lang="PHP">code here</pre> (you can replace PHP with the language you are posting)