Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
38.39% |
43 / 112 |
|
50.00% |
1 / 2 |
CRAP | |
0.00% |
0 / 1 |
db | |
38.39% |
43 / 112 |
|
50.00% |
1 / 2 |
211.32 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
login | |
35.51% |
38 / 107 |
|
0.00% |
0 / 1 |
222.49 |
1 | <?php |
2 | /** |
3 | * |
4 | * This file is part of the phpBB Forum Software package. |
5 | * |
6 | * @copyright (c) phpBB Limited <https://www.phpbb.com> |
7 | * @license GNU General Public License, version 2 (GPL-2.0) |
8 | * |
9 | * For full copyright and license information, please see |
10 | * the docs/CREDITS.txt file. |
11 | * |
12 | */ |
13 | |
14 | namespace phpbb\auth\provider; |
15 | |
16 | use phpbb\captcha\factory; |
17 | use phpbb\captcha\plugins\captcha_abstract; |
18 | use phpbb\config\config; |
19 | use phpbb\db\driver\driver_interface; |
20 | use phpbb\passwords\manager; |
21 | use phpbb\user; |
22 | |
23 | /** |
24 | * Database authentication provider for phpBB3 |
25 | * This is for authentication via the integrated user table |
26 | */ |
27 | class db extends base |
28 | { |
29 | /** @var factory CAPTCHA factory */ |
30 | protected $captcha_factory; |
31 | |
32 | /** @var config phpBB config */ |
33 | protected $config; |
34 | |
35 | /** @var driver_interface DBAL driver instance */ |
36 | protected $db; |
37 | |
38 | /** @var user User object */ |
39 | protected $user; |
40 | |
41 | /** |
42 | * phpBB passwords manager |
43 | * |
44 | * @var manager |
45 | */ |
46 | protected $passwords_manager; |
47 | |
48 | /** |
49 | * Database Authentication Constructor |
50 | * |
51 | * @param factory $captcha_factory |
52 | * @param config $config |
53 | * @param driver_interface $db |
54 | * @param manager $passwords_manager |
55 | * @param user $user |
56 | */ |
57 | public function __construct(factory $captcha_factory, config $config, driver_interface $db, manager $passwords_manager, user $user) |
58 | { |
59 | $this->captcha_factory = $captcha_factory; |
60 | $this->config = $config; |
61 | $this->db = $db; |
62 | $this->passwords_manager = $passwords_manager; |
63 | $this->user = $user; |
64 | } |
65 | |
66 | /** |
67 | * {@inheritdoc} |
68 | */ |
69 | public function login($username, $password) |
70 | { |
71 | // Auth plugins get the password untrimmed. |
72 | // For compatibility we trim() here. |
73 | $password = trim($password); |
74 | |
75 | // do not allow empty password |
76 | if (!$password) |
77 | { |
78 | return array( |
79 | 'status' => LOGIN_ERROR_PASSWORD, |
80 | 'error_msg' => 'NO_PASSWORD_SUPPLIED', |
81 | 'user_row' => array('user_id' => ANONYMOUS), |
82 | ); |
83 | } |
84 | |
85 | if (!$username) |
86 | { |
87 | return array( |
88 | 'status' => LOGIN_ERROR_USERNAME, |
89 | 'error_msg' => 'LOGIN_ERROR_USERNAME', |
90 | 'user_row' => array('user_id' => ANONYMOUS), |
91 | ); |
92 | } |
93 | |
94 | $username_clean = utf8_clean_string($username); |
95 | |
96 | $sql = 'SELECT * |
97 | FROM ' . USERS_TABLE . " |
98 | WHERE username_clean = '" . $this->db->sql_escape($username_clean) . "'"; |
99 | $result = $this->db->sql_query($sql); |
100 | $row = $this->db->sql_fetchrow($result); |
101 | $this->db->sql_freeresult($result); |
102 | |
103 | if (($this->user->ip && !$this->config['ip_login_limit_use_forwarded']) || |
104 | ($this->user->forwarded_for && $this->config['ip_login_limit_use_forwarded'])) |
105 | { |
106 | $sql = 'SELECT COUNT(*) AS attempts |
107 | FROM ' . LOGIN_ATTEMPT_TABLE . ' |
108 | WHERE attempt_time > ' . (time() - (int) $this->config['ip_login_limit_time']); |
109 | if ($this->config['ip_login_limit_use_forwarded']) |
110 | { |
111 | $sql .= " AND attempt_forwarded_for = '" . $this->db->sql_escape($this->user->forwarded_for) . "'"; |
112 | } |
113 | else |
114 | { |
115 | $sql .= " AND attempt_ip = '" . $this->db->sql_escape($this->user->ip) . "' "; |
116 | } |
117 | |
118 | $result = $this->db->sql_query($sql); |
119 | $attempts = (int) $this->db->sql_fetchfield('attempts'); |
120 | $this->db->sql_freeresult($result); |
121 | |
122 | $attempt_data = array( |
123 | 'attempt_ip' => $this->user->ip, |
124 | 'attempt_browser' => trim(substr($this->user->browser, 0, 149)), |
125 | 'attempt_forwarded_for' => $this->user->forwarded_for, |
126 | 'attempt_time' => time(), |
127 | 'user_id' => ($row) ? (int) $row['user_id'] : 0, |
128 | 'username' => $username, |
129 | 'username_clean' => $username_clean, |
130 | ); |
131 | $sql = 'INSERT INTO ' . LOGIN_ATTEMPT_TABLE . $this->db->sql_build_array('INSERT', $attempt_data); |
132 | $this->db->sql_query($sql); |
133 | } |
134 | else |
135 | { |
136 | $attempts = 0; |
137 | } |
138 | |
139 | $login_error_attempts = 'LOGIN_ERROR_ATTEMPTS'; |
140 | |
141 | $user_login_attempts = (is_array($row) && $this->config['max_login_attempts'] && $row['user_login_attempts'] >= $this->config['max_login_attempts']); |
142 | $ip_login_attempts = ($this->config['ip_login_limit_max'] && $attempts >= $this->config['ip_login_limit_max']); |
143 | |
144 | $show_captcha = $user_login_attempts || $ip_login_attempts; |
145 | |
146 | if ($show_captcha) |
147 | { |
148 | $captcha = $this->captcha_factory->get_instance($this->config['captcha_plugin']); |
149 | |
150 | // Get custom message for login error when exceeding maximum number of attempts |
151 | if ($captcha instanceof captcha_abstract) |
152 | { |
153 | $login_error_attempts = $captcha->get_login_error_attempts(); |
154 | } |
155 | } |
156 | |
157 | if (!$row) |
158 | { |
159 | if ($this->config['ip_login_limit_max'] && $attempts >= $this->config['ip_login_limit_max']) |
160 | { |
161 | return array( |
162 | 'status' => LOGIN_ERROR_ATTEMPTS, |
163 | 'error_msg' => $login_error_attempts, |
164 | 'user_row' => array('user_id' => ANONYMOUS), |
165 | ); |
166 | } |
167 | |
168 | return array( |
169 | 'status' => LOGIN_ERROR_USERNAME, |
170 | 'error_msg' => 'LOGIN_ERROR_USERNAME', |
171 | 'user_row' => array('user_id' => ANONYMOUS), |
172 | ); |
173 | } |
174 | |
175 | // If there are too many login attempts, we need to check for a confirm image |
176 | // Every auth module is able to define what to do by itself... |
177 | if ($show_captcha) |
178 | { |
179 | $captcha->init(\phpbb\captcha\plugins\confirm_type::LOGIN); |
180 | if ($captcha->validate() !== true) |
181 | { |
182 | return array( |
183 | 'status' => LOGIN_ERROR_ATTEMPTS, |
184 | 'error_msg' => $login_error_attempts, |
185 | 'user_row' => $row, |
186 | ); |
187 | } |
188 | else |
189 | { |
190 | $captcha->reset(); |
191 | } |
192 | |
193 | } |
194 | |
195 | // Check password ... |
196 | if ($this->passwords_manager->check($password, $row['user_password'], $row)) |
197 | { |
198 | // Check for old password hash... |
199 | if ($this->passwords_manager->convert_flag || strlen($row['user_password']) == 32) |
200 | { |
201 | $hash = $this->passwords_manager->hash($password); |
202 | |
203 | // Update the password in the users table to the new format |
204 | $sql = 'UPDATE ' . USERS_TABLE . " |
205 | SET user_password = '" . $this->db->sql_escape($hash) . "' |
206 | WHERE user_id = {$row['user_id']}"; |
207 | $this->db->sql_query($sql); |
208 | |
209 | $row['user_password'] = $hash; |
210 | } |
211 | |
212 | $sql = 'DELETE FROM ' . LOGIN_ATTEMPT_TABLE . ' |
213 | WHERE user_id = ' . $row['user_id']; |
214 | $this->db->sql_query($sql); |
215 | |
216 | if ($row['user_login_attempts'] != 0) |
217 | { |
218 | // Successful, reset login attempts (the user passed all stages) |
219 | $sql = 'UPDATE ' . USERS_TABLE . ' |
220 | SET user_login_attempts = 0 |
221 | WHERE user_id = ' . $row['user_id']; |
222 | $this->db->sql_query($sql); |
223 | } |
224 | |
225 | // User inactive... |
226 | if ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE) |
227 | { |
228 | return array( |
229 | 'status' => LOGIN_ERROR_ACTIVE, |
230 | 'error_msg' => 'ACTIVE_ERROR', |
231 | 'user_row' => $row, |
232 | ); |
233 | } |
234 | |
235 | // Successful login... set user_login_attempts to zero... |
236 | return array( |
237 | 'status' => LOGIN_SUCCESS, |
238 | 'error_msg' => false, |
239 | 'user_row' => $row, |
240 | ); |
241 | } |
242 | |
243 | // Password incorrect - increase login attempts |
244 | $sql = 'UPDATE ' . USERS_TABLE . ' |
245 | SET user_login_attempts = user_login_attempts + 1 |
246 | WHERE user_id = ' . (int) $row['user_id'] . ' |
247 | AND user_login_attempts < ' . LOGIN_ATTEMPTS_MAX; |
248 | $this->db->sql_query($sql); |
249 | |
250 | // Give status about wrong password... |
251 | return array( |
252 | 'status' => ($show_captcha) ? LOGIN_ERROR_ATTEMPTS : LOGIN_ERROR_PASSWORD, |
253 | 'error_msg' => 'LOGIN_ERROR_PASSWORD', |
254 | 'user_row' => $row, |
255 | ); |
256 | } |
257 | } |