Close button-only bypass via XML-RPC system.multicall
The credential-based exemption used did_action( 'application_password_did_authenticate'), which is request-global. In a system.multicall, a first boxcar authenticated with any application password let later boxcars sign in other users with a normal password. The exemption now applies only to the user the application password authenticated in the same authenticate pass (reset at priority 0). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
850f0dcd54
commit
b35f6a867b
1 changed files with 33 additions and 1 deletions
|
|
@ -37,6 +37,13 @@ class M365_Login_Auth {
|
||||||
*/
|
*/
|
||||||
private $graph;
|
private $graph;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User authenticated by an application password in the current authenticate pass (0 = none).
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $app_password_user = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
|
|
@ -55,6 +62,9 @@ class M365_Login_Auth {
|
||||||
add_action( 'init', array( $this, 'maybe_accept_fallback_key' ), 6 );
|
add_action( 'init', array( $this, 'maybe_accept_fallback_key' ), 6 );
|
||||||
// Runs after core's username/password handlers (priority 20), which would otherwise overwrite an early WP_Error.
|
// Runs after core's username/password handlers (priority 20), which would otherwise overwrite an early WP_Error.
|
||||||
add_filter( 'authenticate', array( $this, 'block_password_login' ), 99, 3 );
|
add_filter( 'authenticate', array( $this, 'block_password_login' ), 99, 3 );
|
||||||
|
// Track application-password sign-ins per authenticate pass (XML-RPC multicall runs several passes per request).
|
||||||
|
add_filter( 'authenticate', array( $this, 'reset_app_password_user' ), 0 );
|
||||||
|
add_action( 'application_password_did_authenticate', array( $this, 'remember_app_password_user' ) );
|
||||||
// No session cookies from API contexts (XML-RPC, REST) while password sign-in is disabled.
|
// No session cookies from API contexts (XML-RPC, REST) while password sign-in is disabled.
|
||||||
add_filter( 'send_auth_cookies', array( $this, 'block_api_auth_cookies' ), 99, 4 );
|
add_filter( 'send_auth_cookies', array( $this, 'block_api_auth_cookies' ), 99, 4 );
|
||||||
|
|
||||||
|
|
@ -164,7 +174,9 @@ class M365_Login_Auth {
|
||||||
// Exempt by credential, not by request context: application passwords (XML-RPC, REST) and
|
// Exempt by credential, not by request context: application passwords (XML-RPC, REST) and
|
||||||
// WP-CLI keep working. A normal password is refused everywhere – also in forms of other
|
// WP-CLI keep working. A normal password is refused everywhere – also in forms of other
|
||||||
// plugins that happen to run inside xmlrpc.php or a REST request.
|
// plugins that happen to run inside xmlrpc.php or a REST request.
|
||||||
if ( ( defined( 'WP_CLI' ) && WP_CLI ) || ( $user instanceof WP_User && did_action( 'application_password_did_authenticate' ) ) ) {
|
// The application password must have authenticated exactly this user in this pass – did_action()
|
||||||
|
// is request-global and would let a later multicall boxcar through with a normal password.
|
||||||
|
if ( ( defined( 'WP_CLI' ) && WP_CLI ) || ( $user instanceof WP_User && $this->app_password_user && $this->app_password_user === $user->ID ) ) {
|
||||||
return $user;
|
return $user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -182,6 +194,26 @@ class M365_Login_Auth {
|
||||||
return new WP_Error( 'm365_login_button_only', __( 'Password sign-in is disabled on this site. Please use the Microsoft button.', 'm365-login' ) );
|
return new WP_Error( 'm365_login_button_only', __( 'Password sign-in is disabled on this site. Please use the Microsoft button.', 'm365-login' ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a new authenticate pass (runs first on the authenticate filter).
|
||||||
|
*
|
||||||
|
* @param null|WP_User|WP_Error $user Result so far (unchanged).
|
||||||
|
* @return null|WP_User|WP_Error
|
||||||
|
*/
|
||||||
|
public function reset_app_password_user( $user ) {
|
||||||
|
$this->app_password_user = 0;
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remembers which user an application password authenticated in the current pass.
|
||||||
|
*
|
||||||
|
* @param WP_User $user Authenticated user.
|
||||||
|
*/
|
||||||
|
public function remember_app_password_user( $user ) {
|
||||||
|
$this->app_password_user = $user instanceof WP_User ? (int) $user->ID : 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* While button-only mode is active, API requests (XML-RPC, REST) never receive session cookies.
|
* While button-only mode is active, API requests (XML-RPC, REST) never receive session cookies.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue