Completed
Push — 3.x ( b13c7c )
by Daniel
07:33
created

Db::preProcessCredential()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 1
1
<?php
2
3
namespace ZfcUser\Authentication\Adapter;
4
5
use Interop\Container\ContainerInterface;
6
use Zend\Authentication\Result as AuthenticationResult;
7
use Zend\EventManager\EventInterface;
8
use Zend\ServiceManager\ServiceManager;
9
use Zend\Crypt\Password\Bcrypt;
10
use Zend\Session\Container as SessionContainer;
11
use ZfcUser\Entity\UserInterface;
12
use ZfcUser\Mapper\UserInterface as UserMapperInterface;
13
use ZfcUser\Options\ModuleOptions;
14
15
class Db extends AbstractAdapter
16
{
17
    /**
18
     * @var UserMapperInterface
19
     */
20
    protected $mapper;
21
22
    /**
23
     * @var callable
24
     */
25
    protected $credentialPreprocessor;
26
27
    /**
28
     * @var ServiceManager
29
     */
30
    protected $serviceManager;
31
32
    /**
33
     * @var ModuleOptions
34
     */
35
    protected $options;
36
37
    /**
38
     * Called when user id logged out
39
     * @param EventInterface $e
40
     */
41
    public function logout(EventInterface $e)
42
    {
43
        $this->getStorage()->clear();
44
    }
45
46
    /**
47
     * @param EventInterface $e
48
     * @return bool
49
     */
50
    public function authenticate(EventInterface $e)
51
    {
52
        $e = $e->getTarget();
53
        if ($this->isSatisfied()) {
54
            $storage = $this->getStorage()->read();
55
            $e->setIdentity($storage['identity'])
56
              ->setCode(AuthenticationResult::SUCCESS)
57
              ->setMessages(array('Authentication successful.'));
58
            return;
59
        }
60
61
        $identity   = $e->getRequest()->getPost()->get('identity');
62
        $credential = $e->getRequest()->getPost()->get('credential');
63
        $credential = $this->preProcessCredential($credential);
64
        /** @var UserInterface|null $userObject */
65
        $userObject = null;
66
67
        // Cycle through the configured identity sources and test each
68
        $fields = $this->getOptions()->getAuthIdentityFields();
69
        while (!is_object($userObject) && count($fields) > 0) {
70
            $mode = array_shift($fields);
71
            switch ($mode) {
72
                case 'username':
73
                    $userObject = $this->getMapper()->findByUsername($identity);
74
                    break;
75
                case 'email':
76
                    $userObject = $this->getMapper()->findByEmail($identity);
77
                    break;
78
            }
79
        }
80
81
        if (!$userObject) {
82
            $e->setCode(AuthenticationResult::FAILURE_IDENTITY_NOT_FOUND)
83
              ->setMessages(array('A record with the supplied identity could not be found.'));
84
            $this->setSatisfied(false);
85
            return false;
86
        }
87
88
        if ($this->getOptions()->getEnableUserState()) {
89
            // Don't allow user to login if state is not in allowed list
90
            if (!in_array($userObject->getState(), $this->getOptions()->getAllowedLoginStates())) {
91
                $e->setCode(AuthenticationResult::FAILURE_UNCATEGORIZED)
92
                  ->setMessages(array('A record with the supplied identity is not active.'));
93
                $this->setSatisfied(false);
94
                return false;
95
            }
96
        }
97
98
        $bcrypt = new Bcrypt();
99
        $bcrypt->setCost($this->getOptions()->getPasswordCost());
100
        if (!$bcrypt->verify($credential, $userObject->getPassword())) {
101
            // Password does not match
102
            $e->setCode(AuthenticationResult::FAILURE_CREDENTIAL_INVALID)
103
              ->setMessages(array('Supplied credential is invalid.'));
104
            $this->setSatisfied(false);
105
            return false;
106
        }
107
108
        // regen the id
109
        $session = new SessionContainer($this->getStorage()->getNameSpace());
110
        $session->getManager()->regenerateId();
111
112
        // Success!
113
        $e->setIdentity($userObject->getId());
114
        // Update user's password hash if the cost parameter has changed
115
        $this->updateUserPasswordHash($userObject, $credential, $bcrypt);
116
        $this->setSatisfied(true);
117
        $storage = $this->getStorage()->read();
118
        $storage['identity'] = $e->getIdentity();
119
        $this->getStorage()->write($storage);
120
        $e->setCode(AuthenticationResult::SUCCESS)
121
          ->setMessages(array('Authentication successful.'));
122
    }
123
124
    protected function updateUserPasswordHash(UserInterface $userObject, $password, Bcrypt $bcrypt)
125
    {
126
        $hash = explode('$', $userObject->getPassword());
127
        if ($hash[2] === $bcrypt->getCost()) {
128
            return;
129
        }
130
        $userObject->setPassword($bcrypt->create($password));
131
        $this->getMapper()->update($userObject);
132
        return $this;
133
    }
134
135
    public function preProcessCredential($credential)
136
    {
137
        $processor = $this->getCredentialPreprocessor();
138
        if (is_callable($processor)) {
139
            return $processor($credential);
140
        }
141
142
        return $credential;
143
    }
144
145
    /**
146
     * getMapper
147
     *
148
     * @return UserMapperInterface
149
     */
150
    public function getMapper()
151
    {
152
        if (null === $this->mapper) {
153
            $this->mapper = $this->getServiceManager()->get('zfcuser_user_mapper');
154
        }
155
156
        return $this->mapper;
157
    }
158
159
    /**
160
     * setMapper
161
     *
162
     * @param UserMapperInterface $mapper
163
     * @return Db
164
     */
165
    public function setMapper(UserMapperInterface $mapper)
166
    {
167
        $this->mapper = $mapper;
168
169
        return $this;
170
    }
171
172
    /**
173
     * Get credentialPreprocessor.
174
     *
175
     * @return callable
176
     */
177
    public function getCredentialPreprocessor()
178
    {
179
        return $this->credentialPreprocessor;
180
    }
181
182
    /**
183
     * Set credentialPreprocessor.
184
     *
185
     * @param callable $credentialPreprocessor
186
     * @return $this
187
     */
188
    public function setCredentialPreprocessor($credentialPreprocessor)
189
    {
190
        $this->credentialPreprocessor = $credentialPreprocessor;
191
        return $this;
192
    }
193
194
    /**
195
     * Retrieve service manager instance
196
     *
197
     * @return ServiceManager
198
     */
199
    public function getServiceManager()
200
    {
201
        return $this->serviceManager;
202
    }
203
204
    /**
205
     * Set service manager instance
206
     *
207
     * @param ContainerInterface $serviceManager
208
     */
209
    public function setServiceManager(ContainerInterface $serviceManager)
210
    {
211
        $this->serviceManager = $serviceManager;
0 ignored issues
show
Documentation Bug introduced by
$serviceManager is of type object<Interop\Container\ContainerInterface>, but the property $serviceManager was declared to be of type object<Zend\ServiceManager\ServiceManager>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
212
    }
213
214
    /**
215
     * @param ModuleOptions $options
216
     */
217
    public function setOptions(ModuleOptions $options)
218
    {
219
        $this->options = $options;
220
    }
221
222
    /**
223
     * @return ModuleOptions
224
     */
225
    public function getOptions()
226
    {
227
        if ($this->options === null) {
228
            $this->setOptions($this->getServiceManager()->get('zfcuser_module_options'));
229
        }
230
231
        return $this->options;
232
    }
233
}
234