Changeset 33019
- Timestamp:
- 07/01/2015 06:32:07 AM (10 years ago)
- Location:
- trunk
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/user.php
r32980 r33019 2459 2459 } 2460 2460 2461 if ( $wp_hasher->CheckPassword( $key, $row->user_activation_key ) ) 2461 /** 2462 * Filter the expiration time of password reset keys. 2463 * 2464 * @since 4.3.0 2465 * 2466 * @param int $expiration The expiration time in seconds. 2467 */ 2468 $expiration_duration = apply_filters( 'password_reset_expiration', DAY_IN_SECONDS ); 2469 2470 if ( false !== strpos( $row->user_activation_key, ':' ) ) { 2471 list( $pass_request_time, $pass_key ) = explode( ':', $row->user_activation_key, 2 ); 2472 $expiration_time = $pass_request_time + $expiration_duration; 2473 } else { 2474 $pass_key = $row->user_activation_key; 2475 $expiration_time = false; 2476 } 2477 2478 $hash_is_correct = $wp_hasher->CheckPassword( $key, $pass_key ); 2479 2480 if ( $hash_is_correct && $expiration_time && time() < $expiration_time ) { 2462 2481 return get_userdata( $row->ID ); 2463 2464 if ( $key === $row->user_activation_key ) { 2482 } elseif ( $hash_is_correct && $expiration_time ) { 2483 // Key has an expiration time that's passed 2484 return new WP_Error( 'expired_key', __( 'Invalid key' ) ); 2485 } 2486 2487 if ( hash_equals( $row->user_activation_key, $key ) || ( $hash_is_correct && ! $expiration_time ) ) { 2465 2488 $return = new WP_Error( 'expired_key', __( 'Invalid key' ) ); 2466 2489 $user_id = $row->ID; … … 2468 2491 /** 2469 2492 * Filter the return value of check_password_reset_key() when an 2470 * old-style key is used (plain-text key was stored in the database).2493 * old-style key is used. 2471 2494 * 2472 * @since 3.7.0 2495 * @since 3.7.0 Previously plain-text keys were stored in the database. 2496 * @since 4.3.0 Previously key hashes were stored without an expiration time. 2473 2497 * 2474 2498 * @param WP_Error $return A WP_Error object denoting an expired key. -
trunk/src/wp-login.php
r32672 r33019 364 364 $wp_hasher = new PasswordHash( 8, true ); 365 365 } 366 $hashed = $wp_hasher->HashPassword( $key );366 $hashed = time() . ':' . $wp_hasher->HashPassword( $key ); 367 367 $wpdb->update( $wpdb->users, array( 'user_activation_key' => $hashed ), array( 'user_login' => $user_login ) ); 368 368 … … 529 529 530 530 if ( isset( $_GET['error'] ) ) { 531 if ( 'invalidkey' == $_GET['error'] ) 532 $errors->add( 'invalidkey', __( 'Sorry, that key does not appear to be valid.' ) ); 533 elseif ( 'expiredkey' == $_GET['error'] ) 534 $errors->add( 'expiredkey', __( 'Sorry, that key has expired. Please try again.' ) ); 531 if ( 'invalidkey' == $_GET['error'] ) { 532 $errors->add( 'invalidkey', __( 'Your password reset link appears to be invalid. Please request a new lnk below.' ) ); 533 } elseif ( 'expiredkey' == $_GET['error'] ) { 534 $errors->add( 'expiredkey', __( 'Your password reset link has expired. Please request a new link below.' ) ); 535 } 535 536 } 536 537 -
trunk/tests/phpunit/tests/auth.php
r32785 r33019 7 7 class Tests_Auth extends WP_UnitTestCase { 8 8 var $user_id; 9 var $wp_hasher; 9 10 10 11 function setUp() { 11 12 parent::setUp(); 12 13 $this->user_id = $this->factory->user->create(); 14 15 require_once ABSPATH . WPINC . '/class-phpass.php'; 16 $this->wp_hasher = new PasswordHash( 8, true ); 13 17 } 14 18 … … 160 164 $this->assertInstanceOf( 'WP_Error', $user ); 161 165 } 166 167 /** 168 * @ticket 32429 169 */ 170 function test_user_activation_key_is_checked() { 171 global $wpdb; 172 173 $key = wp_generate_password( 20, false ); 174 $user = $this->factory->user->create_and_get(); 175 $wpdb->update( $wpdb->users, array( 176 'user_activation_key' => strtotime( '-1 hour' ) . ':' . $this->wp_hasher->HashPassword( $key ), 177 ), array( 178 'ID' => $user->ID, 179 ) ); 180 181 // A valid key should be accepted 182 $check = check_password_reset_key( $key, $user->user_login ); 183 $this->assertInstanceOf( 'WP_User', $check ); 184 $this->assertSame( $user->ID, $check->ID ); 185 186 // An invalid key should be rejected 187 $check = check_password_reset_key( 'key', $user->user_login ); 188 $this->assertInstanceOf( 'WP_Error', $check ); 189 190 // An empty key should be rejected 191 $check = check_password_reset_key( '', $user->user_login ); 192 $this->assertInstanceOf( 'WP_Error', $check ); 193 194 // A truncated key should be rejected 195 $partial = substr( $key, 0, 10 ); 196 $check = check_password_reset_key( $partial, $user->user_login ); 197 $this->assertInstanceOf( 'WP_Error', $check ); 198 } 199 200 /** 201 * @ticket 32429 202 */ 203 function test_expired_user_activation_key_is_rejected() { 204 global $wpdb; 205 206 $key = wp_generate_password( 20, false ); 207 $user = $this->factory->user->create_and_get(); 208 $wpdb->update( $wpdb->users, array( 209 'user_activation_key' => strtotime( '-48 hours' ) . ':' . $this->wp_hasher->HashPassword( $key ), 210 ), array( 211 'ID' => $user->ID, 212 ) ); 213 214 // An expired but otherwise valid key should be rejected 215 $check = check_password_reset_key( $key, $user->user_login ); 216 $this->assertInstanceOf( 'WP_Error', $check ); 217 } 218 219 /** 220 * @ticket 32429 221 */ 222 function test_empty_user_activation_key_fails_key_check() { 223 global $wpdb; 224 225 $user = $this->factory->user->create_and_get(); 226 227 // An empty user_activation_key should not allow any key to be accepted 228 $check = check_password_reset_key( 'key', $user->user_login ); 229 $this->assertInstanceOf( 'WP_Error', $check ); 230 231 // An empty user_activation_key should not allow an empty key to be accepted 232 $check = check_password_reset_key( '', $user->user_login ); 233 $this->assertInstanceOf( 'WP_Error', $check ); 234 } 235 236 /** 237 * @ticket 32429 238 */ 239 function test_legacy_user_activation_key_is_rejected() { 240 global $wpdb; 241 242 // A legacy user_activation_key is one without the `time()` prefix introduced in WordPress 4.3. 243 244 $key = wp_generate_password( 20, false ); 245 $user = $this->factory->user->create_and_get(); 246 $wpdb->update( $wpdb->users, array( 247 'user_activation_key' => $this->wp_hasher->HashPassword( $key ), 248 ), array( 249 'ID' => $user->ID, 250 ) ); 251 252 // A legacy user_activation_key should not be accepted 253 $check = check_password_reset_key( $key, $user->user_login ); 254 $this->assertInstanceOf( 'WP_Error', $check ); 255 256 // An empty key with a legacy user_activation_key should be rejected 257 $check = check_password_reset_key( '', $user->user_login ); 258 $this->assertInstanceOf( 'WP_Error', $check ); 259 } 260 261 /** 262 * @ticket 32429 263 * @ticket 24783 264 */ 265 function test_plaintext_user_activation_key_is_rejected() { 266 global $wpdb; 267 268 // A plaintext user_activation_key is one stored before hashing was introduced in WordPress 3.7. 269 270 $key = wp_generate_password( 20, false ); 271 $user = $this->factory->user->create_and_get(); 272 $wpdb->update( $wpdb->users, array( 273 'user_activation_key' => $key, 274 ), array( 275 'ID' => $user->ID, 276 ) ); 277 278 // A plaintext user_activation_key should not allow an otherwise valid key to be accepted 279 $check = check_password_reset_key( $key, $user->user_login ); 280 $this->assertInstanceOf( 'WP_Error', $check ); 281 282 // A plaintext user_activation_key should not allow an empty key to be accepted 283 $check = check_password_reset_key( '', $user->user_login ); 284 $this->assertInstanceOf( 'WP_Error', $check ); 285 } 162 286 }
Note: See TracChangeset
for help on using the changeset viewer.