From 8e31c417c182110df327a36788bae1cc11c435c9 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Mon, 16 Dec 2024 09:31:11 -0500 Subject: [PATCH 1/4] Added support for Oauth2PermissionScopes --- CHANGELOG.md | 4 + .../MSFT_AADApplication.psm1 | 75 +++++++++++++++++-- .../MSFT_AADApplication.schema.mof | 16 ++++ .../MSFT_PPPowerAppPolicyUrlPatterns.psm1 | 9 +-- .../Dependencies/Manifest.psd1 | 2 +- 5 files changed, 91 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 986cbd1f48..69b06b3e33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,13 @@ # UNRELEASED +* AADApplication + * Added support for Oauth2PermissionScopes. * M365DSCUtil * Update `Get-M365DSCWorkloadsListFromResourceNames` function for more input types. FIXES [#5525](https://github.com/microsoft/Microsoft365DSC/issues/5525) +* DEPENDENCIES + * Updated Microsoft.PowerApps.Administration.PowerShell to version 2.0.202. # 1.24.1211.1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADApplication/MSFT_AADApplication.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADApplication/MSFT_AADApplication.psm1 index 069acb9eb3..3e306012f0 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADApplication/MSFT_AADApplication.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADApplication/MSFT_AADApplication.psm1 @@ -275,7 +275,24 @@ function Get-TargetResource $complexPreAuthorizedApplications += $myPreAuthorizedApplications } } + + $complexOAuth2Scopes = @() + foreach ($currentOAuth2Scope in $AADApp.api.Oauth2PermissionScopes) + { + $complexOAuth2Scopes += @{ + adminConsentDescription = $currentOAuth2Scope.adminConsentDescription + adminConsentDisplayName = $currentOAuth2Scope.adminConsentDisplayName + id = $currentOAuth2Scope.id + isEnabled = $currentOAuth2Scope.isEnabled + type = $currentOAuth2Scope.type + userConsentDescription = $currentOAuth2Scope.userConsentDescription + userConsentDisplayName = $currentOAuth2Scope.userConsentDisplayName + value = $currentOAuth2Scope.value + } + } + $complexApi.Add('PreAuthorizedApplications', $complexPreAuthorizedApplications) + $complexApi.Add('Oauth2PermissionScopes', $complexOAuth2Scopes) if ($complexApi.values.Where({ $null -ne $_ }).Count -eq 0) { $complexApi = $null @@ -736,18 +753,55 @@ function Set-TargetResource } $currentParameters.Remove('AvailableToOtherTenants') | Out-Null $currentParameters.Remove('PublicClient') | Out-Null + $currentParameters.Remove('Verbose') | Out-Null - if ($currentParameters.KnownClientApplications) + #region API + $apiValue = @{} + if ($currentParameters.Api.KnownClientApplications) + { + $apiValue.Add('KnownClientApplications', $currentParameters.Api.KnownClientApplications) + } + if ($currentParameters.Api.Oauth2PermissionScopes) { - $apiValue = @{ - KnownClientApplications = $currentParameters.KnownClientApplications + Write-Verbose -Message "Oauth2PermissionScopes specified and is not empty" + $scopeValue = @() + foreach ($scope in $currentParameters.Api.Oauth2PermissionScopes) + { + $scopeEntry = @{ + adminConsentDescription = $scope.adminConsentDescription + adminConsentDisplayName = $scope.adminConsentDisplayName + isEnabled = $scope.isEnabled + type = $scope.type + userConsentDescription = $scope.userConsentDescription + userConsentDisplayName = $scope.userConsentDisplayName + value = $scope.value + } + if (-not [System.String]::IsNullOrEmpty($scope.id)) + { + Write-Verbose -Message "Adding existing scope id {$($scope.id)}" + $scopeEntry.Add('id', $scope.id) + } + else + { + Write-Verbose -Message "Generating new scope id" + $scopeEntry.Add('id', (New-Guid).ToString()) + } + + $scopeValue += $scopeEntry } - $currentParameters.Add('Api', $apiValue) - $currentParameters.Remove('KnownClientApplications') | Out-Null + $apiValue.Add('Oauth2PermissionScopes', $scopeValue) + } + #endregion + + if ($currentParameters.ContainsKey('Api')) + { + Write-Verbose "Found existing API parameter. Updating with $(Convert-M365DscHashtableToString -Hashtable $apiValue)" + $currentParameters.Api = $apiValue } else { - $currentParameters.Remove('KnownClientApplications') | Out-Null + Write-Verbose "Adding API parameter with $(Convert-M365DscHashtableToString -Hashtable $apiValue)" + $currentParameters.Add('Api', $apiValue) } if ($ReplyUrls -or $LogoutURL -or $Homepage) @@ -774,7 +828,6 @@ function Set-TargetResource $currentParameters.Remove('Homepage') | Out-Null $currentParameters.Remove('OnPremisesPublishing') | Out-Null - $keys = (([Hashtable]$currentParameters).clone()).Keys foreach ($key in $keys) { @@ -859,6 +912,7 @@ function Set-TargetResource $currentParameters.Remove('ApplicationTemplateId') | Out-Null Write-Verbose -Message "Creating New AzureAD Application {$DisplayName} with values:`r`n$($currentParameters | Out-String)" + Write-Verbose -Message "Parameters with API: $(ConvertTo-Json $currentParameters -Depth 10)" $currentAADApp = New-MgApplication @currentParameters Write-Verbose -Message "Azure AD Application {$DisplayName} was successfully created" $needToUpdatePermissions = $true @@ -1043,7 +1097,7 @@ function Set-TargetResource $allRequiredAccess = @() } else - { + { $allSourceAPIs = $Permissions.SourceAPI | Select-Object -Unique $allRequiredAccess = @() @@ -1570,6 +1624,11 @@ function Export-TargetResource CimInstanceName = 'MicrosoftGraphPreAuthorizedApplication' IsRequired = $False } + @{ + Name = 'Oauth2PermissionScopes' + CimInstanceName = 'MSFT_MicrosoftGraphApiOauth2PermissionScopes' + IsRequired = $False + } ) $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString ` -ComplexObject $Results.Api ` diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADApplication/MSFT_AADApplication.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_AADApplication/MSFT_AADApplication.schema.mof index 21e278cc40..d64409ef93 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADApplication/MSFT_AADApplication.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADApplication/MSFT_AADApplication.schema.mof @@ -82,10 +82,26 @@ class MSFT_MicrosoftGraphPreAuthorizedApplication [Write, Description("The unique identifier for the scopes the client application is granted.")] String PermissionIds[]; }; +[ClassVersion("1.0.0")] +class MSFT_MicrosoftGraphApiOauth2PermissionScopes +{ + [Write, Description("A description of the delegated permissions, intended to be read by an administrator granting the permission on behalf of all users. This text appears in tenant-wide admin consent experiences.")] String adminConsentDescription; + [Write, Description("The permission's title, intended to be read by an administrator granting the permission on behalf of all users.")] String adminConsentDisplayName; + [Write, Description("A description of the delegated permissions, intended to be read by a user granting the permission on their own behalf. This text appears in consent experiences where the user is consenting only on behalf of themselves.")] String userConsentDescription; + [Write, Description("A title for the permission, intended to be read by a user granting the permission on their own behalf. This text appears in consent experiences where the user is consenting only on behalf of themselves.")] String userConsentDisplayName; + [Write, Description("Specifies the value to include in the scp (scope) claim in access tokens. Must not exceed 120 characters in length.")] String value; + [Write, Description("When you create or update a permission, this property must be set to true (which is the default). To delete a permission, this property must first be set to false. At that point, in a subsequent call, the permission may be removed.")] Boolean isEnabled; + [Write, Description("The possible values are: User and Admin. Specifies whether this delegated permission should be considered safe for non-admin users to consent to on behalf of themselves, or whether an administrator consent should always be required.")] String type; + [Write, Description("Unique delegated permission identifier inside the collection of delegated permissions defined for a resource application.")] String id; + +}; + [ClassVersion("1.0.0")] class MSFT_MicrosoftGraphApiApplication { [Write, Description("Lists the client applications that are preauthorized with the specified delegated permissions to access this application's APIs. Users aren't required to consent to any preauthorized application (for the permissions specified). However, any other permissions not listed in preAuthorizedApplications (requested through incremental consent for example) will require user consent."), EmbeddedInstance("MSFT_MicrosoftGraphPreAuthorizedApplication")] String PreAuthorizedApplications[]; + [Write, Description("List of associated API scopes."), EmbeddedInstance("MSFT_MicrosoftGraphAPIOauth2PermissionScopes")] String Oauth2PermissionScopes[]; + }; [ClassVersion("1.0.0")] diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_PPPowerAppPolicyUrlPatterns/MSFT_PPPowerAppPolicyUrlPatterns.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_PPPowerAppPolicyUrlPatterns/MSFT_PPPowerAppPolicyUrlPatterns.psm1 index 602805cb67..75ee6a2896 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_PPPowerAppPolicyUrlPatterns/MSFT_PPPowerAppPolicyUrlPatterns.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_PPPowerAppPolicyUrlPatterns/MSFT_PPPowerAppPolicyUrlPatterns.psm1 @@ -173,9 +173,6 @@ function Set-TargetResource Add-M365DSCTelemetryEvent -Data $data #endregion - $policy = Get-AdminDlpPolicy | Where-Object -FilterScript { $_.DisplayName -eq $PolicyName } - $policyNameValue = $policy.PolicyName - # CREATE if ($Ensure -eq 'Present') { @@ -192,10 +189,10 @@ function Set-TargetResource } } $payload = $(ConvertTo-Json $body -Depth 9 -Compress) - Write-Verbose -Message "Setting new Url Patterns for Policy {$($PolicyNameValue)} with parameters:`r`n$payload" + Write-Verbose -Message "Setting new Url Patterns for Policy {$($PolicyName)} with parameters:`r`n$payload" New-PowerAppPolicyUrlPatterns -TenantId $PPTenantId ` - -PolicyName $policyNameValue ` + -PolicyName $PolicyName ` -NewUrlPatterns $body ` -Verbose } @@ -203,7 +200,7 @@ function Set-TargetResource elseif ($Ensure -eq 'Absent') { Write-Verbose -Message "Removing Url Patterns for Policy {$($PolicyNameValue)}" - Remove-PowerAppPolicyUrlPatterns -TenantId $PPTenantId -PolicyName $policyNameValue + Remove-PowerAppPolicyUrlPatterns -TenantId $PPTenantId -PolicyName $PolicyName } } diff --git a/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 b/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 index 815cde6893..716c252ea6 100644 --- a/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 +++ b/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 @@ -114,7 +114,7 @@ }, @{ ModuleName = 'Microsoft.PowerApps.Administration.PowerShell' - RequiredVersion = '2.0.200' + RequiredVersion = '2.0.202' }, @{ ModuleName = 'MicrosoftTeams' From aac1ec41b558822e21b4a942055cb4a52926bc74 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Mon, 16 Dec 2024 09:59:57 -0500 Subject: [PATCH 2/4] Update MSFT_AADApplication.psm1 --- .../DSCResources/MSFT_AADApplication/MSFT_AADApplication.psm1 | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADApplication/MSFT_AADApplication.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADApplication/MSFT_AADApplication.psm1 index 3e306012f0..72953ed80b 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADApplication/MSFT_AADApplication.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADApplication/MSFT_AADApplication.psm1 @@ -791,6 +791,7 @@ function Set-TargetResource } $apiValue.Add('Oauth2PermissionScopes', $scopeValue) } + $currentParameters.Remove('KnownClientApplications') | Out-Null #endregion if ($currentParameters.ContainsKey('Api')) From 685e692b3205e343ad84fcdee56fe6cdaa74cb8c Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Mon, 16 Dec 2024 10:06:09 -0500 Subject: [PATCH 3/4] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12693f9e04..4062422a63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ FIXES [#5525](https://github.com/microsoft/Microsoft365DSC/issues/5525) * DEPENDENCIES * Updated Microsoft.PowerApps.Administration.PowerShell to version 2.0.202. + * Updated ReverseDSC to version 2.0.0.23. # 1.24.1211.1 From 3ce55d9cc043725c39a184c15343863e82410398 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Mon, 16 Dec 2024 10:06:26 -0500 Subject: [PATCH 4/4] Update Manifest.psd1 --- Modules/Microsoft365DSC/Dependencies/Manifest.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 b/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 index 716c252ea6..3482e986ff 100644 --- a/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 +++ b/Modules/Microsoft365DSC/Dependencies/Manifest.psd1 @@ -138,7 +138,7 @@ }, @{ ModuleName = 'ReverseDSC' - RequiredVersion = '2.0.0.22' + RequiredVersion = '2.0.0.23' } ) }