PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 5.7.0
Defender Security – Malware Scanner, Login Security & Firewall v5.7.0
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
defender-security / src / component / audit / class-users-audit.php

class-users-audit.php in Defender Security – Malware Scanner, Login Security & Firewall 5.7.0, at src/component/audit/class-users-audit.php

468 lines 14.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handles user-related audit events.
4 *
5 * @package WP_Defender\Component\Audit
6 */
7
8 namespace WP_Defender\Component\Audit;
9
10 use WP_User;
11 use WP_Defender\Traits\User;
12 use WP_Defender\Model\Audit_Log;
13
14 /**
15 * Handle user-related audit events such as login, logout, registration, and profile updates.
16 */
17 class Users_Audit extends Audit_Event {
18
19 use User;
20
21 public const ACTION_LOGIN = 'login', ACTION_LOGOUT = 'logout', ACTION_REGISTERED = 'registered',
22 ACTION_LOST_PASS = 'lost_password', ACTION_RESET_PASS = 'reset_password';
23
24 public const CONTEXT_SESSION = 'session', CONTEXT_USERS = 'users', CONTEXT_PROFILE = 'profile';
25
26 /**
27 * Returns an array of hooks associated with various user actions to capture and log them.
28 *
29 * @return array
30 */
31 public function get_hooks(): array {
32
33 return array(
34 'wp_login_failed' => array(
35 'args' => array( 'username' ),
36 'text' => sprintf(
37 /* translators: 1: Blog name, 2: Username */
38 esc_html__( '%1$s User login fail. Username: %2$s', 'defender-security' ),
39 '{{blog_name}}',
40 '{{username}}'
41 ),
42 'event_type' => Audit_Log::EVENT_TYPE_USER,
43 'context' => self::CONTEXT_SESSION,
44 'action_type' => self::ACTION_LOGIN,
45 ),
46 'wp_login' => array(
47 'args' => array( 'userlogin', 'user' ),
48 'text' => sprintf(
49 /* translators: 1: Blog name, 2: Username */
50 esc_html__( '%1$s User login success: %2$s', 'defender-security' ),
51 '{{blog_name}}',
52 '{{userlogin}}'
53 ),
54 'event_type' => Audit_Log::EVENT_TYPE_USER,
55 'context' => self::CONTEXT_SESSION,
56 'action_type' => self::ACTION_LOGIN,
57 ),
58 'wpmu_2fa_login' => array(
59 'args' => array( 'user_id', '2fa_slug' ),
60 'text' => sprintf(
61 /* translators: 1: Blog name, 2: 2fa method slug, 3: Username. */
62 esc_html__( '%1$s 2fa with %2$s method login success for user: %3$s', 'defender-security' ),
63 '{{blog_name}}',
64 '{{2fa_slug}}',
65 '{{username}}'
66 ),
67 'event_type' => Audit_Log::EVENT_TYPE_USER,
68 'context' => self::CONTEXT_SESSION,
69 'action_type' => self::ACTION_LOGIN,
70 'program_args' => array(
71 'username' => array(
72 'callable' => 'get_user_by',
73 'params' => array(
74 'id',
75 '{{user_id}}',
76 ),
77 'result_property' => 'user_login',
78 ),
79 ),
80 ),
81 'wp_logout' => array(
82 'args' => array( 'user_id' ),
83 'text' => sprintf(
84 /* translators: 1: Blog name, 2: Username */
85 esc_html__( '%1$s User logout success: %2$s', 'defender-security' ),
86 '{{blog_name}}',
87 '{{username}}'
88 ),
89 'event_type' => Audit_Log::EVENT_TYPE_USER,
90 'action_type' => self::ACTION_LOGOUT,
91 'context' => self::CONTEXT_SESSION,
92 'program_args' => array(
93 'username' => array(
94 'callable' => 'get_user_by',
95 'params' => array(
96 'id',
97 '{{user_id}}',
98 ),
99 'result_property' => 'user_login',
100 ),
101 ),
102 ),
103 'user_register' => array(
104 'args' => array( 'user_id' ),
105 'text' => is_admin()
106 ? sprintf(
107 /* translators: 1: Blog name, 2: Source of action. For e.g. Hub or a logged-in user, 3: Username, 4: User role */
108 esc_html__( '%1$s %2$s added a new user: Username: %3$s, Role: %4$s', 'defender-security' ),
109 '{{blog_name}}',
110 '{{wp_user}}',
111 '{{username}}',
112 '{{user_role}}'
113 )
114 : sprintf(
115 /* translators: 1: Blog name, 2: Username, 3: User role */
116 esc_html__( '%1$s A new user registered: Username: %2$s, Role: %3$s', 'defender-security' ),
117 '{{blog_name}}',
118 '{{username}}',
119 '{{user_role}}'
120 ),
121 'event_type' => Audit_Log::EVENT_TYPE_USER,
122 'context' => self::CONTEXT_USERS,
123 'action_type' => self::ACTION_REGISTERED,
124 'program_args' => array(
125 'username' => array(
126 'callable' => 'get_user_by',
127 'params' => array(
128 'id',
129 '{{user_id}}',
130 ),
131 'result_property' => 'user_login',
132 ),
133 'user_role' => array(
134 'callable' => array( self::class, 'get_user_role' ),
135 'params' => array(
136 '{{user_id}}',
137 ),
138 ),
139 ),
140 ),
141 'delete_user' => array(
142 'args' => array( 'user_id' ),
143 'text' => sprintf(
144 /* translators: 1: Blog name, 2: Source of action. For e.g. Hub or a logged-in user, 3: User ID, 4: Username */
145 esc_html__( '%1$s %2$s deleted a user: ID: %3$s, username: %4$s', 'defender-security' ),
146 '{{blog_name}}',
147 '{{wp_user}}',
148 '{{user_id}}',
149 '{{username}}'
150 ),
151 'context' => self::CONTEXT_USERS,
152 'action_type' => self::ACTION_DELETED,
153 'event_type' => Audit_Log::EVENT_TYPE_USER,
154 'program_args' => array(
155 'username' => array(
156 'callable' => 'get_user_by',
157 'params' => array(
158 'id',
159 '{{user_id}}',
160 ),
161 'result_property' => 'user_login',
162 ),
163 ),
164 ),
165 'remove_user_from_blog' => array(
166 'args' => array( 'user_id', 'blog_id' ),
167 'context' => self::CONTEXT_USERS,
168 'action_type' => self::ACTION_DELETED,
169 'event_type' => Audit_Log::EVENT_TYPE_USER,
170 'callback' => array( self::class, 'remove_user_from_blog_callback' ),
171 ),
172 'wpmu_delete_user' => array(
173 'args' => array( 'user_id' ),
174 'text' => sprintf(
175 /* translators: 1: Blog name, 2: Source of action. For e.g. Hub or a logged-in user, 3: User ID, 4: Username */
176 esc_html__( '%1$s %2$s deleted a user: ID: %3$s, username: %4$s', 'defender-security' ),
177 '{{blog_name}}',
178 '{{wp_user}}',
179 '{{user_id}}',
180 '{{username}}'
181 ),
182 'context' => self::CONTEXT_USERS,
183 'action_type' => self::ACTION_DELETED,
184 'event_type' => Audit_Log::EVENT_TYPE_USER,
185 'program_args' => array(
186 'username' => array(
187 'callable' => 'get_user_by',
188 'params' => array(
189 'id',
190 '{{user_id}}',
191 ),
192 'result_property' => 'user_login',
193 ),
194 ),
195 ),
196 'profile_update' => array(
197 'args' => array( 'user_id', 'old_user_data' ),
198 'action_type' => self::ACTION_UPDATED,
199 'event_type' => Audit_Log::EVENT_TYPE_USER,
200 'context' => self::CONTEXT_PROFILE,
201 'callback' => array( self::class, 'profile_update_callback' ),
202 ),
203 'retrieve_password' => array(
204 'args' => array( 'username' ),
205 'text' => sprintf(
206 /* translators: 1: Blog name, 2: Username */
207 esc_html__( '%1$s Password requested to reset for user: %2$s', 'defender-security' ),
208 '{{blog_name}}',
209 '{{username}}'
210 ),
211 'action_type' => self::ACTION_LOST_PASS,
212 'event_type' => Audit_Log::EVENT_TYPE_USER,
213 'context' => self::CONTEXT_PROFILE,
214 'program_args' => array(
215 'user' => array(
216 'callable' => 'get_user_by',
217 'params' => array(
218 'login',
219 '{{username}}',
220 ),
221 ),
222 ),
223 ),
224 'after_password_reset' => array(
225 'args' => array( 'user' ),
226 'text' => sprintf(
227 /* translators: 1: Blog name, 2: Username. */
228 esc_html__( '%1$s Password reset for user: %2$s', 'defender-security' ),
229 '{{blog_name}}',
230 '{{user_login}}'
231 ),
232 'event_type' => Audit_Log::EVENT_TYPE_USER,
233 'action_type' => self::ACTION_RESET_PASS,
234 'context' => self::CONTEXT_PROFILE,
235 'custom_args' => array(
236 'user_login' => '{{user->user_login}}',
237 ),
238 ),
239 'set_user_role' => array(
240 'args' => array( 'user_ID', 'new_role', 'old_role' ),
241 'text' => sprintf(
242 /* translators: 1: Blog name, 2: Source of action. For e.g. Hub or a logged-in user, 3: Username, 4: Old user role, 5: New user role */
243 esc_html__( "%1\$s %2\$s changed user %3\$s's role from %4\$s to %5\$s", 'defender-security' ),
244 '{{blog_name}}',
245 '{{wp_user}}',
246 '{{username}}',
247 '{{from_role}}',
248 '{{new_role}}'
249 ),
250 'action_type' => self::ACTION_UPDATED,
251 'event_type' => Audit_Log::EVENT_TYPE_USER,
252 'context' => self::CONTEXT_PROFILE,
253 'custom_args' => array(
254 'from_role' => '{{old_role->0}}',
255 ),
256 'program_args' => array(
257 'username' => array(
258 'callable' => 'get_user_by',
259 'params' => array(
260 'id',
261 '{{user_ID}}',
262 ),
263 'result_property' => 'user_login',
264 ),
265 ),
266 'false_when' => array(
267 array(
268 '{{old_role}}',
269 array(),
270 '==',
271 ),
272 ),
273 ),
274 'wpdef_session_lock' => array(
275 'args' => array( 'user_id', 'session_lock_type' ),
276 'text' => sprintf(
277 /* translators: 1: Blog name, 2: Username, 3: Session lock type. */
278 esc_html__( '%1$s User session ended for %2$s due to a change in %3$s', 'defender-security' ),
279 '{{blog_name}}',
280 '{{username}}',
281 '{{session_lock_type}}'
282 ),
283 'event_type' => Audit_Log::EVENT_TYPE_USER,
284 'context' => self::CONTEXT_SESSION,
285 'action_type' => self::ACTION_LOGIN,
286 'program_args' => array(
287 'username' => array(
288 'callable' => 'get_user_by',
289 'params' => array(
290 'id',
291 '{{user_id}}',
292 ),
293 'result_property' => 'user_login',
294 ),
295 ),
296 ),
297 'wpdef_session_timeout' => array(
298 'args' => array( 'user_id' ),
299 'text' => sprintf(
300 /* translators: 1: Blog name, 2: Username. */
301 esc_html__( '%1$s User session ended for %2$s due to an idle session', 'defender-security' ),
302 '{{blog_name}}',
303 '{{username}}'
304 ),
305 'event_type' => Audit_Log::EVENT_TYPE_USER,
306 'context' => self::CONTEXT_SESSION,
307 'action_type' => self::ACTION_LOGIN,
308 'program_args' => array(
309 'username' => array(
310 'callable' => 'get_user_by',
311 'params' => array(
312 'id',
313 '{{user_id}}',
314 ),
315 'result_property' => 'user_login',
316 ),
317 ),
318 ),
319 // Since 5.6.0.
320 'wpmudev_sso_set_current_user' => array(
321 'args' => array( 'user_id' ),
322 'text' => sprintf(
323 /* translators: 1: Blog name, 2: Username. */
324 esc_html__( '%1$s Hub SSO login success: %2$s', 'defender-security' ),
325 '{{blog_name}}',
326 '{{username}}'
327 ),
328 'event_type' => Audit_Log::EVENT_TYPE_USER,
329 'context' => self::CONTEXT_SESSION,
330 'action_type' => self::ACTION_LOGIN,
331 'program_args' => array(
332 'username' => array(
333 'callable' => 'get_user_by',
334 'params' => array(
335 'id',
336 '{{user_id}}',
337 ),
338 'result_property' => 'user_login',
339 ),
340 ),
341 ),
342 );
343 }
344
345 /**
346 * Log when user is removed from a blog.
347 *
348 * @return bool|array
349 */
350 public function remove_user_from_blog_callback() {
351 if ( self::is_create_user_action() ) {
352 return false;
353 }
354
355 $args = func_get_args();
356 $user_id = $args[1]['user_id'];
357 $blog_id = $args[1]['blog_id'];
358 $user = get_user_by( 'id', $user_id );
359 $username = $user->user_login ?? '';
360 $current_user_display = $this->get_user_display( get_current_user_id() );
361 $blog_name = is_multisite() ? '[' . get_bloginfo( 'name' ) . ']' : '';
362
363 return array(
364 sprintf(
365 /* translators: 1: Blog name, 2: User's display name, 3: User ID, 4: Username, 5: Blog ID */
366 esc_html__( '%1$s %2$s removed a user: ID: %3$s, username: %4$s from blog %5$s', 'defender-security' ),
367 $blog_name,
368 $current_user_display,
369 $user_id,
370 $username,
371 $blog_id
372 ),
373 self::ACTION_DELETED,
374 );
375 }
376
377 /**
378 * Callback for logging when a user's profile is updated. It distinguishes between self-updates and updates made by
379 * other users.
380 *
381 * @return bool|array
382 */
383 public function profile_update_callback() {
384 if ( self::is_create_user_action() ) {
385 return false;
386 }
387
388 $args = func_get_args();
389 $user_id = $args[1]['user_id'];
390 $current_user = get_user_by( 'id', $user_id );
391 $blog_name = is_multisite() ? '[' . get_bloginfo( 'name' ) . ']' : '';
392 $current_user_id = get_current_user_id();
393
394 if ( $current_user_id === $user_id ) {
395
396 return array(
397 sprintf(
398 /* translators: 1: Blog name, 2: User's nicename */
399 esc_html__( '%1$s User %2$s updated his/her profile', 'defender-security' ),
400 $blog_name,
401 $current_user->user_nicename
402 ),
403 self::ACTION_UPDATED,
404 );
405 } elseif ( 0 !== $current_user_id ) {
406
407 return array(
408 sprintf(
409 /* translators: 1: Blog name, 2: User's display name, 3: User's nicename */
410 esc_html__( "%1\$s %2\$s updated user %3\$s's profile information", 'defender-security' ),
411 $blog_name,
412 $this->get_user_display( $current_user_id ),
413 $current_user->user_nicename
414 ),
415 self::ACTION_UPDATED,
416 );
417 }
418 }
419
420 /**
421 * Provides a dictionary for translating action constants into human-readable strings.
422 *
423 * @return array
424 */
425 public function dictionary(): array {
426 return array(
427 self::ACTION_LOST_PASS => esc_html__( 'lost password', 'defender-security' ),
428 self::ACTION_REGISTERED => esc_html__( 'registered', 'defender-security' ),
429 self::ACTION_LOGIN => esc_html__( 'login', 'defender-security' ),
430 self::ACTION_LOGOUT => esc_html__( 'logout', 'defender-security' ),
431 self::ACTION_RESET_PASS => esc_html__( 'password reset', 'defender-security' ),
432 );
433 }
434
435 /**
436 * Static method to retrieve the role of a user by their ID
437 *
438 * @param int $user_id The ID of the user whose role is to be fetched.
439 *
440 * @return string
441 */
442 public static function get_user_role( $user_id ): string {
443 $user = get_user_by( 'id', $user_id );
444 if ( $user instanceof WP_User ) {
445 $_this = new self();
446
447 return $_this->get_first_user_role( $user );
448 } else {
449 return '';
450 }
451 }
452
453 /**
454 * Check if it is a create new user request.
455 *
456 * @since 2.8.0
457 * @retun bool
458 */
459 public static function is_create_user_action(): bool {
460 $action = defender_get_data_from_request( 'action', 'p' );
461 if ( 'createuser' === $action ) {
462 return true;
463 }
464
465 return false;
466 }
467 }
468