]> git.immae.eu Git - github/wallabag/wallabag.git/blob - src/Wallabag/CoreBundle/Security/Authentication/Encoder/WallabagPasswordEncoder.php
fcfe418bf966d076bb4c0e24f826010527ac47c8
[github/wallabag/wallabag.git] / src / Wallabag / CoreBundle / Security / Authentication / Encoder / WallabagPasswordEncoder.php
1 <?php
2
3 namespace Wallabag\CoreBundle\Security\Authentication\Encoder;
4
5 use Symfony\Component\Security\Core\Encoder\BasePasswordEncoder;
6 use Symfony\Component\Security\Core\Exception\BadCredentialsException;
7
8 /**
9 * This override just add en extra variable (username) to be able to salt the password
10 * the way Wallabag v1 does. It will avoid to break compatibility with Wallabag v1
11 *
12 */
13 class WallabagPasswordEncoder extends BasePasswordEncoder
14 {
15 private $algorithm;
16 private $encodeHashAsBase64;
17 private $iterations;
18 private $username = null;
19
20 /**
21 * Constructor.
22 *
23 * @param string $algorithm The digest algorithm to use
24 * @param bool $encodeHashAsBase64 Whether to base64 encode the password hash
25 * @param int $iterations The number of iterations to use to stretch the password hash
26 */
27 public function __construct($algorithm = 'sha512', $encodeHashAsBase64 = true, $iterations = 5000)
28 {
29 $this->algorithm = $algorithm;
30 $this->encodeHashAsBase64 = $encodeHashAsBase64;
31 $this->iterations = $iterations;
32 }
33
34 public function setUsername($username)
35 {
36 $this->username = $username;
37 }
38
39 /**
40 * {@inheritdoc}
41 */
42 public function encodePassword($raw, $salt)
43 {
44 if ($this->isPasswordTooLong($raw)) {
45 throw new BadCredentialsException('Invalid password.');
46 }
47
48 if (!in_array($this->algorithm, hash_algos(), true)) {
49 throw new \LogicException(sprintf('The algorithm "%s" is not supported.', $this->algorithm));
50 }
51
52 $salted = $this->mergePasswordAndSalt($raw, $salt);
53 $digest = hash($this->algorithm, $salted, true);
54
55 // "stretch" hash
56 for ($i = 1; $i < $this->iterations; $i++) {
57 $digest = hash($this->algorithm, $digest.$salted, true);
58 }
59
60 return $this->encodeHashAsBase64 ? base64_encode($digest) : bin2hex($digest);
61 }
62
63 /**
64 * {@inheritdoc}
65 *
66 * We inject the username inside the salted password
67 */
68 protected function mergePasswordAndSalt($password, $salt)
69 {
70 if (null === $this->username) {
71 throw new \LogicException('We can not check the password without a username.');
72 }
73
74 if (empty($salt)) {
75 return $password;
76 }
77
78 return $password.$this->username.$salt;
79 }
80
81 /**
82 * {@inheritdoc}
83 */
84 public function isPasswordValid($encoded, $raw, $salt)
85 {
86 return !$this->isPasswordTooLong($raw) && $this->comparePasswords($encoded, $this->encodePassword($raw, $salt));
87 }
88 }