From 3b694493bb52ba64f286279bd88e5dbedaffaf18 Mon Sep 17 00:00:00 2001 From: Lucio Date: Tue, 4 Oct 2022 00:28:58 -0300 Subject: [PATCH 1/5] Added logging function --- providers/class-two-factor-provider.php | 33 +++++++++++++++++++++++++ providers/class-two-factor-totp.php | 9 +++++-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/providers/class-two-factor-provider.php b/providers/class-two-factor-provider.php index a2f9be06..8842bce2 100644 --- a/providers/class-two-factor-provider.php +++ b/providers/class-two-factor-provider.php @@ -72,6 +72,39 @@ public function pre_process_authentication( $user ) { */ abstract public function validate_authentication( $user ); + /** + * Logs the failed authentication. + * + * @param WP_User $user WP_User object of the user trying to login. + * @param string|false $code The code used to authenticate, if available. + * + * @return void + */ + public function log_failure( $user, $code = false ) { + /** + * This action is triggered when a Two Factor validation fails. + * + * @param WP_User $user WP_User object of the user trying to login. + * @param string|false $code The code used to authenticate, if available. + */ + do_action( 'two_factor_user_login_failed', $user, $code ); + + /* translators: %1$d: the user's ID %2$s: the code used to authenticate */ + $log_message = sprintf( esc_html__( 'The user with ID %1$d failed to login using the code "%2$s"', 'two-factor' ), $user->ID, esc_html( $code ) ); + + /** + * This action is triggered when a Two Factor validation fails. + * + * @param boolean $should_log Whether or not the authentication failure should be logged. + * @param WP_User $user WP_User object of the user trying to login. + * @param string|false $code The code used to authenticate, if available. + * @param string $log_message The generated log message. + */ + if ( apply_filters( 'two_factor_log_failure', true, $user, $code, $log_message ) ) { + error_log( $log_message ); + } + } + /** * Whether this Two Factor provider is configured and available for the user specified. * diff --git a/providers/class-two-factor-totp.php b/providers/class-two-factor-totp.php index 4d5a2828..046e6a65 100644 --- a/providers/class-two-factor-totp.php +++ b/providers/class-two-factor-totp.php @@ -288,14 +288,19 @@ public function admin_notices( $user_id ) { * @return bool Whether the user gave a valid code */ public function validate_authentication( $user ) { + $success = false; if ( ! empty( $_REQUEST['authcode'] ) ) { - return $this->is_valid_authcode( + $success = $this->is_valid_authcode( $this->get_user_totp_key( $user->ID ), sanitize_text_field( $_REQUEST['authcode'] ) ); } - return false; + if ( ! $success ) { + $this->log_failure( $user, ! empty( $_REQUEST['authcode'] ) ? sanitize_text_field( $_REQUEST['authcode'] ) : false ); + } + + return $success; } /** From 07dc6e15687e42ee0eb18b4b9b6afa747b96ba08 Mon Sep 17 00:00:00 2001 From: Lucio Date: Tue, 4 Oct 2022 16:06:14 -0300 Subject: [PATCH 2/5] Fix two_factor_log_failure filter description --- providers/class-two-factor-provider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/class-two-factor-provider.php b/providers/class-two-factor-provider.php index 8842bce2..3e8b1d1d 100644 --- a/providers/class-two-factor-provider.php +++ b/providers/class-two-factor-provider.php @@ -93,7 +93,7 @@ public function log_failure( $user, $code = false ) { $log_message = sprintf( esc_html__( 'The user with ID %1$d failed to login using the code "%2$s"', 'two-factor' ), $user->ID, esc_html( $code ) ); /** - * This action is triggered when a Two Factor validation fails. + * This filter is triggered to checke whether it's needed to log the authentication failure. * * @param boolean $should_log Whether or not the authentication failure should be logged. * @param WP_User $user WP_User object of the user trying to login. From 969e4d2f1c1930e4b7320b621031685e5ec5044a Mon Sep 17 00:00:00 2001 From: Lucio Date: Tue, 4 Oct 2022 16:16:55 -0300 Subject: [PATCH 3/5] Add Two_Factor_Provider class to hooks --- providers/class-two-factor-provider.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/providers/class-two-factor-provider.php b/providers/class-two-factor-provider.php index 3e8b1d1d..bb7aed2b 100644 --- a/providers/class-two-factor-provider.php +++ b/providers/class-two-factor-provider.php @@ -78,16 +78,19 @@ abstract public function validate_authentication( $user ); * @param WP_User $user WP_User object of the user trying to login. * @param string|false $code The code used to authenticate, if available. * + * @since 0.9.0 + * * @return void */ public function log_failure( $user, $code = false ) { /** * This action is triggered when a Two Factor validation fails. * - * @param WP_User $user WP_User object of the user trying to login. - * @param string|false $code The code used to authenticate, if available. + * @param WP_User $user WP_User object of the user trying to login. + * @param string|false $code The code used to authenticate, if available. + * @param Two_Factor_Provider $this The Provider class used during the authentication. */ - do_action( 'two_factor_user_login_failed', $user, $code ); + do_action( 'two_factor_user_login_failed', $user, $code, $this ); /* translators: %1$d: the user's ID %2$s: the code used to authenticate */ $log_message = sprintf( esc_html__( 'The user with ID %1$d failed to login using the code "%2$s"', 'two-factor' ), $user->ID, esc_html( $code ) ); @@ -99,8 +102,9 @@ public function log_failure( $user, $code = false ) { * @param WP_User $user WP_User object of the user trying to login. * @param string|false $code The code used to authenticate, if available. * @param string $log_message The generated log message. + * @param Two_Factor_Provider $this The Provider class used during the authentication. */ - if ( apply_filters( 'two_factor_log_failure', true, $user, $code, $log_message ) ) { + if ( apply_filters( 'two_factor_log_failure', true, $user, $code, $log_message, $this ) ) { error_log( $log_message ); } } From 96b7cc02b4b35d8e18980c1bb52bce534b504c16 Mon Sep 17 00:00:00 2001 From: Lucio Date: Tue, 4 Oct 2022 16:23:08 -0300 Subject: [PATCH 4/5] Add failures logging to remaining providers --- providers/class-two-factor-backup-codes.php | 8 +++++++- providers/class-two-factor-email.php | 8 +++++++- providers/class-two-factor-fido-u2f.php | 10 ++++++++-- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/providers/class-two-factor-backup-codes.php b/providers/class-two-factor-backup-codes.php index 5d2dcf88..bc443828 100644 --- a/providers/class-two-factor-backup-codes.php +++ b/providers/class-two-factor-backup-codes.php @@ -305,7 +305,13 @@ public function authentication_page( $user ) { */ public function validate_authentication( $user ) { $backup_code = isset( $_POST['two-factor-backup-code'] ) ? sanitize_text_field( wp_unslash( $_POST['two-factor-backup-code'] ) ) : false; - return $this->validate_code( $user, filter_var( $backup_code, FILTER_SANITIZE_STRING ) ); + $success = $this->validate_code( $user, filter_var( $backup_code, FILTER_SANITIZE_STRING ) ); + + if ( ! $success ) { + $this->log_failure( $user, $backup_code ); + } + + return $success; } /** diff --git a/providers/class-two-factor-email.php b/providers/class-two-factor-email.php index 5946c719..3783f5db 100644 --- a/providers/class-two-factor-email.php +++ b/providers/class-two-factor-email.php @@ -320,7 +320,13 @@ public function validate_authentication( $user ) { // Ensure there are no spaces or line breaks around the code. $code = trim( sanitize_text_field( $_REQUEST['two-factor-email-code'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, handled by the core method already. - return $this->validate_token( $user->ID, $code ); + $success = $this->validate_token( $user->ID, $code ); + + if ( ! $success ) { + $this->log_failure( $user, $code ); + } + + return $success; } /** diff --git a/providers/class-two-factor-fido-u2f.php b/providers/class-two-factor-fido-u2f.php index 330451c2..3c272f53 100644 --- a/providers/class-two-factor-fido-u2f.php +++ b/providers/class-two-factor-fido-u2f.php @@ -212,10 +212,16 @@ public function validate_authentication( $user ) { self::update_security_key( $user->ID, $reg ); - return true; + $success = true; } catch ( Exception $e ) { - return false; + $success = false; + } + + if ( ! $success ) { + $this->log_failure( $user, $response ); } + + return $success; } /** From bf6bd6a8d5ef5b9ed5f8d31b20d7c9bddf086cba Mon Sep 17 00:00:00 2001 From: Lucisu <46996317+Lucisu@users.noreply.github.com> Date: Sat, 15 Oct 2022 18:28:57 -0300 Subject: [PATCH 5/5] Add user_login to failed authentication log message --- providers/class-two-factor-provider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/class-two-factor-provider.php b/providers/class-two-factor-provider.php index bb7aed2b..6ff66c23 100644 --- a/providers/class-two-factor-provider.php +++ b/providers/class-two-factor-provider.php @@ -93,7 +93,7 @@ public function log_failure( $user, $code = false ) { do_action( 'two_factor_user_login_failed', $user, $code, $this ); /* translators: %1$d: the user's ID %2$s: the code used to authenticate */ - $log_message = sprintf( esc_html__( 'The user with ID %1$d failed to login using the code "%2$s"', 'two-factor' ), $user->ID, esc_html( $code ) ); + $log_message = sprintf( esc_html__( 'The user %1$s (ID: %2$d) failed to login using the code "%3$s"', 'two-factor' ), esc_html( $user->user_login ), $user->ID, esc_html( $code ) ); /** * This filter is triggered to checke whether it's needed to log the authentication failure.