From 5cd36791280c117245ba5ef5813eade81d455317 Mon Sep 17 00:00:00 2001 From: Hou Chi Chan Date: Thu, 22 Oct 2026 14:12:56 -0700 Subject: [PATCH] fix: accept single-tenant unrestricted audience Co-authored-by: GitHub Copilot --- setup/support/Epp.Setup.psm1 | 17 +++++++++++++---- setup/tests/ProviderConfiguration.Tests.ps1 | 13 ++++++++++++- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/setup/support/Epp.Setup.psm1 b/setup/support/Epp.Setup.psm1 index 95f3eb6..ce39599 100644 --- a/setup/support/Epp.Setup.psm1 +++ b/setup/support/Epp.Setup.psm1 @@ -224,7 +224,7 @@ function Resolve-EppApplicationProvider { } $application = Get-EppApplication -Inputs $Inputs -ClientId $Inputs.ApplicationId $restriction = Get-EppSignInAudienceRestrictions -Inputs $Inputs -ApplicationObjectId $application.Id - $state = Get-EppProviderRestrictionState -Restriction $restriction + $state = Get-EppProviderRestrictionState -Restriction $restriction -SignInAudience $application.SignInAudience $configured = @() if ($application.SignInAudience -eq 'AzureADMultipleOrgs' -and $state -and $state.isHomeTenantAllowed) { foreach ($entry in $entries) { @@ -968,9 +968,16 @@ function Get-EppSignInAudienceRestrictions { } function Get-EppProviderRestrictionState { - param($Restriction) + param($Restriction, [string] $SignInAudience) if ($null -eq $Restriction) { return $null } + # Graph can return unrestrictedAudience instead of null for a new single-tenant app. The + # app's sign-in audience still prevents external tenants, so this is equivalent to having no + # provider allowlist yet. Never normalize the same shape for a multitenant application. + if ($Restriction -is [Collections.IDictionary] -and $Restriction['kind'] -ceq 'unrestricted' -and + $SignInAudience -ceq 'AzureADMyOrg') { + return $null + } if ($Restriction -isnot [Collections.IDictionary] -or $Restriction['kind'] -cne 'allowedTenants' -or $Restriction['isHomeTenantAllowed'] -isnot [bool] -or $Restriction['allowedTenantIds'] -isnot [Array]) { throw 'The application has an unsupported provider-tenant restriction. Review it before running setup.' @@ -1288,7 +1295,8 @@ function Connect-EppContext { $tenantRestriction = if (-not $pendingApplication) { Get-EppSignInAudienceRestrictions -Inputs $Inputs -ApplicationObjectId $application.Id } else { $null } - $providerRestrictionState = Get-EppProviderRestrictionState -Restriction $tenantRestriction + $providerRestrictionState = Get-EppProviderRestrictionState -Restriction $tenantRestriction ` + -SignInAudience $application.SignInAudience $allowedTenants = @(if ($providerRestrictionState) { $providerRestrictionState.allowedTenantIds }) $Inputs.ProviderAllowedTenantIds = @(($allowedTenants + @($Inputs.ProviderTenantId)) | Sort-Object -Unique) $version = if ($application.Api -and $application.Api.RequestedAccessTokenVersion) { [int]$application.Api.RequestedAccessTokenVersion } else { 1 } @@ -1618,7 +1626,8 @@ function Initialize-EppGraphAccess { } Assert-EppCertificatePlanUnchanged -Application $application -Plan $Context.CertificatePlan $restriction = Get-EppSignInAudienceRestrictions -Inputs $Inputs -ApplicationObjectId $application.Id - $currentProviderState = Get-EppProviderRestrictionState -Restriction $restriction + $currentProviderState = Get-EppProviderRestrictionState -Restriction $restriction ` + -SignInAudience $application.SignInAudience if (-not (Test-EppJsonEqual $currentProviderState $Context.ProviderRestrictionState)) { throw 'The application provider configuration changed after the plan was reviewed. Rerun setup; no provider tenants will be removed.' } diff --git a/setup/tests/ProviderConfiguration.Tests.ps1 b/setup/tests/ProviderConfiguration.Tests.ps1 index 16d11b2..3a198f4 100644 --- a/setup/tests/ProviderConfiguration.Tests.ps1 +++ b/setup/tests/ProviderConfiguration.Tests.ps1 @@ -139,6 +139,9 @@ try { Assert (Test-EppProviderTenantRestriction -Restriction $both -ProviderTenantId $telesign.TenantId) 'A configured provider can coexist with other allowed providers.' Assert (Test-EppProviderTenantRestriction -Restriction $both -ProviderTenantId $telesign.TenantId -ExpectedAllowedTenantIds @($telesign.TenantId, $soprano.TenantId)) 'Compare allowed tenants independently of ordering.' Assert (-not (Test-EppProviderTenantRestriction -Restriction $both -ProviderTenantId $telesign.TenantId -ExpectedAllowedTenantIds @($telesign.TenantId))) 'Readback must match the complete approved allowlist.' + $unrestricted = @{ '@odata.type' = '#microsoft.graph.unrestrictedAudience'; kind = 'unrestricted'; allowedTenantIds = @($script:Tenant) } + Assert ($null -eq (Get-EppProviderRestrictionState -Restriction $unrestricted -SignInAudience 'AzureADMyOrg')) 'Treat Graph unrestrictedAudience as an empty provider configuration only while the app is single tenant.' + Assert-Throws { Get-EppProviderRestrictionState -Restriction $unrestricted -SignInAudience 'AzureADMultipleOrgs' } 'unsupported provider-tenant restriction' Assert-Throws { Get-EppProviderRestrictionState (New-TestRestriction @($telesign.TenantId, $telesign.TenantId)) } 'duplicate allowed' Assert-Throws { Get-EppProviderRestrictionState @{ kind = 'unexpected'; isHomeTenantAllowed = $true; allowedTenantIds = @() } } 'unsupported provider-tenant restriction' Assert-Throws { Get-EppProviderRestrictionState (New-TestRestriction @('invalid')) } 'nonempty GUID' @@ -174,6 +177,11 @@ try { $expected = @((@($existing) + @($telesign.TenantId)) | Sort-Object -Unique) Assert (($inputs.ProviderAllowedTenantIds -join ',') -ceq ($expected -join ',')) 'Preflight must preserve existing known and unknown allowed tenants while adding the selected provider.' } + Reset-TestState + $script:Restriction = $unrestricted + $inputs = New-TestInputs + Assert-Throws { Connect-EppContext -Inputs $inputs -Names @{ resourceGroup = 'unit' } -NonInteractive } '^provider-preflight-boundary$' + Assert (($inputs.ProviderAllowedTenantIds -join ',') -ceq $telesign.TenantId) 'Single-tenant unrestrictedAudience must enter preflight as an empty provider configuration.' foreach ($alreadyConfigured in @($false, $true)) { Reset-TestState $script:Application.SignInAudience = 'AzureADMultipleOrgs' @@ -210,7 +218,10 @@ try { Reset-TestState $inputs = New-TestInputs $inputs.ProviderAllowedTenantIds = @($telesign.TenantId) - if ($case.New) { $inputs.NewApplicationDisplayName = 'New EPP application' } + if ($case.New) { + $inputs.NewApplicationDisplayName = 'New EPP application' + $script:Restriction = $unrestricted + } for ($index = 0; $index -lt $case.Failures; $index++) { $script:ApplicationReadErrors.Enqueue($case.Error) } $context = @{ Application = @{ Id = $script:ObjectId; SignInAudience = $script:Application.SignInAudience }