“Passwords Evolved” is an open source WordPress plugin that I’ve built and maintained over the years. It’s a security plugin that prevents someone from using a password that has appeared in a data breach. To do that, it leverages the “Have I Been Pwned?” API to check if the password you’re using was found in a breach.
The plugin also changes the hashing function used to hash WordPress passwords. Initially, the plugin only supported the bcrypt hashing function. This hashing function has been standard since PHP 5.5.
Since PHP 7.0, it’s been possible to hash passwords using a newer function called Argon2. Argon2 is available natively since PHP 7.2. Before that, you had to use the libsodium library to use Argon2 with PHP. There’s also a libsodium compatibility layer starting in WordPress 5.2.
Checking for and using all these different hashing functions sounds like a headache waiting to happen. But, in fact, it’s not that hard to design a set of classes to handle all these different cases. The “Chain-of-Responsibility” pattern was created for situations such as this one.
What is the “Chain-of-Responsibility” pattern?
So “Chain-of-Responsibility” sounds like a mouthful, but it’s not too complicated in practice. A good analogy for it is the if ... elseif ... elseif
conditionals chain. The “Chain-of-Responsibility” pattern is basically the object-oriented version of that chain. (Thus the name!)
So that’s the idea with the “Chain-of-Responsibility” pattern. You have a chain of objects. And whenever you want to perform an operation on some input, you pass it to that chain. The chain will pass it from one object to the next until one of them can perform an operation on it. Just like you would with that if ... elseif ... elseif
chain.
The diagram above shows the chain in action. The chain has three objects, and the input passes from object to object. But since the second object decides to perform an action on the input, the third object never gets to interact with it.
This highlights the big difference between the “Chain-of-Responsibility” pattern and the better-known decorator pattern. With the decorator pattern, every object gets to interact and “decorate” the input. It’s not just one object that gets to interact with it.
Besides this, both patterns work nearly identically. So, if you’re already familiar with the decorator pattern, the inner workings of the “Chain-of-Responsibility” pattern won’t surprise you. Both patterns have a similar implementation.
Starting with an interface
The core element of this implementation of the “Chain-of-Responsibility” pattern is going to be an interface. For the “Passwords Evolved” plugin, that interface was the PasswordHasherInterface
interface. Here’s a look at it:
/** * A password hasher hashes a password using a hashing algorithm. */ interface PasswordHasherInterface { /** * Hashes the given password. Returns null if unable to hash password. * * @param string $password * * @return string|null */ public function hash_password($password); /** * Checks if the password hasher supports the given hash for verification. * * @param string $hash * * @return bool */ public function is_hash_supported($hash); /** * Checks if the given hash is valid. If a hash is invalid, we need to rehash it. * * @param string $hash * * @return bool */ public function is_hash_valid($hash); /** * Validates that the given password matches the given hash. * * @param string $password * @param string $hash * * @return bool */ public function is_password_valid($password, $hash); }
The PasswordHasherInterface
(shown above) has four methods. Three of them perform actions on a hash value or password. These are the inputs that we described earlier.
Those three action-performing methods are the hash_password
, is_hash_valid
and is_password_valid
methods. The hash_password
method takes a password
turns it into a hash value. The is_hash_valid
method checks if the given hash value is a valid hash
value or not. The is_password_valid
method checks if the given password
is valid for the given hash
value.
The fourth method in the PasswordHasherInterface
interface is the is_hash_supported
method. This method is central to this implementation of the “Chain-of-Responsibility” pattern. It’s the method used to determine if our object in the chain can perform actions on the given hash
.
Whenever you use any of the three action-performing methods, the chain will start calling the is_hash_supported
method on all the objects in the chain. The first object in the chain that returns true
will be the one selected to perform the requested action. The value returned by the action is the one returned by the chain.
Creating some password hashers
Now that we have the PasswordHasherInterface
interface, we can move on to designing our classes. Before we create our chain, we’ll create some password hashers that we can use with it. For this article, we’ll create two.
WordPress password hasher
The first password hasher that we’ll create will hash passwords using WordPress’s built-in PasswordHash
class. We’re going to call it WordPressPasswordHasher
. You can see the code for it below.
/** * Password hasher that uses the builtin WordPress password hasher. */ class WordPressPasswordHasher implements PasswordHasherInterface { /** * WordPress password hasher. * * @var \PasswordHash */ private $wordpress_hasher; /** * Constructor. * * @param \PasswordHash $wordpress_hasher */ public function __construct(\PasswordHash $wordpress_hasher) { $this->wordpress_hasher = $wordpress_hasher; } /** * {@inheritdoc} */ public function hash_password($password) { return $this->wordpress_hasher->HashPassword($password); } /** * {@inheritdoc} */ public function is_hash_supported($hash) { return 0 === strpos($hash, '$P$'); } /** * {@inheritdoc} */ public function is_hash_valid($hash) { return false; } /** * {@inheritdoc} */ public function is_password_valid($password, $hash) { return $this->wordpress_hasher->CheckPassword($password, $hash); } }
Wrapper methods
The WordPressPasswordHasher
class is just a wrapper around the PasswordHash
class. This means that, for a lot of PasswordHasherInterface
methods, we’re just going to call a PasswordHash
method. (This is why it’s a good example of the adapter pattern!) Because of that, the WordPressPasswordHasher
constructor will just take a PasswordHash
object as an argument. We then assign it to the wordpress_hasher
class property.
Next, let’s look at the implementations of the PasswordHasherInterface
methods. Two of them call a method on the PasswordHash
object stored inside our WordPressPasswordHasher
object. There’s hash_password
which calls the HashPassword
method of the PasswordHash
object. And then there’s is_password_valid
which calls the CheckPassword
method.
The two more interesting methods to discuss are is_hash_supported
and is_hash_valid
. The is_hash_supported
method uses the strpos
function to check if a hash starts with $P$
. But what does $P$
mean and why are we looking for it?
The reason why we look for $P$
is because of how hash functions work. Each function will prefix a hash value that it generates. That way, you can tell it created the hash value. For the PasswordHash
class, that prefix is $P$
and that’s why we’re looking for it.
The last method is is_hash_valid
. You might be wondering why it returns false
without even looking at the hash value. This is intended because of what the plugin wants to do. It wants WordPress passwords to use a stronger hashing function.
So by always returning false
, we’re forcing the plugin to discard any hash value created by the PasswordHash
class. Instead, the plugin will have to rehash the password using a stronger hashing function. This might seem weird but it’ll make more sense once we go over how the “chain” works later in the article.
Native password hasher
For the second password hasher, we’re going to use PHP’s native password hashing functions. These functions can use different hashing algorithms such as Argon2. But by default, they use bcrypt.
As for the class, we’ll name it NativePasswordHasher
. It’ll also implement the PasswordHasherInterface
interface. (All classes in the chain should.) Here’s what the code for the class.
/** * Password hasher that uses the native PHP password hashing functions. */ class NativePasswordHasher implements PasswordHasherInterface { /** * Algorithm used when hashing a password. * * @var int */ private $algorithm; /** * Constructor. */ public function __construct() { $this->algorithm = PASSWORD_DEFAULT; if (defined('PASSWORD_ARGON2ID')) { $this->algorithm = PASSWORD_ARGON2ID; } elseif (defined('PASSWORD_ARGON2I')) { $this->algorithm = PASSWORD_ARGON2I; } } /** * {@inheritdoc} */ public function hash_password($password) { return password_hash($password, $this->algorithm); } /** * {@inheritdoc} */ public function is_hash_supported($hash) { if (0 === strpos($hash, '$argon2id$')) { return defined('PASSWORD_ARGON2ID'); } elseif (0 === strpos($hash, '$argon2i$')) { return defined('PASSWORD_ARGON2I'); } return 0 === strpos($hash, '$2'); } /** * {@inheritdoc} */ public function is_hash_valid($hash) { return !password_needs_rehash($hash, $this->algorithm); } /** * {@inheritdoc} */ public function is_password_valid($password, $hash) { return password_verify($password, $hash); } }
Choosing an algorithm
The interesting part of the NativePasswordHasher
class is the constructor. This is where we’re going to choose the hashing algorithm used by the class. We’ll store that hashing algorithm value in the algorithm
class property.
Choosing the algorithm is simply a question of detecting PHP password constants using the defined
function. By default, we’re going to assign the PASSWORD_DEFAULT
constant value to the algorithm
property. This constant stores the default hashing algorithm used by PHP.
At this time, this default algorithm is bcrypt. We could have also just used its constant called PASSWORD_BCRYPT
instead. But, either way, both PASSWORD_DEFAULT
and PASSWORD_BCRYPT
are identical.
The rest of the constructor is just two guard clauses. They check if PHP supports one of the two possible Argon2 hashing algorithms. If PHP does, we change the value of the algorithm
property.
The first constant that we look for is PASSWORD_ARGON2ID
. This is the preferred Argon2 hashing algorithm. That said, it’s only available starting with PHP 7.3. So, to support PHP 7.2, we check for the PASSWORD_ARGON2I
constant as well.
Using the algorithm
Now that we set the algorithm
class property, we can look at how we use it in the NativePasswordHasher
class. The two methods that make use of it are the hash_password
and is_hash_valid
methods. Both use the algorithm
class property as the second argument of a PHP password function.
These two functions are password_hash
and password_needs_rehash
. The hash_password
method uses the password_hash
function to create a hash value using our chosen algorithm. Meanwhile, the is_hash_valid
uses the password_needs_rehash
function to check if a hash value is valid for our chosen algorithm.
Checking the hash
The last two methods don’t use the algorithm. The is_hash_supported
method is very similar to the one in the WordPressPasswordHasher
class. We use it to check if the NativePasswordHasher
supports the given hash value.
The is_hash_supported
method is a bit more complex than the one in the WordPressPasswordHasher
class. That’s because we have to check for three hash prefixes. Two prefixes are for the two Argon2 algorithms and the third one is for bcrypt.
Checking if we support Argon2 algorithms is done in two steps. First, we check if the hash value contains the algorithm prefix. If it does, we check if the password constant is defined using the defined
function. If we get to the end of the method, we check for the bcrypt prefix only since it’s the default algorithm.
Verifying the password also doesn’t require the algorithm
class property. All that you have to do is pass the password
and hash
value to the password_verify
password function. password_verify
will figure out which algorithm to use by checking the hash value prefix like we’ve been doing.
Designing the chain
Now that we have some password hashers, we can move on to designing our chain. We’re going to call it PasswordHasherChain
. Unlike our password hashers, we’re going to take a bit more time explaining the design of the class.
/** * Manages a chain of password hashers. */ class PasswordHasherChain implements PasswordHasherInterface { }
But first, let’s start by creating the empty PasswordHasherChain
class. It implements the PasswordHasherInterface
interface that our password hashers also implement. The fact that all these classes share the same interface is one of the most crucial aspects of the design.
Constructor
To begin, we’re going to add the constructor to our PasswordHasherChain
.
/** * Manages a chain of password hashers. */ class PasswordHasherChain implements PasswordHasherInterface { /** * The password hashers that the chain handles. * * @var PasswordHasherInterface[] */ private $password_hashers; /** * Constructor. * * @param PasswordHasherInterface[] $password_hashers */ public function __construct(array $password_hashers = []) { $this->password_hashers = $password_hashers; } // ... }
You can see above that the constructor has a single parameter called password_hashers
. We assign it to a class property also called password_hashers
. We type hinted the password_hashers
constructor parameter as an array
with a default of an empty array.
More type safety
The problem with an array
type hint is that it doesn’t give us a lot of type safety. The password_hashers
array can contain any type of value. But we want it to contain only PasswordHasherInterface
objects.
So we’re going to add some extra type safety to our constructor. We’re going to do that by running the password_hashers
array through an array function. For what we’re trying to do, that array function will be the array_filter
function.
/** * Manages a chain of password hashers. */ class PasswordHasherChain implements PasswordHasherInterface { /** * The password hashers that the chain handles. * * @var PasswordHasherInterface[] */ private $password_hashers; /** * Constructor. * * @param PasswordHasherInterface[] $password_hashers */ public function __construct(array $password_hashers = []) { $this->password_hashers = array_filter($password_hashers, function ($password_hasher) { return $password_hasher instanceof PasswordHasherInterface; }); } // ... }
Above is the updated PasswordHasherChain
constructor using the array_filter
function. The array_filter
function will remove all array elements that our callback
returns false
for. Here, that callback
is an anonymous function.
This anonymous function receives a password_hasher
as an argument. It’ll then determine whether password_hasher
is an instance of PasswordHasherInterface
or not. It does this by using the instanceof
operator. The operator will return true
if password_hasher
is an instance of PasswordHasherInterface
. Otherwise, it’ll return false
.
We assign the array returned by the array_filter
function to password_hashers
array class property like before. But now, we’re sure that the array only contains PasswordHasherInterface
objects. This will allow us to use it without worrying that there might be invalid data in it.
Selecting a password hasher
The use of the array_filter
function in the PasswordHasherChain
class constructor was really just the beginning. Now that we have a clean password_hashers
array class property, we’re going to use array functions with it as well! To begin, let’s look at how we can select a password_hasher
from the password_hashers
array.
/** * Manages a chain of password hashers. */ class PasswordHasherChain implements PasswordHasherInterface { // ... /** * Get the password hasher that supports the given hash. * * @param string $hash * * @return PasswordHasherInterface|null */ private function get_password_hasher($hash) { return array_reduce($this->password_hashers, function ($found, PasswordHasherInterface $password_hasher) use ($hash) { if (!$found instanceof PasswordHasherInterface && $password_hasher->is_hash_supported($hash)) { $found = $password_hasher; } return $found; }); } }
The method that we’re creating to do that is called get_password_hasher
. The method that you can see above has a single parameter: hash
. This is the hash value that we want the returned password hasher to support.
Using array_reduce to find a password hash
To find that password hasher, we’re going to use the array_reduce
function. This array function reduces an array to a single value using a callback. The callback
will again be an anonymous function.
This anonymous function has two parameters: found
and password_hasher
. found
is the current value that array_reduce
would return if this was the last array item. password_hasher
is the current password hasher from the password_hashers
array that we’re evaluating.
Now, let’s look at the code inside the anonymous function. It only contains a single conditional that we use to assign the password_hasher
to the found
variable. This conditional checks for two things.
First, it checks if we found a password hasher already. We do that by checking if found
is an object implementing the PasswordHasherInterface
. The reason for this check is that we don’t want to overwrite the found
value if we already found a password harsher.
If we still haven’t found a password hasher, we move on to the second check. That’s calling the is_hash_supported
method of the given password_hasher
. If the method returns true
, we assign the password_hasher
to the found
variable and return it.
Once array_reduce
has finished going through the array of password hashers, it’ll return one of possible two results. Either we found a password hasher, so the result is a class implementing the PasswordHasherInterface
interface. Or it’s null
because we didn’t find one.
Using the get_password_hasher method
The get_password_hasher
method is central to the PasswordHasherChain
class. Two of the PasswordHasherInterface
interface methods need us to find the correct password hasher for the given hash
value. Those two methods are is_hash_supported
and is_hash_valid
.
/** * Manages a chain of password hashers. */ class PasswordHasherChain implements PasswordHasherInterface { // ... /** * {@inheritdoc} */ public function is_hash_supported($hash) { return $this->get_password_hasher($hash) instanceof PasswordHasherInterface; } /** * {@inheritdoc} */ public function is_hash_valid($hash) { $password_hasher = $this->get_password_hasher($hash); if (!$password_hasher instanceof PasswordHasherInterface) { return false; } return $password_hasher->is_hash_valid($hash); } // ... }
The is_password_supported
method is quite simple. We call the get_password_hasher
method. We then check the returned value using the instanceof
operator.
If the value returned by the get_password_hasher
method is an instance of PasswordHasherInterface
interface object, we return true
. That’s because we know the chain has a password hasher that supports the given hash
. Otherwise, we return false
because the get_password_hasher
method returned null
.
The is_hash_valid
method is similar to the is_password_supported
method. We start by getting the password hasher for the given hash
value using the get_password_hasher
method. We then use the instanceof
operator again.
That’s where the similarities end. We have to do a bit more than just use the instanceof
operator in the is_hash_valid
method. We only use the instanceof
operator to validate if the get_password_hasher
method returned a password hasher.
If we don’t have password hasher, we want to return false
since we have no way to validate the hash
value. If we do have a password hasher, we want to run the hash
through the is_hash_valid
method of the password hasher. We then pass back the return the value from the password hasher as the return value from our is_hash_valid
method.
Working with passwords
So far, we’ve only touched methods that dealt with the hash
value. This is what we built the get_password_hasher
method for. The two other methods of the PasswordHasherChain
that we want to look at are for passwords.
/** * Manages a chain of password hashers. */ class PasswordHasherChain implements PasswordHasherInterface { // ... /** * {@inheritdoc} */ public function hash_password($password) { $hash = array_reduce($this->password_hashers, function ($hash, PasswordHasherInterface $password_hasher) use ($password) { if (empty($hash)) { $hash = $password_hasher->hash_password($password); } return $hash; }); if (empty($hash)) { throw new \RuntimeException('Could not create a hash for the given password.'); } return $hash; } // ... /** * {@inheritdoc} */ public function is_password_valid($password, $hash) { return array_reduce($this->password_hashers, function ($check, PasswordHasherInterface $password_hasher) use ($password, $hash) { if (true !== $check) { $check = $password_hasher->is_password_valid($password, $hash); } return $check; }, false); } // ... }
Above you can see these two methods which are hash_password
and is_password_valid
. Both methods are quite similar to one another. They rely on using the array_reduce
function on the password_hashers
array.
Both anonymous functions passed to the array_reduce
function are just a guard clause. The guard clause is there to determine if we want to return the current carry value or not. If we haven’t, we get a new one from the current password_hasher
.
For the hash_password
method, we want to stop trying to hash a password once we successfully hashed one. We can test for that using the empty
function. If the hash
carry value is empty, we know we haven’t managed to hash the given password
yet.
For the is_password_valid
method, the guard clause doesn’t use the empty
function. Instead, we only stop checking the password if check
is identical to true
. That’s because we want every password hasher to have an opportunity to check the password. If we stopped when check
was false
, we might omit a password hasher that could validate the password.
How to use the chain
So that’s it for the PasswordHasherChain
class! We’re going to wrap this up by looking at how to use it with our other password hashers. Here’s how that looks:
if (!class_exists('PasswordHash')) { require_once ABSPATH . WPINC . '/class-phpass.php'; } $password_hasher = new PasswordHasherChain([ new NativePasswordHasher(), new WordPressPasswordHasher(new \PasswordHash(8, true)), ]);
The code above starts with a guard clause. We need it because WordPress doesn’t always load the file containing the PasswordHash
class. So we need to check to see if it’s there first using the class_exists
function. If the class doesn’t exist, we require the class-phpass.php
file.
Once we’ve passed the guard clause, we initialize the PasswordHasherChain
class. We pass it the array of password hashers which we initialize at the same time. The first one is NativePasswordHasher
and the second one is the WordPressPasswordHasher
.
The order of the password hashers in the array is important here. The chain will stop once it finds a valid password hasher to perform an action. So we want to order them so that our preferred password hasher gets selected.
For this scenario, we want the WordPressPasswordHasher
to go last. We don’t want it to hash new passwords using the WordPress algorithm. We only want it validate passwords that were already hashed using that algorithm. (This is why the is_hash_valid
method of WordPressPasswordHasher
class returns false
.)
Seeing it in action
To see how the chain works in a plugin, I suggest looking at the Passwords Evolved plugin code. (Reading code is a great way to learn too!) You’ll see how to replace the WordPress implementation with our own. There’s also a third password hasher just for libsodium.
If you’re just interested in the code, you can check out this gist.
Photo Credit: Vladyslav Cherkasenko