diff --git a/src/wp-includes/pluggable.php b/src/wp-includes/pluggable.php index 1256431438..643fc24c5d 100644 --- a/src/wp-includes/pluggable.php +++ b/src/wp-includes/pluggable.php @@ -1812,6 +1812,18 @@ function wp_verify_nonce( $nonce, $action = -1 ) { return 2; } + /** + * Fires when nonce verification fails. + * + * @since 4.4.0 + * + * @param string $nonce The invalid nonce. + * @param string|int $action The nonce action. + * @param WP_User $user The current user object. + * @param string $token The user's session token. + */ + do_action( 'wp_verify_nonce_failed', $nonce, $action, $user, $token ); + // Invalid nonce return false; } diff --git a/tests/phpunit/tests/auth.php b/tests/phpunit/tests/auth.php index 90141883f4..947265ea26 100644 --- a/tests/phpunit/tests/auth.php +++ b/tests/phpunit/tests/auth.php @@ -8,6 +8,11 @@ class Tests_Auth extends WP_UnitTestCase { var $user_id; var $wp_hasher; + /** + * action hook + */ + protected $nonce_failure_hook = 'wp_verify_nonce_failed'; + function setUp() { parent::setUp(); $this->user_id = $this->factory->user->create(); @@ -110,6 +115,30 @@ class Tests_Auth extends WP_UnitTestCase { $this->assertFalse( wp_verify_nonce( 1 ) ); } + /** + * @ticket 24030 + */ + function test_wp_nonce_verify_failed() { + $nonce = substr( md5( uniqid() ), 0, 10 ); + $count = did_action( $this->nonce_failure_hook ); + + wp_verify_nonce( $nonce, 'nonce_test_action' ); + + $this->assertEquals( ( $count + 1 ), did_action( $this->nonce_failure_hook ) ); + } + + /** + * @ticket 24030 + */ + function test_wp_nonce_verify_success() { + $nonce = wp_create_nonce( 'nonce_test_action' ); + $count = did_action( $this->nonce_failure_hook ); + + wp_verify_nonce( $nonce, 'nonce_test_action' ); + + $this->assertEquals( $count, did_action( $this->nonce_failure_hook ) ); + } + function test_password_length_limit() { $passwords = array( str_repeat( 'a', 4095 ), // short