Created
November 3, 2010 14:42
-
-
Save jmikola/661150 to your computer and use it in GitHub Desktop.
Password hashing in a Doctrine2 ODM model class
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Document\PasswordContainer: | |
type: document | |
collection: password_container | |
fields: | |
password: | |
type: string | |
salt: | |
type: string | |
algorithm: | |
type: string | |
lifecycleCallbacks: | |
prePersist: [ hashPassword ] | |
preUpdate: [ hashPassword ] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.