Db.php 3.79 KB
Newer Older
1
<?php
2

3
4
namespace UnicaenAuth\Authentication\Adapter;

Bertrand Gauthier's avatar
Bertrand Gauthier committed
5
6
use Laminas\Authentication\Result as AuthenticationResult;
use Laminas\Crypt\Password\Bcrypt;
7
use ZfcUser\Entity\UserInterface;
8
9

/**
Bertrand Gauthier's avatar
Bertrand Gauthier committed
10
11
12
 * Adpater d'authentification à partir de la base de données.
 * 
 * Ajout par rapport à la classe mère : si aucune base de données ou table n'existe,
13
 * l'authentification ne plante pas (i.e. renvoit false).
14
15
16
 *
 * @author Bertrand GAUTHIER <bertrand.gauthier@unicaen.fr>
 */
17
class Db extends AbstractDb
18
{
19
20
21
22
23
24
25
26
27
28
    const TYPE = 'db';

    protected $type = self::TYPE;

    /**
     * @var callable
     */
    protected $credentialPreprocessor;

    /**
29
     * @return \ZfcUser\Entity\UserInterface|null
30
     */
31
    protected function fetchUserObject(): ?UserInterface
32
    {
33
        $identity = $this->event->getRequest()->getPost()->get('identity');
34

35
36
37
38
        /** @var UserInterface|null $userObject */
        $userObject = null;

        // Cycle through the configured identity sources and test each
39
        $fields = $this->moduleOptions->getAuthIdentityFields();
40
41
42
43
        while (!is_object($userObject) && count($fields) > 0) {
            $mode = array_shift($fields);
            switch ($mode) {
                case 'username':
44
                    $userObject = $this->mapper->findByUsername($identity);
45
46
                    break;
                case 'email':
47
                    $userObject = $this->mapper->findByEmail($identity);
48
49
                    break;
            }
50
        }
51
52

        if (!$userObject) {
53
            $this->event
54
                ->setCode(AuthenticationResult::FAILURE_IDENTITY_NOT_FOUND)
55
                ->setMessages([]); // NB: ne pas préciser la cause
56
            $this->setSatisfied(false);
57

58
            return null;
59
60
        }

61
62
63
64
65
66
67
68
69
70
71
72
        return $userObject;
    }

    /**
     * @param \ZfcUser\Entity\UserInterface $userObject
     * @return bool
     */
    protected function authenticateUserObject(UserInterface $userObject): bool
    {
        $credential = $this->event->getRequest()->getPost()->get('credential');
        $credential = $this->preProcessCredential($credential);

73
        $bcrypt = new Bcrypt();
74
75
76
77
78
        $bcrypt->setCost($this->moduleOptions->getPasswordCost());
        $ok = $bcrypt->verify($credential, $userObject->getPassword());

        if (!$ok) {
            $this->event
79
                ->setCode(AuthenticationResult::FAILURE_CREDENTIAL_INVALID)
80
                ->setMessages([]); // NB: ne pas préciser la cause
81
            $this->setSatisfied(false);
82

83
84
85
86
87
            return false;
        }

        // Update user's password hash if the cost parameter has changed
        $this->updateUserPasswordHash($userObject, $credential, $bcrypt);
88
89

        return true;
90
91
    }

92
    protected function updateUserPasswordHash(UserInterface $userObject, $password, Bcrypt $bcrypt): self
93
94
95
    {
        $hash = explode('$', $userObject->getPassword());
        if ($hash[2] === $bcrypt->getCost()) {
96
            return $this;
97
98
        }
        $userObject->setPassword($bcrypt->create($password));
99
100
        $this->mapper->update($userObject);

101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
        return $this;
    }

    public function preProcessCredential($credential)
    {
        $processor = $this->getCredentialPreprocessor();
        if (is_callable($processor)) {
            return $processor($credential);
        }

        return $credential;
    }

    /**
     * Get credentialPreprocessor.
     *
117
     * @return callable|null
118
     */
119
    public function getCredentialPreprocessor(): ?callable
120
121
122
123
124
125
126
127
    {
        return $this->credentialPreprocessor;
    }

    /**
     * Set credentialPreprocessor.
     *
     * @param callable $credentialPreprocessor
128
     * @return self
129
     */
130
    public function setCredentialPreprocessor(callable $credentialPreprocessor): self
131
132
133
134
    {
        $this->credentialPreprocessor = $credentialPreprocessor;
        return $this;
    }
135
}