diff --git a/src/wp-includes/class-wp-application-passwords.php b/src/wp-includes/class-wp-application-passwords.php index 50d9060dfdff5..dde7ce1e983aa 100644 --- a/src/wp-includes/class-wp-application-passwords.php +++ b/src/wp-includes/class-wp-application-passwords.php @@ -60,6 +60,7 @@ public static function is_in_use() { * * @since 5.6.0 * @since 5.7.0 Returns WP_Error if application name already exists. + * @since x.y.z The hashed password value now uses wp_hash_value() instead of phpass. * * @param int $user_id User ID. * @param array $args { @@ -95,7 +96,7 @@ public static function create_new_application_password( $user_id, $args = array( } $new_password = wp_generate_password( static::PW_LENGTH, false ); - $hashed_password = wp_hash_password( $new_password ); + $hashed_password = self::hash_password( $new_password ); $new_item = array( 'uuid' => wp_generate_uuid4(), @@ -124,6 +125,7 @@ public static function create_new_application_password( $user_id, $args = array( * Fires when an application password is created. * * @since 5.6.0 + * @since x.y.z @since x.y.z The hashed password value now uses wp_hash_value() instead of phpass. * * @param int $user_id The user ID. * @param array $new_item { @@ -249,7 +251,7 @@ public static function application_name_exists_for_user( $user_id, $name ) { * Updates an application password. * * @since 5.6.0 - * @since x.y.z The actual password should now be hashed using bcrypt instead of phpass. See wp_hash_password(). + * @since x.y.z The actual password should now be hashed using wp_hash_value(). * * @param int $user_id User ID. * @param string $uuid The password's UUID. @@ -302,7 +304,7 @@ public static function update_application_password( $user_id, $uuid, $update = a * Fires when an application password is updated. * * @since 5.6.0 - * @since x.y.z The password is now hashed using bcrypt instead of phpass. + * @since x.y.z The password is now hashed using wp_hash_value() instead of phpass. * Existing passwords may still be hashed using phpass. * * @param int $user_id The user ID. @@ -472,4 +474,45 @@ public static function chunk_password( $raw_password ) { return trim( chunk_split( $raw_password, 4, ' ' ) ); } + + /** + * Hashes a plaintext application password. + * + * @since x.y.z + * + * @param string $password Plaintext password. + * @return string Hashed password. + */ + public static function hash_password( $password ) { + return wp_hash_value( $password ); + } + + /** + * Checks a plaintext application password against a hashed password. + * + * @since x.y.z + * + * @param string $password Plaintext password. + * @param string $hash Hash of the password to check against. + * @return bool Whether the password matches the hashed password. + */ + public static function check_password( $password, $hash ) { + return wp_verify_hashed_value( $password, $hash ); + } + + /** + * Checks whether a password hash needs to be rehashed. + * + * A password hashed in a prior version of WordPress may still be hashed with phpass and will + * need to be rehashed. If the algorithm is changed in WordPress then a password hashed in a + * previous version will need to be rehashed. + * + * @since x.y.z + * + * @param string $hash Hash of a password to check. + * @return bool Whether the hash needs to be rehashed. + */ + public static function password_needs_rehash( $hash ) { + return ! str_starts_with( $hash, '$generic$' ); + } } diff --git a/src/wp-includes/user.php b/src/wp-includes/user.php index d77f2e375a7b0..8a392ee7bb20a 100644 --- a/src/wp-includes/user.php +++ b/src/wp-includes/user.php @@ -437,17 +437,10 @@ function wp_authenticate_application_password( $input_user, $username, $password $hashed_passwords = WP_Application_Passwords::get_user_application_passwords( $user->ID ); foreach ( $hashed_passwords as $key => $item ) { - $valid = wp_check_password( $password, $item['password'], $user->ID ); - - if ( ! $valid ) { + if ( ! WP_Application_Passwords::check_password( $password, $item['password'] ) ) { continue; } - if ( wp_password_needs_rehash( $item['password'] ) ) { - $item['password'] = wp_hash_password( $password ); - WP_Application_Passwords::update_application_password( $user->ID, $item['uuid'], $item ); - } - $error = new WP_Error(); /** @@ -471,6 +464,11 @@ function wp_authenticate_application_password( $input_user, $username, $password return $error; } + if ( WP_Application_Passwords::password_needs_rehash( $item['password'] ) ) { + $item['password'] = WP_Application_Passwords::hash_password( $password ); + WP_Application_Passwords::update_application_password( $user->ID, $item['uuid'], $item ); + } + WP_Application_Passwords::record_application_password_usage( $user->ID, $item['uuid'] ); /** diff --git a/tests/phpunit/tests/auth.php b/tests/phpunit/tests/auth.php index bc77132e94c70..dfe94fcc728ba 100644 --- a/tests/phpunit/tests/auth.php +++ b/tests/phpunit/tests/auth.php @@ -1039,7 +1039,7 @@ public function test_phpass_password_is_rehashed_after_successful_application_pa // Verify that the application password needs rehashing. $hash = WP_Application_Passwords::get_user_application_password( self::$user_id, $uuid )['password']; - $this->assertTrue( wp_password_needs_rehash( $hash ) ); + $this->assertTrue( WP_Application_Passwords::password_needs_rehash( $hash ) ); // Authenticate. $user = wp_authenticate_application_password( null, self::USER_LOGIN, $password ); @@ -1051,7 +1051,7 @@ public function test_phpass_password_is_rehashed_after_successful_application_pa // Verify that the application password no longer needs rehashing. $hash = WP_Application_Passwords::get_user_application_password( self::$user_id, $uuid )['password']; - $this->assertFalse( wp_password_needs_rehash( $hash ) ); + $this->assertFalse( WP_Application_Passwords::password_needs_rehash( $hash ) ); // Verify that the user's password has not been touched. $this->assertSame( $user_pass, get_userdata( self::$user_id )->user_pass );