Make WordPress Core


Ignore:
Timestamp:
07/21/2020 12:01:10 PM (6 years ago)
Author:
TimothyBlynJacobs
Message:

REST API: Issue a _doing_it_wrong when registering a route without a permission callback.

The REST API treats routes without a permission_callback as public. Because this happens without any warning to the user, if the permission callback is unintentionally omitted or misspelled, the endpoint can end up being available to the public. Such a scenario has happened multiple times in the wild, and the results can be catostrophic when it occurs.

For REST API routes that are intended to be public, it is recommended to set the permission callback to the __return_true built in function.

Fixes #50075.
Props rmccue, sorenbronsted, whyisjake, SergeyBiryukov, TimothyBlynJacobs.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tests/phpunit/tests/rest-api.php

    r48365 r48526  
    8585                        '/test',
    8686                        array(
    87                                 'methods'  => array( 'GET' ),
    88                                 'callback' => '__return_null',
     87                                'methods'             => array( 'GET' ),
     88                                'callback'            => '__return_null',
     89                                'permission_callback' => '__return_true',
    8990                        )
    9091                );
     
    121122                        array(
    122123                                array(
    123                                         'methods'  => array( 'GET' ),
    124                                         'callback' => '__return_null',
    125                                 ),
    126                                 array(
    127                                         'methods'  => array( 'POST' ),
    128                                         'callback' => '__return_null',
     124                                        'methods'             => array( 'GET' ),
     125                                        'callback'            => '__return_null',
     126                                        'permission_callback' => '__return_true',
     127                                ),
     128                                array(
     129                                        'methods'             => array( 'POST' ),
     130                                        'callback'            => '__return_null',
     131                                        'permission_callback' => '__return_true',
    129132                                ),
    130133                        )
     
    161164                        '/test',
    162165                        array(
    163                                 'methods'  => array( 'GET' ),
    164                                 'callback' => '__return_null',
     166                                'methods'             => array( 'GET' ),
     167                                'callback'            => '__return_null',
     168                                'permission_callback' => '__return_true',
    165169                        )
    166170                );
     
    169173                        '/test',
    170174                        array(
    171                                 'methods'  => array( 'POST' ),
    172                                 'callback' => '__return_null',
     175                                'methods'             => array( 'POST' ),
     176                                'callback'            => '__return_null',
     177                                'permission_callback' => '__return_true',
    173178                        )
    174179                );
     
    188193                        '/test',
    189194                        array(
    190                                 'methods'      => array( 'GET' ),
    191                                 'callback'     => '__return_null',
    192                                 'should_exist' => false,
     195                                'methods'             => array( 'GET' ),
     196                                'callback'            => '__return_null',
     197                                'permission_callback' => '__return_true',
     198                                'should_exist'        => false,
    193199                        )
    194200                );
     
    197203                        '/test',
    198204                        array(
    199                                 'methods'      => array( 'POST' ),
    200                                 'callback'     => '__return_null',
    201                                 'should_exist' => true,
     205                                'methods'             => array( 'POST' ),
     206                                'callback'            => '__return_null',
     207                                'permission_callback' => '__return_true',
     208                                'should_exist'        => true,
    202209                        ),
    203210                        true
     
    224231                        '/test-empty-namespace',
    225232                        array(
    226                                 'methods'  => array( 'POST' ),
    227                                 'callback' => '__return_null',
     233                                'methods'             => array( 'POST' ),
     234                                'callback'            => '__return_null',
     235                                'permission_callback' => '__return_true',
    228236                        ),
    229237                        true
     
    243251                        '',
    244252                        array(
    245                                 'methods'  => array( 'POST' ),
    246                                 'callback' => '__return_null',
     253                                'methods'             => array( 'POST' ),
     254                                'callback'            => '__return_null',
     255                                'permission_callback' => '__return_true',
    247256                        ),
    248257                        true
     
    265274                        '/test',
    266275                        array(
    267                                 'methods'  => array( 'GET' ),
    268                                 'callback' => '__return_null',
     276                                'methods'             => array( 'GET' ),
     277                                'callback'            => '__return_null',
     278                                'permission_callback' => '__return_true',
    269279                        )
    270280                );
     
    283293                        '/test',
    284294                        array(
    285                                 'methods'  => 'GET',
    286                                 'callback' => '__return_null',
     295                                'methods'             => 'GET',
     296                                'callback'            => '__return_null',
     297                                'permission_callback' => '__return_true',
    287298                        )
    288299                );
     
    301312                        '/test',
    302313                        array(
    303                                 'methods'  => array( 'GET', 'POST' ),
    304                                 'callback' => '__return_null',
     314                                'methods'             => array( 'GET', 'POST' ),
     315                                'callback'            => '__return_null',
     316                                'permission_callback' => '__return_true',
    305317                        )
    306318                );
     
    325337                        '/test',
    326338                        array(
    327                                 'methods'  => 'GET,POST',
    328                                 'callback' => '__return_null',
     339                                'methods'             => 'GET,POST',
     340                                'callback'            => '__return_null',
     341                                'permission_callback' => '__return_true',
    329342                        )
    330343                );
     
    346359                        '/test',
    347360                        array(
    348                                 'methods'  => 'GET,POST',
    349                                 'callback' => '__return_null',
     361                                'methods'             => 'GET,POST',
     362                                'callback'            => '__return_null',
     363                                'permission_callback' => '__return_true',
    350364                        )
    351365                );
     
    368382                        '/test',
    369383                        array(
    370                                 'methods'  => 'GET,POST',
    371                                 'callback' => '__return_true',
     384                                'methods'             => 'GET,POST',
     385                                'callback'            => '__return_true',
     386                                'permission_callback' => '__return_true',
    372387                        )
    373388                );
     
    911926                        '/test',
    912927                        array(
    913                                 'methods'  => array( 'GET' ),
    914                                 'callback' => '__return_null',
     928                                'methods'             => array( 'GET' ),
     929                                'callback'            => '__return_null',
     930                                'permission_callback' => '__return_true',
    915931                        )
    916932                );
     
    9971013                        '/my-route',
    9981014                        array(
    999                                 'callback' => '__return_true',
     1015                                'callback'            => '__return_true',
     1016                                'permission_callback' => '__return_true',
    10001017                        )
    10011018                );
     
    10051022
    10061023                $this->assertTrue( rest_do_request( '/my-namespace/v1/my-route' )->get_data() );
     1024        }
     1025
     1026        /**
     1027         * @ticket 50075
     1028         */
     1029        public function test_register_route_with_missing_permission_callback_top_level_route() {
     1030                $this->setExpectedIncorrectUsage( 'register_rest_route' );
     1031
     1032                $registered = register_rest_route(
     1033                        'my-ns/v1',
     1034                        '/my-route',
     1035                        array(
     1036                                'callback' => '__return_true',
     1037                        )
     1038                );
     1039
     1040                $this->assertTrue( $registered );
     1041        }
     1042
     1043        /**
     1044         * @ticket 50075
     1045         */
     1046        public function test_register_route_with_missing_permission_callback_single_wrapped_route() {
     1047                $this->setExpectedIncorrectUsage( 'register_rest_route' );
     1048
     1049                $registered = register_rest_route(
     1050                        'my-ns/v1',
     1051                        '/my-route',
     1052                        array(
     1053                                array(
     1054                                        'callback' => '__return_true',
     1055                                ),
     1056                        )
     1057                );
     1058
     1059                $this->assertTrue( $registered );
     1060        }
     1061
     1062
     1063        /**
     1064         * @ticket 50075
     1065         */
     1066        public function test_register_route_with_missing_permission_callback_multiple_wrapped_route() {
     1067                $this->setExpectedIncorrectUsage( 'register_rest_route' );
     1068
     1069                $registered = register_rest_route(
     1070                        'my-ns/v1',
     1071                        '/my-route',
     1072                        array(
     1073                                array(
     1074                                        'callback' => '__return_true',
     1075                                ),
     1076                                array(
     1077                                        'callback'            => '__return_true',
     1078                                        'permission_callback' => '__return_true',
     1079                                ),
     1080                        )
     1081                );
     1082
     1083                $this->assertTrue( $registered );
    10071084        }
    10081085
Note: See TracChangeset for help on using the changeset viewer.