Match accounts by mail address and user principal name
Some checks are pending
CI / PHP lint (7.4) (pull_request) Waiting to run
CI / PHP lint (8.0) (pull_request) Waiting to run
CI / PHP lint (8.1) (pull_request) Waiting to run
CI / PHP lint (8.2) (pull_request) Waiting to run
CI / PHP lint (8.3) (pull_request) Waiting to run
CI / PHP lint (8.4) (pull_request) Waiting to run
CI / WordPress Coding Standards (pull_request) Waiting to run
CI / WordPress.org Plugin Check (pull_request) Waiting to run
Some checks are pending
CI / PHP lint (7.4) (pull_request) Waiting to run
CI / PHP lint (8.0) (pull_request) Waiting to run
CI / PHP lint (8.1) (pull_request) Waiting to run
CI / PHP lint (8.2) (pull_request) Waiting to run
CI / PHP lint (8.3) (pull_request) Waiting to run
CI / PHP lint (8.4) (pull_request) Waiting to run
CI / WordPress Coding Standards (pull_request) Waiting to run
CI / WordPress.org Plugin Check (pull_request) Waiting to run
Sign-in and sync only used the first address (the mail attribute). A
WordPress account that carries the user principal name while the
Microsoft mail differs was not found at sign-in ("no WordPress account")
and the sync created a duplicate account for it.
Both now try the mail address and then the user principal name (UPN
only for members, only with the UPN fallback on, and only within the
e-mail domain allow-list). Privileged accounts keep the stricter rule;
a matching UPN is sufficient there as well.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
81b3a74ae5
commit
cc88f145f2
4 changed files with 34 additions and 14 deletions
|
|
@ -533,22 +533,30 @@ class M365_Login_Auth {
|
|||
$this->link_account( (int) $attempt['link_user'], $claims, $oid );
|
||||
}
|
||||
|
||||
$email = $this->email_from_claims( $claims );
|
||||
if ( '' !== $email && ! $this->domain_allowed( $email ) ) {
|
||||
// E-mail and user principal name may differ: every usable address is tried (on the domain allow-list).
|
||||
$candidates = $this->email_candidates( $claims );
|
||||
$email = $candidates ? $candidates[0] : '';
|
||||
$allowed = array_values( array_filter( $candidates, array( $this, 'domain_allowed' ) ) );
|
||||
if ( $candidates && ! $allowed ) {
|
||||
$this->fail( 'domain_not_allowed' );
|
||||
}
|
||||
|
||||
// 1. An account already bound to this Microsoft identity, 2. an account the administrator
|
||||
// assigned this user principal name to, 3. the e-mail address.
|
||||
// assigned this user principal name to, 3. the e-mail address, then the user principal name.
|
||||
$user = $this->find_bound_user( $oid );
|
||||
if ( ! $user ) {
|
||||
$user = $this->find_assigned_user( $claims );
|
||||
}
|
||||
if ( ! $user ) {
|
||||
if ( '' === $email ) {
|
||||
if ( ! $allowed ) {
|
||||
$this->fail( 'no_email' );
|
||||
}
|
||||
$user = get_user_by( 'email', $email );
|
||||
foreach ( $allowed as $candidate ) {
|
||||
$user = get_user_by( 'email', $candidate );
|
||||
if ( $user instanceof WP_User ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( ! $user instanceof WP_User ) {
|
||||
/** This action is documented in wp-includes/user.php */
|
||||
|
|
@ -1072,12 +1080,12 @@ class M365_Login_Auth {
|
|||
}
|
||||
|
||||
/**
|
||||
* Extracts the e-mail address used for matching.
|
||||
* Addresses used for matching, in order (e-mail claim, then user principal name).
|
||||
*
|
||||
* @param array $claims Verified claims.
|
||||
* @return string Lowercase e-mail or empty string.
|
||||
* @return string[] Lowercase addresses.
|
||||
*/
|
||||
private function email_from_claims( $claims ) {
|
||||
private function email_candidates( $claims ) {
|
||||
$candidates = array();
|
||||
$email = ! empty( $claims['email'] ) && is_string( $claims['email'] ) ? $claims['email'] : '';
|
||||
$upn = ! empty( $claims['preferred_username'] ) && is_string( $claims['preferred_username'] ) ? $claims['preferred_username'] : '';
|
||||
|
|
@ -1101,19 +1109,23 @@ class M365_Login_Auth {
|
|||
}
|
||||
}
|
||||
|
||||
$out = array();
|
||||
foreach ( $candidates as $candidate ) {
|
||||
$candidate = strtolower( trim( $candidate ) );
|
||||
if ( is_email( $candidate ) ) {
|
||||
/**
|
||||
* Filters the e-mail address used to look up the WordPress user.
|
||||
* Filters an e-mail address used to look up the WordPress user.
|
||||
*
|
||||
* @param string $email E-mail from the token.
|
||||
* @param array $claims Verified claims.
|
||||
*/
|
||||
return (string) apply_filters( 'm365_login_match_email', $candidate, $claims );
|
||||
$candidate = strtolower( (string) apply_filters( 'm365_login_match_email', $candidate, $claims ) );
|
||||
if ( is_email( $candidate ) && ! in_array( $candidate, $out, true ) ) {
|
||||
$out[] = $candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
return '';
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue