Repository navigation
ENG-5386: Basic Auth Plugin Blocks WP Admin Button Login #10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
loukie-pressable
merged 13 commits into
main
from
johnluke/eng-5386-basic-auth-plugin-blocks-wp-admin-button-login
Oct 8, 2026
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
c6186d9
ENG-5386: Test that a valid OnePress one-click token gets past Basic …
loukieluke 8de497c
ENG-5386: Let a valid OnePress one-click login through Basic Auth
loukieluke d8af4f2
ENG-5386: Test the one-click waiver's input bounds and OnePress readi…
loukieluke 8cb2edb
ENG-5386: Bound the one-click token and mirror OnePress's readiness g…
loukieluke 718a071
ENG-5386: Test that the waiver stands down whenever OnePress does
loukieluke 290c601
ENG-5386: Mirror OnePress's readiness guard in full
loukieluke 5bb08fb
ENG-5386: Document the one-click waiver and the test file's real scope
loukieluke 19fa769
ENG-5386: Complete the README exception list and correct the test fil…
loukieluke f5e4858
ENG-5386: Use a neutral site id in the test tokens
loukieluke d731272
ENG-5386: Test that the waiver needs OnePress to see the same token
loukieluke ac519a7
ENG-5386: Waive only when OnePress will see the same token; correct o…
loukieluke 3955e10
ENG-5386: Test the OnePress waiver through real plugins_loaded dispatch
loukieluke 8d286f5
ENG-5386: Correct how the $_REQUEST paragraph describes a body override
loukieluke File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| <?php | ||
| /** | ||
| * Router for tests/onepress-dispatch-test.php, served by PHP's built-in web server. | ||
| * | ||
| * Loads the plugin, stands in for the few WordPress functions its request path calls | ||
| * and for the OnePress Login plugin, then fires `plugins_loaded` the way WordPress | ||
| * does. The response says which happened: Basic Auth challenged (401), or the | ||
| * request reached OnePress's handler. | ||
| * | ||
| * It runs under the cli-server SAPI on purpose: the plugin waives every CLI request, | ||
| * so only a non-CLI request exercises the real dispatch. | ||
| * | ||
| * @package HostingBasicAuthentication | ||
| */ | ||
|
|
||
| // Only ever a fixture for the dispatch test, never something a site should serve. | ||
| // `/tests export-ignore` keeps it out of the release zip; this is the second layer. | ||
| if ( 'cli-server' !== php_sapi_name() ) { | ||
| exit( 1 ); | ||
| } | ||
|
|
||
| define( 'ABSPATH', __DIR__ ); | ||
|
|
||
| // Mirrors the values tests/onepress-dispatch-test.php mints its token from. | ||
| const DISPATCH_SECRET = '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08'; | ||
| const DISPATCH_USER_ID = 7; | ||
|
|
||
| $GLOBALS['wp_filter'] = array(); | ||
| $GLOBALS['pagenow'] = basename( strtok( $_SERVER['REQUEST_URI'] ?? '/', '?' ) ); | ||
|
|
||
| function add_action( $hook, $callback, $priority = 10, $accepted_args = 1 ) { | ||
| $GLOBALS['wp_filter'][ $hook ][ $priority ][] = $callback; | ||
| } | ||
|
|
||
| function add_filter( $hook, $callback, $priority = 10, $accepted_args = 1 ) { | ||
| add_action( $hook, $callback, $priority, $accepted_args ); | ||
| } | ||
|
|
||
| function do_action( $hook ) { | ||
| $by_priority = $GLOBALS['wp_filter'][ $hook ] ?? array(); | ||
| ksort( $by_priority ); | ||
|
|
||
| foreach ( $by_priority as $callbacks ) { | ||
| foreach ( $callbacks as $callback ) { | ||
| call_user_func( $callback ); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| function is_multisite() { | ||
| return false; | ||
| } | ||
|
|
||
| function is_super_admin() { | ||
| return false; | ||
| } | ||
|
|
||
| function is_user_logged_in() { | ||
| return false; | ||
| } | ||
|
|
||
| function wp_installing() { | ||
| return false; | ||
| } | ||
|
|
||
| function wp_doing_ajax() { | ||
| return false; | ||
| } | ||
|
|
||
| function wp_doing_cron() { | ||
| return false; | ||
| } | ||
|
|
||
| function esc_html__( $text, $domain = 'default' ) { | ||
| return htmlspecialchars( $text, ENT_QUOTES ); | ||
| } | ||
|
|
||
| function get_user_meta( $user_id, $key = '', $single = false ) { | ||
| if ( DISPATCH_USER_ID !== $user_id || 'mpcp_auth_token' !== $key ) { | ||
| return ''; | ||
| } | ||
|
|
||
| return array( 'value' => md5( DISPATCH_SECRET ), 'exp' => time() + 30 ); | ||
| } | ||
|
|
||
| /** | ||
| * Stand-in for Pressable OnePress Login: registers on the same hook and priority, under | ||
| * the same condition, and reports that it was reached instead of logging anyone in. | ||
| */ | ||
| final class Pressable_OnePress_Login_Plugin { | ||
| public function __construct() { | ||
| if ( 'wp-login.php' === $GLOBALS['pagenow'] && isset( $_REQUEST['mpcp_token'] ) ) { | ||
| add_action( 'plugins_loaded', array( $this, 'handle_server_login_request' ) ); | ||
| } | ||
| } | ||
|
|
||
| public function handle_server_login_request() { | ||
| echo 'ONEPRESS-HANDLED'; | ||
| exit; | ||
| } | ||
| } | ||
|
|
||
| require __DIR__ . '/../../pressable-basic-authentication.php'; | ||
| new Pressable_OnePress_Login_Plugin(); | ||
|
|
||
| do_action( 'plugins_loaded' ); | ||
|
|
||
| echo 'NOT-CHALLENGED-NOR-HANDLED'; |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The waiver validates
$_GET['mpcp_token'], but OnePress decides whether to handle the request from$_REQUEST(non-blocking). Inpressable-onepress-login,is_ready_to_handle_mpcp_login_request()registers the handler only whenisset( $_REQUEST['mpcp_token'] )(class-pressable-onepress-login-plugin.php:172), andhandle_server_login_request()reads$_REQUEST['mpcp_token'](line 25). Atplugins_loaded,$_REQUESTis still PHP's own, built fromrequest_order. WordPress only rebuilds it as$_GET + $_POSTinwp_magic_quotes(), afterplugins_loaded.request_order = "GP"I see no hole. A valid query token puts the value in$_REQUEST, so OnePress registers. Every one of its branches, success and all four failures, ends inwp_safe_redirect+exit, so nothing else onwp-login.phpruns. A POSTmpcp_tokenoverriding the query one only makes OnePress validate the wrong value and burn the sender's own token.request_orderthat leaves out G, OnePress never registers. A request likePOST /wp-login.php?mpcp_token=<valid>withaction=lostpasswordthen passes the waiver and runs WordPress's normal login actions with no Basic Auth challenge. It still needs a valid, unexpired token and a matching UA, so this is not a bypass for an outsider. But it breaks the property the docblock above states: "nothing else reaches wp-login.php unchallenged."A cheap way to make the two agree whatever the PHP config:
The test stubs OnePress with an empty class and never sets
$_REQUEST, so a case with$_GETset and$_REQUESTunset (or different) would pin it. Is this worth adding, or do you know WP Cloud pinsrequest_orderto GP? If so, reply with that and I'll take it as answered.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed — added your guard. I don't know what
request_orderWP Cloud's PHP uses, so I didn't want to depend on it.d731272: tests first, one with the token absent from$_REQUESTand one with a different$_REQUESTtoken. Both failed against the previous head.ac519a7:pressable-basic-authentication.php:335now returns false unless($_REQUEST['mpcp_token'] ?? null) === $encoded. The docblock explains why: OnePress registers on and reads$_REQUEST, which atplugins_loadedis still PHP's own, built fromrequest_order.Both suites are green on PHP 8.1 and 8.4. Deleting the new check fails both new cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Verified at
3955e10: line 335 rejects unless$_REQUESTholds the same string as the validated query token. Because theis_stringcheck on line 331 runs first, a missing, array-valued or different$_REQUESTvalue can no longer get the waiver, whateverrequest_orderis. Both new cases pin it. Resolved.