Skip to content

Fix internal admin losing SUPER during customized plan provisioning#9717

Open
darjoo wants to merge 1 commit into
mainfrom
darjoo-fix-admin-super-retention
Open

Fix internal admin losing SUPER during customized plan provisioning#9717
darjoo wants to merge 1 commit into
mainfrom
darjoo-fix-admin-super-retention

Conversation

@darjoo

@darjoo darjoo commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

What & why

Internal tenant administrators (Global Admin / Dynamics 365 Admin) lost their SUPER permission set when they were provisioned for the first time and their license plan configuration was customized without explicitly including SUPER. This could lock the first admin out of an environment right after customizing a plan.

The root cause is in codeunit 9018 "Azure AD Plan Impl.", procedure AddNewlyAssignedUserPlans. The internal-admin exemption was only applied on the default (non-customized) plan branch:

if IsPlanConfigurationCustomized then
    ShouldRemoveSuper := not PlanConfigurationContainsSuper   // admin check bypassed
else
    ShouldRemoveSuper := not IsUserAdmin(UserSecurityID);

When any assigned plan was customized and omitted SUPER, the admin check was skipped entirely and SUPER was removed.

The fix adds a local IsUserInternalAdmin helper (Global Admin, D365 Admin, and BC Admin plans only) and guards the customized branch with it:

ShouldRemoveSuper := (not PlanConfigurationContainsSuper) and (not IsUserInternalAdmin(UserSecurityID))

Key decisions:

  • Delegated (partner) admins are intentionally not exempted here. Their SUPER is governed separately in AssignPlanToUserWithDelegatedRole, so IsUserInternalAdmin deliberately excludes the delegated/helpdesk plans (unlike the pre-existing IsUserAdmin, which includes delegated admin).
  • The default (non-customized) branch is untouched, so default-plan behavior is unchanged.
  • SUPER is still only ever revoked during first-login provisioning; existing users are unaffected.

Linked work

Fixes #

How I validated this

  • I read the full diff and it contains only changes I intended.
  • I built the affected app(s) locally with no new analyzer warnings.
  • I ran the change in Business Central and confirmed it behaves as expected.
  • I added or updated tests for the new behavior, or explained below why none are needed.

What I tested and the outcome

Added six tests to AzureADPlanModuleTest.codeunit.al (codeunit 139509) exercising RefreshUserPlanAssignments on a customized Premium plan:

  • Internal Global Admin + customized plan without SUPER -> retains SUPER.
  • Dynamics 365 Admin + customized plan without SUPER -> retains SUPER.
  • Ordinary (non-admin) user + customized plan without SUPER -> loses SUPER.
  • Any user + customized plan containing SUPER -> retains SUPER.
  • Delegated admin + customized plan without SUPER -> loses SUPER (explicitly not treated as internal admin).
  • Existing (already provisioned) user -> retains SUPER regardless of customization.

Default-plan behavior remains covered by the existing internal/D365/delegated admin tests.

Note: the affected apps were not built or run in Business Central from this automated environment (no container toolchain available here). Please build the System Application and the _Exclude_PlanConfiguration_ Tests app and run codeunits 132912 and 139509 locally before merging.

Risk & compatibility

  • Security-sensitive: this restores a privilege (SUPER) for internal admins that was being incorrectly removed. It does not grant SUPER to any user who should not have it: ordinary users still lose SUPER, and the "contains SUPER" and default-plan paths are unchanged.
  • No schema, data, or permission-set changes; no telemetry changes.
  • The defect has existed since the initial commit, so it affects all supported releases. Backports to the active releases/24.x through releases/28.x branches are recommended.

Internal tenant administrators (Global Admin / D365 Admin) lost SUPER when
provisioned for the first time with a customized license plan that omits SUPER.
In codeunit 9018 "Azure AD Plan Impl.", AddNewlyAssignedUserPlans only applied
the admin exemption on the default (non-customized) plan branch; the customized
branch set ShouldRemoveSuper solely from whether the configuration contained
SUPER, bypassing the admin check.

Add a local IsUserInternalAdmin helper (Global Admin, D365 Admin, BC Admin plans
only, excluding delegated partner roles) and guard the customized branch with it,
so internal admins keep SUPER even when the custom mapping omits it. Ordinary
users still lose SUPER, and delegated admins are intentionally not exempted here
since their SUPER is governed separately in AssignPlanToUserWithDelegatedRole.

Add tests covering internal admin retain, D365 admin retain, non-admin remove,
customized-with-SUPER retain, delegated admin remove, and the existing-user path.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@darjoo
darjoo requested a review from a team July 24, 2026 12:37
@github-actions github-actions Bot added AL: System Application AL: Apps (W1) Add-on apps for W1 Integration GitHub request for Integration area labels Jul 24, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Could not find a linked ADO work item. Please link one by using the pattern 'AB#' followed by the relevant work item number. You may use the 'Fixes' keyword to automatically resolve the work item when the pull request is merged. E.g. 'Fixes AB#1234'

local procedure IsUserInternalAdmin(SecurityID: Guid): Boolean
var
PlanIds: Codeunit "Plan Ids";
begin

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$\textbf{🟡\ Medium\ Severity\ —\ Testing}$

IsUserInternalAdmin() now has three admin-plan branches (Global Admin, D365 Admin, BC Admin), but the new regression tests only exercise the Global Admin and D365 Admin paths (TestInternalAdminKeepsSuperWhenCustomizedPlanOmitsSuper, TestD365AdminKeepsSuperWhenCustomizedPlanOmitsSuper). The BC Admin branch that gates the SUPER-retention behavior is untested. Add an equivalent test using PlanIds.GetBCAdminPlanId() to cover that branch.

Agent judgement — not directly backed by a BCQuality knowledge article.

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.15.4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AL: Apps (W1) Add-on apps for W1 AL: System Application Integration GitHub request for Integration area

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant