Changeset 50065
- Timestamp:
- 01/29/2021 12:05:20 AM (4 years ago)
- Location:
- trunk
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/default-filters.php
r49992 r50065 281 281 add_action( 'auth_cookie_valid', 'rest_cookie_collect_status' ); 282 282 add_action( 'application_password_failed_authentication', 'rest_application_password_collect_status' ); 283 add_action( 'application_password_did_authenticate', 'rest_application_password_collect_status' );283 add_action( 'application_password_did_authenticate', 'rest_application_password_collect_status', 10, 2 ); 284 284 add_filter( 'rest_authentication_errors', 'rest_application_password_check_errors', 90 ); 285 285 add_filter( 'rest_authentication_errors', 'rest_cookie_check_errors', 100 ); -
trunk/src/wp-includes/rest-api.php
r50060 r50065 1049 1049 * 1050 1050 * @since 5.6.0 1051 * @since 5.7.0 Added the `$app_password` parameter. 1051 1052 * 1052 1053 * @global WP_User|WP_Error|null $wp_rest_application_password_status 1054 * @global string|null $wp_rest_application_password_uuid 1053 1055 * 1054 1056 * @param WP_Error $user_or_error The authenticated user or error instance. 1055 */ 1056 function rest_application_password_collect_status( $user_or_error ) { 1057 global $wp_rest_application_password_status; 1057 * @param array $app_password The Application Password used to authenticate. 1058 */ 1059 function rest_application_password_collect_status( $user_or_error, $app_password = array() ) { 1060 global $wp_rest_application_password_status, $wp_rest_application_password_uuid; 1058 1061 1059 1062 $wp_rest_application_password_status = $user_or_error; 1063 1064 if ( empty( $app_password['uuid'] ) ) { 1065 $wp_rest_application_password_uuid = null; 1066 } else { 1067 $wp_rest_application_password_uuid = $app_password['uuid']; 1068 } 1069 } 1070 1071 /** 1072 * Gets the Application Password used for authenticating the request. 1073 * 1074 * @since 5.7.0 1075 * 1076 * @global string|null $wp_rest_application_password_uuid 1077 * 1078 * @return string|null The App Password UUID, or null if Application Passwords was not used. 1079 */ 1080 function rest_get_authenticated_app_password() { 1081 global $wp_rest_application_password_uuid; 1082 1083 return $wp_rest_application_password_uuid; 1060 1084 } 1061 1085 -
trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php
r50030 r50065 53 53 'callback' => array( $this, 'delete_items' ), 54 54 'permission_callback' => array( $this, 'delete_items_permissions_check' ), 55 ), 56 'schema' => array( $this, 'get_public_item_schema' ), 57 ) 58 ); 59 60 register_rest_route( 61 $this->namespace, 62 '/' . $this->rest_base . '/introspect', 63 array( 64 array( 65 'methods' => WP_REST_Server::READABLE, 66 'callback' => array( $this, 'get_current_item' ), 67 'permission_callback' => array( $this, 'get_current_item_permissions_check' ), 68 'args' => array( 69 'context' => $this->get_context_param( array( 'default' => 'view' ) ), 70 ), 55 71 ), 56 72 'schema' => array( $this, 'get_public_item_schema' ), … … 375 391 376 392 /** 393 * Checks if a given request has access to get the currently used application password. 394 * 395 * @since 5.7.0 396 * 397 * @param WP_REST_Request $request Full details about the request. 398 * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. 399 */ 400 public function get_current_item_permissions_check( $request ) { 401 $user = $this->get_user( $request ); 402 403 if ( is_wp_error( $user ) ) { 404 return $user; 405 } 406 407 if ( get_current_user_id() !== $user->ID ) { 408 return new WP_Error( 409 'rest_cannot_introspect_app_password_for_non_authenticated_user', 410 __( 'The authenticated Application Password can only be introspected for the current user.' ), 411 array( 'status' => rest_authorization_required_code() ) 412 ); 413 } 414 415 return true; 416 } 417 418 /** 419 * Retrieves the application password being currently used for authentication. 420 * 421 * @since 5.7.0 422 * 423 * @param WP_REST_Request $request Full details about the request. 424 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. 425 */ 426 public function get_current_item( $request ) { 427 $user = $this->get_user( $request ); 428 429 if ( is_wp_error( $user ) ) { 430 return $user; 431 } 432 433 $uuid = rest_get_authenticated_app_password(); 434 435 if ( ! $uuid ) { 436 return new WP_Error( 437 'rest_no_authenticated_app_password', 438 __( 'Cannot introspect Application Password.' ), 439 array( 'status' => 404 ) 440 ); 441 } 442 443 $password = WP_Application_Passwords::get_user_application_password( $user->ID, $uuid ); 444 445 if ( ! $password ) { 446 return new WP_Error( 447 'rest_application_password_not_found', 448 __( 'Application password not found.' ), 449 array( 'status' => 500 ) 450 ); 451 } 452 453 return $this->prepare_item_for_response( $password, $request ); 454 } 455 456 /** 377 457 * Performs a permissions check for the request. 378 458 * -
trunk/tests/phpunit/tests/auth.php
r49919 r50065 39 39 wp_set_current_user( self::$user_id ); 40 40 update_site_option( 'using_application_passwords', 1 ); 41 42 unset( $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'], $GLOBALS['wp_rest_application_password_status'], $GLOBALS['wp_rest_application_password_uuid'] ); 41 43 } 42 44 … … 45 47 46 48 // Cleanup all the global state. 47 unset( $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'], $GLOBALS['wp_rest_application_password_status'] );49 unset( $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'], $GLOBALS['wp_rest_application_password_status'], $GLOBALS['wp_rest_application_password_uuid'] ); 48 50 } 49 51 … … 443 445 444 446 // Create a new app-only password. 445 list( $user_app_password ) = WP_Application_Passwords::create_new_application_password( $user_id, array( 'name' => 'phpunit' ) );447 list( $user_app_password, $item ) = WP_Application_Passwords::create_new_application_password( $user_id, array( 'name' => 'phpunit' ) ); 446 448 447 449 // Fake a REST API request. … … 453 455 $_SERVER['PHP_AUTH_PW'] = 'http_auth_pass'; 454 456 455 $this->assertSame( 456 null, 457 $this->assertNull( 457 458 wp_validate_application_password( null ), 458 459 'Regular user account password should not be allowed for API authentication' 459 460 ); 461 $this->assertNull( rest_get_authenticated_app_password() ); 460 462 461 463 // Not try with an App password instead. … … 467 469 'Application passwords should be allowed for API authentication' 468 470 ); 471 $this->assertEquals( $item['uuid'], rest_get_authenticated_app_password() ); 469 472 } 470 473 -
trunk/tests/phpunit/tests/rest-api/rest-application-passwords-controller.php
r50030 r50065 68 68 69 69 add_filter( 'wp_is_application_passwords_available', '__return_true' ); 70 } 71 72 public function tearDown() { 73 parent::tearDown(); 74 unset( $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'], $GLOBALS['wp_rest_application_password_status'], $GLOBALS['wp_rest_application_password_uuid'] ); 70 75 } 71 76 … … 878 883 $this->assertCount( 7, $properties ); 879 884 } 885 886 /** 887 * @ticket 52275 888 */ 889 public function test_introspect_item() { 890 $password = $this->setup_app_password_authenticated_request(); 891 $response = rest_do_request( '/wp/v2/users/me/application-passwords/introspect' ); 892 $this->assertNotWPError( $response->as_error() ); 893 894 $this->assertEquals( $password['uuid'], $response->get_data()['uuid'] ); 895 } 896 897 /** 898 * @ticket 52275 899 */ 900 public function test_introspect_item_specific_user() { 901 $password = $this->setup_app_password_authenticated_request(); 902 $response = rest_do_request( '/wp/v2/users/' . self::$admin . '/application-passwords/introspect' ); 903 904 $this->assertEquals( $password['uuid'], $response->get_data()['uuid'] ); 905 } 906 907 /** 908 * @ticket 52275 909 */ 910 public function test_introspect_item_logged_out() { 911 $response = rest_do_request( '/wp/v2/users/me/application-passwords/introspect' ); 912 $this->assertErrorResponse( 'rest_not_logged_in', $response, 401 ); 913 } 914 915 /** 916 * @ticket 52275 917 */ 918 public function test_introspect_item_wrong_user() { 919 $this->setup_app_password_authenticated_request(); 920 $response = rest_do_request( '/wp/v2/users/' . self::$subscriber_id . '/application-passwords/introspect' ); 921 $this->assertErrorResponse( 'rest_cannot_introspect_app_password_for_non_authenticated_user', $response, 403 ); 922 } 923 924 /** 925 * @ticket 52275 926 */ 927 public function test_introspect_item_no_app_password_used() { 928 wp_set_current_user( self::$admin ); 929 $response = rest_do_request( '/wp/v2/users/me/application-passwords/introspect' ); 930 $this->assertErrorResponse( 'rest_no_authenticated_app_password', $response, 404 ); 931 } 932 933 /** 934 * @ticket 52275 935 */ 936 public function test_introspect_item_password_invalid() { 937 $this->setup_app_password_authenticated_request(); 938 add_action( 939 'application_password_did_authenticate', 940 function() { 941 $GLOBALS['wp_rest_application_password_uuid'] = 'invalid_uuid'; 942 } 943 ); 944 945 $response = rest_do_request( '/wp/v2/users/me/application-passwords/introspect' ); 946 $this->assertErrorResponse( 'rest_application_password_not_found', $response, 500 ); 947 } 948 949 /** 950 * Sets up a REST API request to be authenticated using an App Password. 951 * 952 * @since 5.7.0 953 * 954 * @return array The created App Password. 955 */ 956 private function setup_app_password_authenticated_request() { 957 list( $password, $item ) = WP_Application_Passwords::create_new_application_password( self::$admin, array( 'name' => 'Test' ) ); 958 959 $_SERVER['PHP_AUTH_USER'] = get_userdata( self::$admin )->user_login; 960 $_SERVER['PHP_AUTH_PW'] = $password; 961 962 $GLOBALS['current_user'] = null; 963 964 add_filter( 'application_password_is_api_request', '__return_true' ); 965 966 return $item; 967 } 880 968 } -
trunk/tests/phpunit/tests/rest-api/rest-schema-setup.php
r49925 r50065 120 120 '/wp/v2/users/me', 121 121 '/wp/v2/users/(?P<user_id>(?:[\\d]+|me))/application-passwords', 122 '/wp/v2/users/(?P<user_id>(?:[\\d]+|me))/application-passwords/introspect', 122 123 '/wp/v2/users/(?P<user_id>(?:[\\d]+|me))/application-passwords/(?P<uuid>[\\w\\-]+)', 123 124 '/wp/v2/comments', -
trunk/tests/qunit/fixtures/wp-api-generated.js
r50030 r50065 4986 4986 ], 4987 4987 "args": [] 4988 } 4989 ] 4990 }, 4991 "/wp/v2/users/(?P<user_id>(?:[\\d]+|me))/application-passwords/introspect": { 4992 "namespace": "wp/v2", 4993 "methods": [ 4994 "GET" 4995 ], 4996 "endpoints": [ 4997 { 4998 "methods": [ 4999 "GET" 5000 ], 5001 "args": { 5002 "context": { 5003 "description": "Scope under which the request is made; determines fields present in response.", 5004 "type": "string", 5005 "enum": [ 5006 "view", 5007 "embed", 5008 "edit" 5009 ], 5010 "default": "view", 5011 "required": false 5012 } 5013 } 4988 5014 } 4989 5015 ]
Note: See TracChangeset
for help on using the changeset viewer.