WordPress.org

Make WordPress Core

Changeset 49754


Ignore:
Timestamp:
12/04/2020 09:46:42 PM (6 weeks ago)
Author:
helen
Message:

App Passwords: Prevent conflicts when Basic Auth is already used by the site.

Application Passwords uses Basic Authentication to transfer authentication details. If the site is already using Basic Auth, for instance to implement a private staging environment, then the REST API will treat this as an authentication attempt and would end up generating an error for any REST API request.

Now, Application Password authentication will only be attempted if Application Passwords is in use by a site. This is flagged by setting an option whenever an Application Password is created. An upgrade routine is added to set this option if any App Passwords already exist.

Lastly, creating an Application Password will be prevented if the site appears to already be using Basic Authentication.

Props chexwarrior, georgestephanis, adamsilverstein, helen, Clorith, marybaum, TimothyBlynJacobs.
Reviewed by TimothyBlynJacobs, helen.
Merges [49752] to the 5.6 branch.
Fixes #51939.

Location:
branches/5.6
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • branches/5.6

  • branches/5.6/src/wp-admin/authorize-application.php

    r49617 r49754  
    8686        __( 'The Authorize Application request is not allowed.' ) . ' ' . implode( ' ', $is_valid->get_error_messages() ),
    8787        __( 'Cannot Authorize Application' )
     88    );
     89}
     90
     91if ( ! empty( $_SERVER['PHP_AUTH_USER'] ) || ! empty( $_SERVER['PHP_AUTH_PW'] ) ) {
     92    wp_die(
     93        __( 'Your website appears to use Basic Authentication, which is not currently compatible with Application Passwords.' ),
     94        __( 'Cannot Authorize Application' ),
     95        array(
     96            'response'  => 501,
     97            'link_text' => __( 'Go Back' ),
     98            'link_url'  => $reject_url ? add_query_arg( 'error', 'disabled', $reject_url ) : admin_url(),
     99        )
    88100    );
    89101}
  • branches/5.6/src/wp-admin/includes/upgrade.php

    r49745 r49754  
    875875    }
    876876
    877     if ( $wp_current_db_version < 49735 ) {
     877    if ( $wp_current_db_version < 49752 ) {
    878878        upgrade_560();
    879879    }
     
    22792279        delete_transient( 'dirsize_cache' );
    22802280    }
     2281
     2282    if ( $wp_current_db_version < 49752 ) {
     2283        $results = $wpdb->get_results(
     2284            $wpdb->prepare(
     2285                "SELECT 1 FROM {$wpdb->usermeta} WHERE meta_key = %s LIMIT 1",
     2286                WP_Application_Passwords::USERMETA_KEY_APPLICATION_PASSWORDS
     2287            )
     2288        );
     2289
     2290        if ( ! empty( $results ) ) {
     2291            update_site_option( WP_Application_Passwords::OPTION_KEY_IN_USE, 1 );
     2292        }
     2293    }
    22812294}
    22822295
  • branches/5.6/src/wp-admin/user-edit.php

    r49573 r49754  
    739739                }
    740740            }
    741             ?>
    742         <div class="create-application-password form-wrap">
    743             <div class="form-field">
    744                 <label for="new_application_password_name"><?php _e( 'New Application Password Name' ); ?></label>
    745                 <input type="text" size="30" id="new_application_password_name" name="new_application_password_name" placeholder="<?php esc_attr_e( 'WordPress App on My Phone' ); ?>" class="input" aria-required="true" aria-describedby="new_application_password_name_desc" />
    746                 <p class="description" id="new_application_password_name_desc"><?php _e( 'Required to create an Application Password, but not to update the user.' ); ?></p>
     741
     742            if ( empty( $_SERVER['PHP_AUTH_USER'] ) && empty( $_SERVER['PHP_AUTH_PW'] ) ) {
     743                ?>
     744            <div class="create-application-password form-wrap">
     745                <div class="form-field">
     746                    <label for="new_application_password_name"><?php _e( 'New Application Password Name' ); ?></label>
     747                    <input type="text" size="30" id="new_application_password_name" name="new_application_password_name" placeholder="<?php esc_attr_e( 'WordPress App on My Phone' ); ?>" class="input" aria-required="true" aria-describedby="new_application_password_name_desc" />
     748                    <p class="description" id="new_application_password_name_desc"><?php _e( 'Required to create an Application Password, but not to update the user.' ); ?></p>
     749                </div>
     750
     751                <?php
     752                /**
     753                 * Fires in the create Application Passwords form.
     754                 *
     755                 * @since 5.6.0
     756                 *
     757                 * @param WP_User $profileuser The current WP_User object.
     758                 */
     759                do_action( 'wp_create_application_password_form', $profileuser );
     760                ?>
     761
     762                <?php submit_button( __( 'Add New Application Password' ), 'secondary', 'do_new_application_password' ); ?>
    747763            </div>
    748 
    749             <?php
    750             /**
    751              * Fires in the create Application Passwords form.
    752              *
    753              * @since 5.6.0
    754              *
    755              * @param WP_User $profileuser The current WP_User object.
    756              */
    757             do_action( 'wp_create_application_password_form', $profileuser );
    758             ?>
    759 
    760             <?php submit_button( __( 'Add New Application Password' ), 'secondary', 'do_new_application_password' ); ?>
    761         </div>
     764        <?php } else { ?>
     765            <div class="notice notice-error inline">
     766                <p><?php _e( 'Your website appears to use Basic Authentication, which is not currently compatible with Application Passwords.' ); ?></p>
     767            </div>
     768        <?php } ?>
    762769
    763770        <div class="application-passwords-list-table-wrapper">
  • branches/5.6/src/wp-includes/class-wp-application-passwords.php

    r49740 r49754  
    2424
    2525    /**
     26     * The option name used to store whether application passwords is in use.
     27     *
     28     * @since 5.6.0
     29     *
     30     * @type string
     31     */
     32    const OPTION_KEY_IN_USE = 'using_application_passwords';
     33
     34    /**
    2635     * The generated application password length.
    2736     *
     
    3140     */
    3241    const PW_LENGTH = 24;
     42
     43    /**
     44     * Checks if Application Passwords are being used by the site.
     45     *
     46     * This returns true if at least one App Password has ever been created.
     47     *
     48     * @since 5.6.0
     49     *
     50     * @return bool
     51     */
     52    public static function is_in_use() {
     53        return (bool) get_site_option( self::OPTION_KEY_IN_USE );
     54    }
    3355
    3456    /**
     
    6688        if ( ! $saved ) {
    6789            return new WP_Error( 'db_error', __( 'Could not save application password.' ) );
     90        }
     91
     92        if ( ! get_site_option( self::OPTION_KEY_IN_USE ) ) {
     93            update_site_option( self::OPTION_KEY_IN_USE, true );
    6894        }
    6995
  • branches/5.6/src/wp-includes/user.php

    r49627 r49754  
    311311function wp_authenticate_application_password( $input_user, $username, $password ) {
    312312    if ( $input_user instanceof WP_User ) {
     313        return $input_user;
     314    }
     315
     316    if ( ! WP_Application_Passwords::is_in_use() ) {
    313317        return $input_user;
    314318    }
  • branches/5.6/src/wp-includes/version.php

    r49749 r49754  
    2121 * @global int $wp_db_version
    2222 */
    23 $wp_db_version = 49735;
     23$wp_db_version = 49752;
    2424
    2525/**
  • branches/5.6/tests/phpunit/tests/auth.php

    r49617 r49754  
    3838        $this->user = clone self::$_user;
    3939        wp_set_current_user( self::$user_id );
     40        update_site_option( 'using_application_passwords', 1 );
    4041    }
    4142
     
    605606        $this->assertSame( self::$user_id, $user->ID );
    606607    }
     608
     609    /**
     610     * @ticket 51939
     611     */
     612    public function test_authenticate_application_password_returns_null_if_not_in_use() {
     613        delete_site_option( 'using_application_passwords' );
     614
     615        $authenticated = wp_authenticate_application_password( null, 'idonotexist', 'password' );
     616        $this->assertNull( $authenticated );
     617    }
    607618}
  • branches/5.6/tests/phpunit/tests/rest-api/rest-application-passwords-controller.php

    r49617 r49754  
    406406
    407407    /**
     408     * @ticket 51939
     409     */
     410    public function test_create_item_records_app_passwords_in_use() {
     411        wp_set_current_user( self::$admin );
     412
     413        $this->assertFalse( WP_Application_Passwords::is_in_use() );
     414
     415        $request = new WP_REST_Request( 'POST', '/wp/v2/users/me/application-passwords' );
     416        $request->set_body_params( array( 'name' => 'App' ) );
     417        $response = rest_do_request( $request );
     418
     419        $this->assertSame( 201, $response->get_status() );
     420        $this->assertTrue( WP_Application_Passwords::is_in_use() );
     421    }
     422
     423    /**
    408424     * @ticket 42790
    409425     */
Note: See TracChangeset for help on using the changeset viewer.