diff --git a/src/wp-admin/includes/user.php b/src/wp-admin/includes/user.php index 2aeeba0b035b4..805802d4940d5 100644 --- a/src/wp-admin/includes/user.php +++ b/src/wp-admin/includes/user.php @@ -49,10 +49,10 @@ function edit_user( $user_id = 0 ) { $pass1 = ''; $pass2 = ''; if ( isset( $_POST['pass1'] ) ) { - $pass1 = trim( $_POST['pass1'] ); + $pass1 = trim( wp_unslash( $_POST['pass1'] ) ); } if ( isset( $_POST['pass2'] ) ) { - $pass2 = trim( $_POST['pass2'] ); + $pass2 = trim( wp_unslash( $_POST['pass2'] ) ); } if ( isset( $_POST['role'] ) && current_user_can( 'promote_users' ) && ( ! $user_id || current_user_can( 'promote_user', $user_id ) ) ) { diff --git a/src/wp-includes/user.php b/src/wp-includes/user.php index 76bce3966feb2..34f2df8511a61 100644 --- a/src/wp-includes/user.php +++ b/src/wp-includes/user.php @@ -52,7 +52,7 @@ function wp_signon( $credentials = array(), $secure_cookie = '' ) { $credentials['user_login'] = wp_unslash( $_POST['log'] ); } if ( ! empty( $_POST['pwd'] ) && is_string( $_POST['pwd'] ) ) { - $credentials['user_password'] = $_POST['pwd']; + $credentials['user_password'] = wp_unslash( $_POST['pwd'] ); } if ( ! empty( $_POST['rememberme'] ) ) { $credentials['remember'] = $_POST['rememberme']; @@ -207,6 +207,19 @@ function wp_authenticate_username_password( $valid = wp_check_password( $password, $user->user_pass, $user->ID ); + if ( ! $valid ) { + /* + * Back-compat for users whose password was hashed with magic-quote slashes + * intact. If the slashed version matches, migrate the hash to the + * unslashed password. + */ + $valid = wp_check_password( wp_slash( $password ), $user->user_pass, $user->ID ); + + if ( $valid ) { + wp_set_password( $password, $user->ID ); + } + } + if ( ! $valid ) { return new WP_Error( 'incorrect_password', @@ -290,6 +303,19 @@ function wp_authenticate_email_password( $valid = wp_check_password( $password, $user->user_pass, $user->ID ); + if ( ! $valid ) { + /* + * Back-compat for users whose password was hashed with magic-quote slashes + * intact. If the slashed version matches, migrate the hash to the + * unslashed password. + */ + $valid = wp_check_password( wp_slash( $password ), $user->user_pass, $user->ID ); + + if ( $valid ) { + wp_set_password( $password, $user->ID ); + } + } + if ( ! $valid ) { return new WP_Error( 'incorrect_password', diff --git a/src/wp-login.php b/src/wp-login.php index 0b1d2cff308ec..932a162ff1dc7 100644 --- a/src/wp-login.php +++ b/src/wp-login.php @@ -970,7 +970,7 @@ function wp_login_viewport_meta() { // Check if password is one or all empty spaces. if ( ! empty( $_POST['pass1'] ) ) { - $_POST['pass1'] = trim( $_POST['pass1'] ); + $_POST['pass1'] = trim( wp_unslash( $_POST['pass1'] ) ); if ( empty( $_POST['pass1'] ) ) { $errors->add( 'password_reset_empty_space', __( 'The password cannot be a space or all spaces.' ) ); @@ -978,7 +978,7 @@ function wp_login_viewport_meta() { } // Check if password fields do not match. - if ( ! empty( $_POST['pass1'] ) && trim( $_POST['pass2'] ) !== $_POST['pass1'] ) { + if ( ! empty( $_POST['pass1'] ) && trim( wp_unslash( $_POST['pass2'] ) ) !== $_POST['pass1'] ) { $errors->add( 'password_reset_mismatch', __( 'Error: The passwords do not match.' ) ); } diff --git a/tests/phpunit/tests/auth.php b/tests/phpunit/tests/auth.php index a290d11e118e6..7b8997a7b874b 100644 --- a/tests/phpunit/tests/auth.php +++ b/tests/phpunit/tests/auth.php @@ -154,6 +154,55 @@ public function data_passwords_for_trimming() { ); } + /** + * Tests that wp_signon() unslashes the password from $_POST. + * + * @ticket 13655 + */ + public function test_wp_signon_unslashes_password() { + $password = "pa'ss"; + wp_set_password( $password, $this->user->ID ); + + $_POST['log'] = $this->user->user_login; + $_POST['pwd'] = wp_slash( $password ); + $_POST['test'] = 1; + + $authed_user = wp_signon(); + + unset( $_POST['log'], $_POST['pwd'], $_POST['test'] ); + + $this->assertNotWPError( $authed_user ); + $this->assertInstanceOf( 'WP_User', $authed_user ); + $this->assertSame( $this->user->ID, $authed_user->ID ); + } + + /** + * Tests that a password hashed with slashes intact is migrated on login. + * + * @ticket 13655 + */ + public function test_slashed_password_hash_is_migrated_on_login() { + $password = "pa'ss"; + + // Simulate a legacy hash of the slashed password. + $slashed_hash = wp_hash_password( wp_slash( $password ) ); + wp_update_user( + array( + 'ID' => $this->user->ID, + 'user_pass' => $slashed_hash, + ) + ); + + $authed_user = wp_authenticate( $this->user->user_login, $password ); + + $this->assertNotWPError( $authed_user ); + $this->assertSame( $this->user->ID, $authed_user->ID ); + + // The hash should now be of the unslashed password. + $user = get_user_by( 'id', $this->user->ID ); + $this->assertTrue( wp_check_password( $password, $user->user_pass, $user->ID ) ); + } + /** * Tests hooking into wp_set_password(). *