From 38361be8e641f59041c5177dab70bbb8e3d0f4f7 Mon Sep 17 00:00:00 2001 From: Timothy Jacobs Date: Fri, 4 Dec 2020 21:42:52 +0000 Subject: [PATCH] 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. Fixes #51939. git-svn-id: https://develop.svn.wordpress.org/trunk@49752 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/authorize-application.php | 12 +++++ src/wp-admin/includes/upgrade.php | 15 +++++- src/wp-admin/user-edit.php | 47 +++++++++++-------- .../class-wp-application-passwords.php | 26 ++++++++++ src/wp-includes/user.php | 4 ++ src/wp-includes/version.php | 2 +- tests/phpunit/tests/auth.php | 11 +++++ .../rest-application-passwords-controller.php | 16 +++++++ 8 files changed, 111 insertions(+), 22 deletions(-) diff --git a/src/wp-admin/authorize-application.php b/src/wp-admin/authorize-application.php index a6aac398fd..fa8d919747 100644 --- a/src/wp-admin/authorize-application.php +++ b/src/wp-admin/authorize-application.php @@ -88,6 +88,18 @@ if ( is_wp_error( $is_valid ) ) { ); } +if ( ! empty( $_SERVER['PHP_AUTH_USER'] ) || ! empty( $_SERVER['PHP_AUTH_PW'] ) ) { + wp_die( + __( 'Your website appears to use Basic Authentication, which is not currently compatible with Application Passwords.' ), + __( 'Cannot Authorize Application' ), + array( + 'response' => 501, + 'link_text' => __( 'Go Back' ), + 'link_url' => $reject_url ? add_query_arg( 'error', 'disabled', $reject_url ) : admin_url(), + ) + ); +} + if ( ! wp_is_application_passwords_available_for_user( $user ) ) { if ( wp_is_application_passwords_available() ) { $message = __( 'Application passwords are not available for your account. Please contact the site administrator for assistance.' ); diff --git a/src/wp-admin/includes/upgrade.php b/src/wp-admin/includes/upgrade.php index 72f3536578..513e00b734 100644 --- a/src/wp-admin/includes/upgrade.php +++ b/src/wp-admin/includes/upgrade.php @@ -874,7 +874,7 @@ function upgrade_all() { upgrade_550(); } - if ( $wp_current_db_version < 49735 ) { + if ( $wp_current_db_version < 49752 ) { upgrade_560(); } @@ -2278,6 +2278,19 @@ function upgrade_560() { if ( $wp_current_db_version < 49735 ) { delete_transient( 'dirsize_cache' ); } + + if ( $wp_current_db_version < 49752 ) { + $results = $wpdb->get_results( + $wpdb->prepare( + "SELECT 1 FROM {$wpdb->usermeta} WHERE meta_key = %s LIMIT 1", + WP_Application_Passwords::USERMETA_KEY_APPLICATION_PASSWORDS + ) + ); + + if ( ! empty( $results ) ) { + update_site_option( WP_Application_Passwords::OPTION_KEY_IN_USE, 1 ); + } + } } /** diff --git a/src/wp-admin/user-edit.php b/src/wp-admin/user-edit.php index 110eee5d7f..4177288547 100644 --- a/src/wp-admin/user-edit.php +++ b/src/wp-admin/user-edit.php @@ -738,27 +738,34 @@ endif; -
-
- - -

+ + if ( empty( $_SERVER['PHP_AUTH_USER'] ) && empty( $_SERVER['PHP_AUTH_PW'] ) ) { + ?> +
+
+ + +

+
+ + + +
- - - - -
+ +
+

+
+
user = clone self::$_user; wp_set_current_user( self::$user_id ); + update_site_option( 'using_application_passwords', 1 ); } public function tearDown() { @@ -604,4 +605,14 @@ class Tests_Auth extends WP_UnitTestCase { $this->assertInstanceOf( WP_User::class, $user ); $this->assertSame( self::$user_id, $user->ID ); } + + /** + * @ticket 51939 + */ + public function test_authenticate_application_password_returns_null_if_not_in_use() { + delete_site_option( 'using_application_passwords' ); + + $authenticated = wp_authenticate_application_password( null, 'idonotexist', 'password' ); + $this->assertNull( $authenticated ); + } } diff --git a/tests/phpunit/tests/rest-api/rest-application-passwords-controller.php b/tests/phpunit/tests/rest-api/rest-application-passwords-controller.php index fba1e41fd9..79218e307e 100644 --- a/tests/phpunit/tests/rest-api/rest-application-passwords-controller.php +++ b/tests/phpunit/tests/rest-api/rest-application-passwords-controller.php @@ -404,6 +404,22 @@ class WP_Test_REST_Application_Passwords_Controller extends WP_Test_REST_Control $this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 ); } + /** + * @ticket 51939 + */ + public function test_create_item_records_app_passwords_in_use() { + wp_set_current_user( self::$admin ); + + $this->assertFalse( WP_Application_Passwords::is_in_use() ); + + $request = new WP_REST_Request( 'POST', '/wp/v2/users/me/application-passwords' ); + $request->set_body_params( array( 'name' => 'App' ) ); + $response = rest_do_request( $request ); + + $this->assertSame( 201, $response->get_status() ); + $this->assertTrue( WP_Application_Passwords::is_in_use() ); + } + /** * @ticket 42790 */