Completed
Pull Request — 1.x (#634)
by
unknown
15:05
created

Db::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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