Add excluded Entra groups for the Microsoft sign-in
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

New "Excluded Entra groups" card on the Security tab. Members of these
groups (nested memberships count) can never sign in with Microsoft, even
if they are in an allowed group.

A hit in the ID token's groups claim refuses immediately. Otherwise the
plugin always asks Microsoft Graph (checkMemberGroups), because a groups
claim can be filtered in the app registration and cannot prove
non-membership. Graph errors refuse the sign-in (fail closed).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Friederich Loheide 2026-09-23 16:43:10 +00:00
parent 5c9b19399a
commit 791f43a80b
12 changed files with 372 additions and 196 deletions

View file

@ -46,6 +46,7 @@ class M365_Login_Settings {
'bind_oid' => 1,
'allowed_domains' => '',
'allowed_groups' => array(), // id => display name.
'denied_groups' => array(), // id => display name; members may never sign in.
'remember_me' => 0,
// Button-only mode.
'button_only' => 0,
@ -333,6 +334,15 @@ class M365_Login_Settings {
return self::guid_map( $this->get( 'allowed_groups', array() ) );
}
/**
* Excluded Entra group IDs (lowercase GUIDs) mapped to display names.
*
* @return array
*/
public function denied_groups() {
return self::guid_map( $this->get( 'denied_groups', array() ) );
}
/**
* Groups that limit the user sync (lowercase GUID => name); empty = whole tenant.
*
@ -552,6 +562,7 @@ class M365_Login_Settings {
// Allowed groups: GUID => name.
$out['allowed_groups'] = self::sanitize_group_list( isset( $input['allowed_groups'] ) ? $input['allowed_groups'] : array() );
$out['denied_groups'] = self::sanitize_group_list( isset( $input['denied_groups'] ) ? $input['denied_groups'] : array() );
// Button-only mode + fallback key.
$out['button_only'] = empty( $input['button_only'] ) ? 0 : 1;