Skip to content

Commit 7ccfc84

Browse files
committed
Ensure email|login changes invalidate token
1 parent 82a263c commit 7ccfc84

File tree

3 files changed

+127
-23
lines changed

3 files changed

+127
-23
lines changed

tests/wp-includes/rest-api/auth/class-test-wp-rest-token.php

Lines changed: 80 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ public function test_authenticate() {
114114
'role' => 'administrator',
115115
'user_login' => 'testuser',
116116
'user_pass' => 'testpassword',
117+
'user_email' => '[email protected]',
117118
);
118119

119120
$user_id = $this->factory->user->create( $user_data );
@@ -123,14 +124,18 @@ public function test_authenticate() {
123124
array(
124125
'data' => array(
125126
'user' => array(
126-
'id' => $user_id,
127-
'type' => 'wp_user',
127+
'id' => $user_id,
128+
'type' => 'wp_user',
129+
'user_login' => 'testuser',
130+
'user_email' => '[email protected]',
128131
),
129132
),
130133
)
131134
)
132135
);
133136

137+
add_filter( 'rest_authentication_is_api_request', '__return_true' );
138+
134139
// Another authentication method was used.
135140
$this->assertEquals( 'alt_auth', $this->token->authenticate( 'alt_auth' ) );
136141

@@ -186,6 +191,10 @@ public function test_authenticate() {
186191
$authenticate = $mock->authenticate( null );
187192
$this->assertTrue( $authenticate );
188193
$this->assertEquals( $user_id, get_current_user_id() );
194+
remove_filter( 'rest_authentication_is_api_request', '__return_true' );
195+
196+
$authenticate = $mock->authenticate( null );
197+
$this->assertNull( $authenticate );
189198
}
190199

191200
/**
@@ -202,6 +211,7 @@ public function test_require_token() {
202211
'role' => 'administrator',
203212
'user_login' => 'testuser',
204213
'user_pass' => 'testpassword',
214+
'user_email' => '[email protected]',
205215
);
206216

207217
// @codingStandardsIgnoreStart
@@ -315,8 +325,8 @@ public function test_generate_token() {
315325
$user_data = array(
316326
'role' => 'administrator',
317327
'user_login' => 'testuser',
318-
'user_email' => '[email protected]',
319328
'user_pass' => 'testpassword',
329+
'user_email' => '[email protected]',
320330
);
321331

322332
$request = new WP_REST_Request( 'POST', 'wp/v2/token' );
@@ -379,6 +389,7 @@ public function test_validate_token() {
379389
'role' => 'administrator',
380390
'user_login' => 'testuser',
381391
'user_pass' => 'testpassword',
392+
'user_email' => '[email protected]',
382393
);
383394

384395
$user_id = $this->factory->user->create( $user_data );
@@ -390,8 +401,10 @@ public function test_validate_token() {
390401
'exp' => time() - 1,
391402
'data' => array(
392403
'user' => array(
393-
'id' => 10,
394-
'type' => 'wp_user',
404+
'id' => 10,
405+
'type' => 'wp_user',
406+
'user_login' => 'testuser',
407+
'user_email' => '[email protected]',
395408
),
396409
),
397410
)
@@ -521,6 +534,43 @@ public function test_validate_token() {
521534
$this->assertTrue( is_wp_error( $validate_token ) );
522535
$this->assertEquals( $validate_token->get_error_code(), 'rest_authentication_token_error' );
523536

537+
// Invalid token, user email has changed.
538+
wp_update_user(
539+
array(
540+
'ID' => $user_id,
541+
'user_email' => '[email protected]',
542+
)
543+
);
544+
545+
$mock = $this->getMockBuilder( get_class( $this->token ) )
546+
->setMethods(
547+
array(
548+
'jwt',
549+
)
550+
)
551+
->getMock();
552+
$mock->method( 'jwt' )->willReturn( $jwt );
553+
554+
$validate_token = $mock->validate_token();
555+
$this->assertTrue( is_wp_error( $validate_token ) );
556+
$this->assertEquals( $validate_token->get_error_code(), 'rest_authentication_invalid_token_user_email' );
557+
558+
// Invalid token, user login has changed. You cannot change your login, but better safe than sorry.
559+
$jwt->data->user->user_login = 'testuser1';
560+
561+
$mock = $this->getMockBuilder( get_class( $this->token ) )
562+
->setMethods(
563+
array(
564+
'jwt',
565+
)
566+
)
567+
->getMock();
568+
$mock->method( 'jwt' )->willReturn( $jwt );
569+
570+
$validate_token = $mock->validate_token();
571+
$this->assertTrue( is_wp_error( $validate_token ) );
572+
$this->assertEquals( $validate_token->get_error_code(), 'rest_authentication_invalid_token_user_login' );
573+
524574
// @codingStandardsIgnoreStart
525575
unset( $_SERVER['HTTP_AUTHORIZATION'] );
526576
// @codingStandardsIgnoreEnd
@@ -590,15 +640,18 @@ public function test_validate_user() {
590640
'role' => 'administrator',
591641
'user_login' => 'testuser',
592642
'user_pass' => 'testpassword',
643+
'user_email' => '[email protected]',
593644
);
594645

595646
$jwt = json_decode(
596647
wp_json_encode(
597648
array(
598649
'data' => array(
599650
'user' => array(
600-
'id' => 10,
601-
'type' => 'wp_user',
651+
'id' => 10,
652+
'type' => 'wp_user',
653+
'user_login' => 'testuser',
654+
'user_email' => '[email protected]',
602655
),
603656
),
604657
)
@@ -613,8 +666,26 @@ public function test_validate_user() {
613666
$this->assertTrue( is_wp_error( $user_valid ) );
614667
$this->assertEquals( $user_valid->get_error_code(), 'rest_authentication_invalid_token_wp_user' );
615668

616-
$jwt->data->user->id = $this->factory->user->create( $user_data );
617-
$user_valid = $this->token->validate_user( $jwt );
669+
// Create the user.
670+
$jwt->data->user->id = $this->factory->user->create( $user_data );
671+
$jwt->data->user->user_login = 'testuser1';
672+
673+
$user_valid = $this->token->validate_user( $jwt );
674+
$this->assertTrue( is_wp_error( $user_valid ) );
675+
$this->assertEquals( $user_valid->get_error_code(), 'rest_authentication_invalid_token_user_login' );
676+
677+
// Change user values.
678+
$jwt->data->user->user_login = 'testuser';
679+
$jwt->data->user->user_email = '[email protected]';
680+
681+
$user_valid = $this->token->validate_user( $jwt );
682+
$this->assertTrue( is_wp_error( $user_valid ) );
683+
$this->assertEquals( $user_valid->get_error_code(), 'rest_authentication_invalid_token_user_email' );
684+
685+
// Reset user email.
686+
$jwt->data->user->user_email = '[email protected]';
687+
688+
$user_valid = $this->token->validate_user( $jwt );
618689
$this->assertTrue( $user_valid );
619690
}
620691

wp-includes/rest-api/auth/class-wp-rest-key-pair.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,8 +306,8 @@ public function authenticate( $user, WP_REST_Request $request ) {
306306
// Retrieves a user if a valid key & secret is given.
307307
$get_user = get_users(
308308
array(
309-
'meta_key' => $key, // WPCS: slow query ok.
310-
'meta_value' => wp_hash( $secret ), // WPCS: slow query ok.
309+
'meta_key' => $key, // phpcs:ignore
310+
'meta_value' => wp_hash( $secret ), // phpcs:ignore
311311
)
312312
);
313313

wp-includes/rest-api/auth/class-wp-rest-token.php

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,14 @@ public function get_item_schema() {
211211
*/
212212
public function authenticate( $result ) {
213213

214+
// Check for valid API requests.
215+
$api_request = ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) || ( defined( 'REST_REQUEST' ) && REST_REQUEST );
216+
217+
// This is not the authentication you're looking for.
218+
if ( ! apply_filters( 'rest_authentication_is_api_request', $api_request ) ) {
219+
return $result;
220+
}
221+
214222
// Another authentication method was used.
215223
if ( ! is_null( $result ) ) {
216224
return $result;
@@ -245,8 +253,8 @@ public function authenticate( $result ) {
245253
*/
246254
public function require_token() {
247255
$require_token = true;
248-
$request_uri = isset( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : false; // WPCS: sanitization okay.
249-
$request_method = isset( $_SERVER['REQUEST_METHOD'] ) ? $_SERVER['REQUEST_METHOD'] : false; // WPCS: sanitization okay.
256+
$request_uri = isset( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : false; // phpcs:ignore
257+
$request_method = isset( $_SERVER['REQUEST_METHOD'] ) ? $_SERVER['REQUEST_METHOD'] : false; // phpcs:ignore
250258
$rest_uri = self::get_rest_uri();
251259

252260
// User is already authenticated.
@@ -507,11 +515,11 @@ public function validate_token() {
507515
public function get_auth_header() {
508516

509517
// Get HTTP Authorization Header.
510-
$header = isset( $_SERVER['HTTP_AUTHORIZATION'] ) ? $_SERVER['HTTP_AUTHORIZATION'] : false; // WPCS: sanitization okay.
518+
$header = isset( $_SERVER['HTTP_AUTHORIZATION'] ) ? $_SERVER['HTTP_AUTHORIZATION'] : false; // phpcs:ignore
511519

512520
// Check for alternative header.
513521
if ( ! $header && isset( $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ) ) {
514-
$header = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; // WPCS: sanitization okay.
522+
$header = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; // phpcs:ignore
515523
}
516524

517525
// The HTTP Authorization Header is missing, return an error.
@@ -599,14 +607,39 @@ public function validate_user( $token ) {
599607
);
600608
}
601609

602-
if ( 'wp_user' === $token->data->user->type && get_userdata( $token->data->user->id ) === false ) {
603-
return new WP_Error(
604-
'rest_authentication_invalid_token_wp_user',
605-
__( 'Token user is invalid.', 'jwt-auth' ),
606-
array(
607-
'status' => 403,
608-
)
609-
);
610+
if ( 'wp_user' === $token->data->user->type ) {
611+
612+
$userdata = get_userdata( $token->data->user->id );
613+
614+
if ( false === $userdata ) {
615+
return new WP_Error(
616+
'rest_authentication_invalid_token_wp_user',
617+
__( 'Token user is invalid.', 'jwt-auth' ),
618+
array(
619+
'status' => 403,
620+
)
621+
);
622+
}
623+
624+
if ( $token->data->user->user_login !== $userdata->user_login ) {
625+
return new WP_Error(
626+
'rest_authentication_invalid_token_user_login',
627+
__( 'Token user_login is invalid.', 'jwt-auth' ),
628+
array(
629+
'status' => 403,
630+
)
631+
);
632+
}
633+
634+
if ( $token->data->user->user_email !== $userdata->user_email ) {
635+
return new WP_Error(
636+
'rest_authentication_invalid_token_user_email',
637+
__( 'Token user_email is invalid.', 'jwt-auth' ),
638+
array(
639+
'status' => 403,
640+
)
641+
);
642+
}
610643
}
611644

612645
return true;

0 commit comments

Comments
 (0)