Skip to content

Instantly share code, notes, and snippets.

@jmikola
Created November 3, 2010 14:42
Show Gist options
  • Save jmikola/661150 to your computer and use it in GitHub Desktop.
Save jmikola/661150 to your computer and use it in GitHub Desktop.
Password hashing in a Doctrine2 ODM model class
Document\PasswordContainer:
type: document
collection: password_container
fields:
password:
type: string
salt:
type: string
algorithm:
type: string
lifecycleCallbacks:
prePersist: [ hashPassword ]
preUpdate: [ hashPassword ]
<?php
namespace Document;
class PasswordContainer
{
protected $password;
protected $algorithm = 'sha512';
protected $salt;
/**
* Set password
*
* An empty value will be ignored. If the password's value is changed, this
* method will trigger hashing in a prePersist/preUpdate lifecycle callback.
*
* @see hashPassword()
* @param string $password
*/
public function setPassword($password)
{
$password = (string) $password;
if ($this->password !== $password) {
$this->hashPasswordRequired = true;
}
$this->password = $password;
}
/**
* Get password
*
* @return string $password
*/
public function getPassword()
{
return $this->password;
}
/**
* Set hash algorithm
*
* @link http://php.net/manual/en/function.hash-algos.php
* @param string $algorithm
* @throws \InvalidArgumentException
*/
public function setAlgorithm($algorithm)
{
$algorithm = (string) $algorithm;
if (!in_array($algorithm, hash_algos())) {
throw new \InvalidArgumentException('Unsupported hash algorithm: ' . $algorithm);
}
$this->algorithm = $algorithm;
}
/**
* Get hash algorithm
*
* @return string $algorithm
*/
public function getAlgorithm()
{
return $this->algorithm;
}
/**
* Set salt
*
* @param string $salt
*/
public function setSalt($salt)
{
$this->salt = (string) $salt;
}
/**
* Get salt
*
* @return string $salt
*/
public function getSalt()
{
return $this->salt;
}
/**
* Ensure the password is hashed
*
* If hashing is required and a salt is not set, one will be generated.
*/
public function hashPassword()
{
if (isset($this->hashPasswordRequired)) {
if (empty($this->salt)) {
$this->salt = 'generate_some_suitable_salt_value_here';
}
$this->password = $this->_generateHash($password);
unset($this->hashPasswordRequired);
}
}
/**
* Compares input to internal password
*
* @param string $password The password to check
* @return boolean
*/
public function checkPassword($password) {
return $this->password === $this->_generateHash($password);
}
/**
* Generate a hash value of the input (after applying salt)
*
* @param string $input The input to be hashed
* @return string
*/
private function _generateHash($input)
{
return hash($this->algorithm, $this->salt . $input);
}
}
@jmikola
Copy link
Author

jmikola commented Nov 3, 2010

If you're concerned about hashPasswordRequired accidentally ending up in the data model, you could map it as transient to be explicit, but Doctrine should ignore unmapped fields by default.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment