BaseAuthenticate::_findUser()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
nc 4
nop 2
dl 0
loc 21
rs 9.584
c 0
b 0
f 0
ccs 13
cts 13
cp 1
crap 4
1
<?php
2
/**
3
 * Copyright 2016 - 2018, Cake Development Corporation (http://cakedc.com)
4
 *
5
 * Licensed under The MIT License
6
 * Redistributions of files must retain the above copyright notice.
7
 *
8
 * @copyright Copyright 2016 - 2018, Cake Development Corporation (http://cakedc.com)
9
 * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
10
 */
11
12
/**
13
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
14
 * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
15
 *
16
 * Licensed under The MIT License
17
 * For full copyright and license information, please see the LICENSE.txt
18
 * Redistributions of files must retain the above copyright notice.
19
 *
20
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
21
 * @link          http://cakephp.org CakePHP(tm) Project
22
 * @since         0.10.0
23
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
24
 */
25
26
namespace CakeDC\Api\Service\Auth\Authenticate;
27
28
use CakeDC\Api\Service\Action\Action;
29
30
use Cake\Auth\PasswordHasherFactory;
31
use Cake\Core\InstanceConfigTrait;
32
use Cake\Event\EventListenerInterface;
33
use Cake\Http\Response;
34
use Cake\Http\ServerRequest;
35
36
use Cake\ORM\TableRegistry;
37
38
/**
39
 * Base Authentication class with common methods and properties.
40
 *
41
 */
42
abstract class BaseAuthenticate implements EventListenerInterface
43
{
44
    use InstanceConfigTrait;
45
46
    /**
47
     * Default config for this object.
48
     *
49
     * - `fields` The fields to use to identify a user by.
50
     * - `userModel` The alias for users table, defaults to Users.
51
     * - `finder` The finder method to use to fetch user record. Defaults to 'all'.
52
     *   You can set finder name as string or an array where key is finder name and value
53
     *   is an array passed to `Table::find()` options.
54
     *   E.g. ['finderName' => ['some_finder_option' => 'some_value']]
55
     * - `passwordHasher` Password hasher class. Can be a string specifying class name
56
     *    or an array containing `className` key, any other keys will be passed as
57
     *    config to the class. Defaults to 'Default'.
58
     * - Options `scope` and `contain` have been deprecated since 3.1. Use custom
59
     *   finder instead to modify the query to fetch user record.
60
     *
61
     * @var array
62
     */
63
    protected $_defaultConfig = [
64
        'fields' => [
65
            'username' => 'username',
66
            'password' => 'password'
67
        ],
68
        'userModel' => 'Users',
69
        'scope' => [],
70
        'finder' => 'all',
71
        'contain' => null,
72
        'passwordHasher' => 'Default'
73
    ];
74
75
    /**
76
     * An Action
77
     *
78
     * @var \CakeDC\Api\Service\Action\Action
79
     */
80
    protected $_action;
81
82
    /**
83
     * Password hasher instance.
84
     *
85
     * @var \Cake\Auth\AbstractPasswordHasher
86
     */
87
    protected $_passwordHasher;
88
89
    /**
90
     * Whether or not the user authenticated by this class
91
     * requires their password to be rehashed with another algorithm.
92
     *
93
     * @var bool
94
     */
95
    protected $_needsPasswordRehash = false;
96
97
    /**
98
     * Constructor
99
     *
100
     * @param \CakeDC\Api\Service\Action\Action $action An Action instance.
101
     * @param array $config Array of config to use.
102
     */
103
    public function __construct(Action $action, array $config = [])
104 66
    {
105
        $this->_action = $action;
106 66
        $this->setConfig($config);
107 66
    }
108 66
109
    /**
110
     * Find a user record using the username and password provided.
111
     *
112
     * Input passwords will be hashed even when a user doesn't exist. This
113
     * helps mitigate timing attacks that are attempting to find valid usernames.
114
     *
115
     * @param string $username The username/identifier.
116
     * @param string|null $password The password, if not provided password checking is skipped
117
     *   and result of find is returned.
118
     * @return bool|array Either false on failure, or an array of user data.
119
     */
120
    protected function _findUser($username, $password = null)
121 4
    {
122
        $result = $this->_query($username)->first();
123 4
124
        if (empty($result)) {
125 4
            return false;
126 1
        }
127
128
        if ($password !== null) {
129 4
            $hasher = $this->passwordHasher();
130 4
            $hashedPassword = $result->get($this->_config['fields']['password']);
131 4
            if (!$hasher->check($password, $hashedPassword)) {
132 4
                return false;
133 1
            }
134
135
            $this->_needsPasswordRehash = $hasher->needsRehash($hashedPassword);
136 3
            $result->unsetProperty($this->_config['fields']['password']);
137 3
        }
138 3
139
        return $result->toArray();
140 3
    }
141
142
    /**
143
     * Get query object for fetching user from database.
144
     *
145
     * @param string $username The username/identifier.
146
     * @return \Cake\ORM\Query
147
     */
148
    protected function _query($username)
149 57
    {
150
        $config = $this->_config;
151 57
        $table = TableRegistry::getTableLocator()->get($config['userModel']);
152 57
153
        $options = [
154
            'conditions' => [
155
                $table->aliasField($config['fields']['username']) => $username
156 57
            ]
157 57
        ];
158 57
159
        if (!empty($config['scope'])) {
160 57
            $options['conditions'] = array_merge($options['conditions'], $config['scope']);
161
        }
162
        if (!empty($config['contain'])) {
163 57
            $options['contain'] = $config['contain'];
164
        }
165
166
        $finder = $config['finder'];
167 57
        if (is_array($finder)) {
168 57
            $options += current($finder);
169
            $finder = key($finder);
170
        }
171
172
        $query = $table->find($finder, $options);
173 57
174
        return $query;
175 57
    }
176
177
    /**
178
     * Return password hasher object
179
     *
180
     * @return \Cake\Auth\AbstractPasswordHasher Password hasher instance
181
     * @throws \RuntimeException If password hasher class not found or
182
     *   it does not extend AbstractPasswordHasher
183
     */
184
    public function passwordHasher()
185 4
    {
186
        if ($this->_passwordHasher) {
187 4
            return $this->_passwordHasher;
188
        }
189
190
        $passwordHasher = $this->_config['passwordHasher'];
191 4
192
        return $this->_passwordHasher = PasswordHasherFactory::build($passwordHasher);
193 4
    }
194
195
    /**
196
     * Returns whether or not the password stored in the repository for the logged in user
197
     * requires to be rehashed with another algorithm
198
     *
199
     * @return bool
200
     */
201
    public function needsPasswordRehash()
202
    {
203
        return $this->_needsPasswordRehash;
204
    }
205
206
    /**
207
     * Authenticate a user based on the request information.
208
     *
209
     * @param \Cake\Http\ServerRequest $request Request to get authentication information from.
210
     * @param \Cake\Http\Response $response A response object that can have headers added.
211
     * @return mixed Either false on failure, or an array of user data on success.
212
     */
213
    abstract public function authenticate(ServerRequest $request, Response $response);
214
215
    /**
216
     * Get a user based on information in the request. Primarily used by stateless authentication
217
     * systems like basic and digest auth.
218
     *
219
     * @param \Cake\Http\ServerRequest $request Request object.
220
     * @return mixed Either false or an array of user information
221
     */
222
    public function getUser(ServerRequest $request)
223
    {
224
        return false;
225
    }
226
227
    /**
228
     * Handle unauthenticated access attempt. In implementation valid return values
229
     * can be:
230
     *
231
     * - Null - No action taken, AuthComponent should return appropriate response.
232
     * - Cake\Http\Response - A response object, which will cause AuthComponent to
233
     *   simply return that response.
234
     *
235
     * @param ServerRequest $request A request object.
236
     * @param \Cake\Http\Response $response A response object.
237
     * @return void
238
     */
239
    public function unauthenticated(ServerRequest $request, Response $response)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $response is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
240
    {
241
    }
242
243
    /**
244
     * Returns a list of all events that this authenticate class will listen to.
245
     *
246
     * An authenticate class can listen to following events fired by AuthComponent:
247
     *
248
     * - `Auth.afterIdentify` - Fired after a user has been identified using one of
249
     *   configured authenticate class. The callback function should have signature
250
     *   like `afterIdentify(Event $event, array $user)` when `$user` is the
251
     *   identified user record.
252
     *
253
     * - `Auth.logout` - Fired when AuthComponent::logout() is called. The callback
254
     *   function should have signature like `logout(Event $event, array $user)`
255
     *   where `$user` is the user about to be logged out.
256
     *
257
     * @return array List of events this class listens to. Defaults to `[]`.
258
     */
259
    public function implementedEvents()
260 52
    {
261
        return [];
262 52
    }
263
}
264