Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 16 additions & 11 deletions class-two-factor-core.php
Original file line number Diff line number Diff line change
Expand Up @@ -1688,18 +1688,13 @@ public static function process_provider( $provider, $user, $is_post_request ) {
);
}

// Allow the provider to re-send codes, etc.
if ( true === $provider->pre_process_authentication( $user ) ) {
return false;
}

// If it's not a POST request, there's no processing to perform.
if ( ! $is_post_request ) {
return false;
}

// Rate limit two factor authentication attempts.
// Rate limit two factor authentication attempts, including pre-processing (e.g. resend).
if ( true === self::is_user_rate_limited( $user ) ) {
// Invalidate any provider token to prevent reuse after rate limiting.
if ( method_exists( $provider, 'delete_token' ) ) {
$provider->delete_token( $user->ID );
}

$time_delay = self::get_user_time_delay( $user );
$last_login = get_user_meta( $user->ID, self::USER_RATE_LIMIT_KEY, true );

Expand All @@ -1713,6 +1708,16 @@ public static function process_provider( $provider, $user, $is_post_request ) {
);
}

// Allow the provider to re-send codes, etc.
if ( true === $provider->pre_process_authentication( $user ) ) {
return false;
}

// If it's not a POST request, there's no processing to perform.
if ( ! $is_post_request ) {
return false;
}

// Ask the provider to verify the second factor.
if ( true !== $provider->validate_authentication( $user ) ) {
// Store the last time a failed login occurred.
Expand Down
50 changes: 50 additions & 0 deletions tests/class-two-factor-core.php
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,56 @@ public function test_is_user_rate_limited() {
$this->assertFalse( Two_Factor_Core::is_user_rate_limited( $user ) );
}

/**
* Test that email resend requests are blocked while rate limited.
*
* @covers Two_Factor_Core::process_provider()
*/
public function test_process_provider_blocks_email_resend_while_rate_limited() {
$user = $this->get_dummy_user( array( 'Two_Factor_Email' => 'Two_Factor_Email' ) );
$provider = Two_Factor_Email::get_instance();

$provider->generate_token( $user->ID );
$original_token = $provider->get_user_token( $user->ID );

update_user_meta( $user->ID, Two_Factor_Core::USER_FAILED_LOGIN_ATTEMPTS_KEY, 1 );
update_user_meta( $user->ID, Two_Factor_Core::USER_RATE_LIMIT_KEY, time() );

$_REQUEST[ Two_Factor_Email::INPUT_NAME_RESEND_CODE ] = 1;

$result = Two_Factor_Core::process_provider( $provider, $user, true );

unset( $_REQUEST[ Two_Factor_Email::INPUT_NAME_RESEND_CODE ] );

$this->assertWPError( $result );
$this->assertSame( 'two_factor_too_fast', $result->get_error_code() );
$this->assertFalse( $provider->get_user_token( $user->ID ), 'Token is invalidated when rate limited' );
}

/**
* Test that rate limiting invalidates the email token on validation attempts.
*
* @covers Two_Factor_Core::process_provider()
*/
public function test_process_provider_invalidates_email_token_when_rate_limited() {
$user = $this->get_dummy_user( array( 'Two_Factor_Email' => 'Two_Factor_Email' ) );
$provider = Two_Factor_Email::get_instance();

$provider->generate_token( $user->ID );

$this->assertTrue( $provider->user_has_token( $user->ID ), 'Token exists before rate limiting' );

// Simulate a rate-limited state.
update_user_meta( $user->ID, Two_Factor_Core::USER_FAILED_LOGIN_ATTEMPTS_KEY, 3 );
update_user_meta( $user->ID, Two_Factor_Core::USER_RATE_LIMIT_KEY, time() );

$result = Two_Factor_Core::process_provider( $provider, $user, true );

$this->assertWPError( $result );
$this->assertSame( 'two_factor_too_fast', $result->get_error_code() );
$this->assertFalse( $provider->user_has_token( $user->ID ), 'Token is invalidated when rate limited' );
}

/**
* Test that the "invalid login attempts have occurred" login notice works as expected.
*
Expand Down
Loading