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; } /**