Skip to content

Commit

Permalink
Merge pull request #1067 from JohnDuprey/dev
Browse files Browse the repository at this point in the history
CIPP-SAM - Permission builder/CPV
  • Loading branch information
JohnDuprey authored Aug 14, 2024
2 parents dedfff8 + d62a47b commit 940f334
Show file tree
Hide file tree
Showing 6 changed files with 225 additions and 90 deletions.
21 changes: 20 additions & 1 deletion Modules/CIPPCore/Public/Add-CIPPApplicationPermission.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,26 @@ function Add-CIPPApplicationPermission {
}
Set-Location (Get-Item $PSScriptRoot).FullName
if ($RequiredResourceAccess -eq 'CIPPDefaults') {
$RequiredResourceAccess = (Get-Content '.\SAMManifest.json' | ConvertFrom-Json).requiredResourceAccess
#$RequiredResourceAccess = (Get-Content '.\SAMManifest.json' | ConvertFrom-Json).requiredResourceAccess

$Permissions = Get-CippSamPermissions -NoDiff
$RequiredResourceAccess = [System.Collections.Generic.List[object]]::new()

foreach ($AppId in $Permissions.Permissions.PSObject.Properties.Name) {
$AppPermissions = @($Permissions.Permissions.$AppId.applicationPermissions)
$Resource = @{
resourceAppId = $AppId
resourceAccess = [System.Collections.Generic.List[object]]::new()
}
foreach ($Permission in $AppPermissions) {
$Resource.ResourceAccess.Add(@{
id = $Permission.id
type = 'Role'
})
}

$RequiredResourceAccess.Add($Resource)
}
}
$ServicePrincipalList = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/servicePrincipals?`$select=AppId,id,displayName&`$top=999" -skipTokenCache $true -tenantid $Tenantfilter -NoAuthCheck $true
$ourSVCPrincipal = $ServicePrincipalList | Where-Object -Property AppId -EQ $ApplicationId
Expand Down
43 changes: 32 additions & 11 deletions Modules/CIPPCore/Public/Add-CIPPDelegatedPermission.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,31 @@ function Add-CIPPDelegatedPermission {
}

if ($RequiredResourceAccess -eq 'CIPPDefaults') {
$RequiredResourceAccess = (Get-Content '.\SAMManifest.json' | ConvertFrom-Json).requiredResourceAccess
$AdditionalPermissions = Get-Content '.\AdditionalPermissions.json' | ConvertFrom-Json
$Permissions = Get-CippSamPermissions -NoDiff
$NoTranslateRequired = $Permissions.Type -eq 'Table'
$RequiredResourceAccess = [System.Collections.Generic.List[object]]::new()
foreach ($AppId in $Permissions.Permissions.PSObject.Properties.Name) {
$DelegatedPermissions = @($Permissions.Permissions.$AppId.delegatedPermissions)
$ResourceAccess = [System.Collections.Generic.List[object]]::new()
foreach ($Permission in $DelegatedPermissions) {
$ResourceAccess.Add(@{
id = $Permission.value
type = 'Scope'
})
}
$Resource = @{
resourceAppId = $AppId
resourceAccess = @($ResourceAccess)
}
$RequiredResourceAccess.Add($Resource)
}

if ($Tenantfilter -eq $env:TenantID) {
$RequiredResourceAccess = $RequiredResourceAccess + ($AdditionalPermissions | Where-Object { $RequiredResourceAccess.resourceAppId -notcontains $_.resourceAppId })
} else {
# remove the partner center permission if not pushing to partner tenant
$RequiredResourceAccess = $RequiredResourceAccess | Where-Object { $_.resourceAppId -ne 'fa3d9a0c-3fb0-42cc-9193-47c7ecd2edbd' }
}
$RequiredResourceAccess = $RequiredResourceAccess + ($AdditionalPermissions | Where-Object { $RequiredResourceAccess.resourceAppId -notcontains $_.resourceAppId })
}
$Translator = Get-Content '.\PermissionsTranslator.json' | ConvertFrom-Json
$ServicePrincipalList = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/servicePrincipals?`$select=AppId,id,displayName&`$top=999" -tenantid $Tenantfilter -skipTokenCache $true -NoAuthCheck $true
Expand All @@ -46,16 +61,22 @@ function Add-CIPPDelegatedPermission {
continue
}
}
$AdditionalScopes = ($AdditionalPermissions | Where-Object -Property resourceAppId -EQ $App.resourceAppId).resourceAccess | Where-Object -Property type -EQ 'Scope'

$DelegatedScopes = $App.resourceAccess | Where-Object -Property type -EQ 'Scope'
if ($AdditionalScopes) {
$NewScope = (@(($Translator | Where-Object { $_.id -in $DelegatedScopes.id }).value) + @($AdditionalScopes.id | Select-Object -Unique)) -join ' '
if ($NoTranslateRequired) {
$NewScope = @($DelegatedScopes | ForEach-Object { $_.id } | Sort-Object -Unique) -join ' '
} else {
if ($NoTranslateRequired) {
$NewScope = @($DelegatedScopes | ForEach-Object { $_.id } | Sort-Object -Unique) -join ' '
} else {
$NewScope = @(($Translator | Where-Object { $_.id -in $DelegatedScopes.id }).value | Sort-Object -Unique) -join ' '
$NewScope = foreach ($Scope in $DelegatedScopes.id) {
if ($Scope -match '^[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}$') {
$TranslatedScope = ($Translator | Where-Object -Property id -EQ $Scope).value
if ($TranslatedScope) {
$TranslatedScope
}
} else {
$Scope
}
}
$NewScope = (@($NewScope) | Sort-Object -Unique) -join ' '
}

$OldScope = ($CurrentDelegatedScopes | Where-Object -Property Resourceid -EQ $svcPrincipalId.id)
Expand Down Expand Up @@ -83,7 +104,7 @@ function Add-CIPPDelegatedPermission {
# Added permissions
$Added = ($Compare | Where-Object { $_.SideIndicator -eq '=>' }).InputObject -join ' '
$Removed = ($Compare | Where-Object { $_.SideIndicator -eq '<=' }).InputObject -join ' '
$Results.add("Successfully updated permissions for $($svcPrincipalId.displayName). $(if ($Added) { "Added: $Added"}) $(if ($Removed) { "Removed: $Removed"})")
$Results.add("Successfully updated permissions for $($svcPrincipalId.displayName). $(if ($Added) { "Added: $Added"}) $(if ($Removed) { "Removed: $Removed"})")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,21 @@ function Invoke-ExecServicePrincipals {
try {
switch ($Request.Query.Action) {
'Create' {
$Body = @{
'appId' = $Request.Query.AppId
} | ConvertTo-Json -Compress
$Results = New-GraphPostRequest -Uri 'https://graph.microsoft.com/beta/servicePrincipals' -tenantid $TenantFilter -type POST -body $Body
$Action = 'Create'
if ($Request.Query.AppId -match '^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$') {
$Body = @{
'appId' = $Request.Query.AppId
} | ConvertTo-Json -Compress
try {
$Results = New-GraphPostRequest -Uri 'https://graph.microsoft.com/beta/servicePrincipals' -tenantid $TenantFilter -type POST -body $Body
} catch {
$Results = "Unable to create service principal: $($_.Exception.Message)"
$Success = $false
}
} else {
$Results = 'Invalid AppId'
$Success = $false
}
}
default {
if ($Request.Query.AppId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function Invoke-ExecSAMAppPermissions {
$Entity = @{
'PartitionKey' = 'CIPP-SAM'
'RowKey' = 'CIPP-SAM'
'Permissions' = [string]($Permissions | ConvertTo-Json -Depth 10 -Compress)
'Permissions' = [string]($Permissions.Permissions | ConvertTo-Json -Depth 10 -Compress)
}
$Table = Get-CIPPTable -TableName 'AppPermissions'
$null = Add-CIPPAzDataTableEntity @Table -Entity $Entity -Force
Expand All @@ -29,77 +29,7 @@ function Invoke-ExecSAMAppPermissions {
}
}
default {
$ModuleBase = Get-Module -Name CIPPCore | Select-Object -ExpandProperty ModuleBase
$SamManifest = Get-Item "$ModuleBase\Public\SAMManifest.json"
$AdditionalPermissions = Get-Item "$ModuleBase\Public\AdditionalPermissions.json"

$LastWrite = @{
'SAMManifest' = $SamManifest.LastWriteTime
'AdditionalPermissions' = $AdditionalPermissions.LastWriteTime
}

$ServicePrincipals = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/servicePrincipals?$top=999&$select=appId,displayName,appRoles,publishedPermissionScopes' -tenantid $env:TenantID -NoAuthCheck $true
$SAMManifest = Get-Content -Path $SamManifest.FullName | ConvertFrom-Json
$AdditionalPermissions = Get-Content -Path $AdditionalPermissions.FullName | ConvertFrom-Json

$RequiredResources = $SamManifest.requiredResourceAccess

$AppIds = ($RequiredResources.resourceAppId + $AdditionalPermissions.resourceAppId) | Sort-Object -Unique

$Permissions = @{}
foreach ($AppId in $AppIds) {
$ServicePrincipal = $ServicePrincipals | Where-Object -Property appId -EQ $AppId
$AppPermissions = [System.Collections.Generic.List[object]]@()
$ManifestPermissions = ($RequiredResources | Where-Object -Property resourceAppId -EQ $AppId).resourceAccess
$UnpublishedPermissions = ($AdditionalPermissions | Where-Object -Property resourceAppId -EQ $AppId).resourceAccess

foreach ($Permission in $ManifestPermissions) {
$AppPermissions.Add($Permission)
}
if ($UnpublishedPermissions) {
foreach ($Permission in $UnpublishedPermissions) {
$AppPermissions.Add($Permission)
}
}

$ApplicationPermissions = [system.collections.generic.list[object]]@()
$DelegatedPermissions = [system.collections.generic.list[object]]@()
foreach ($Permission in $AppPermissions) {
if ($Permission.id -match '^[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}$') {
if ($Permission.type -eq 'Role') {
$PermissionName = ($ServicePrincipal.appRoles | Where-Object -Property id -EQ $Permission.id).value
} else {
$PermissionName = ($ServicePrincipal.publishedPermissionScopes | Where-Object -Property id -EQ $Permission.id).value
}
} else {
$PermissionName = $Permission.id
}

if ($Permission.type -eq 'Role') {
$ApplicationPermissions.Add([PSCustomObject]@{
id = $Permission.id
value = $PermissionName

})
} else {
$DelegatedPermissions.Add([PSCustomObject]@{
id = $Permission.id
value = $PermissionName
})
}
}

$ServicePrincipal = $ServicePrincipals | Where-Object -Property appId -EQ $AppId
$Permissions.$AppId = @{
applicationPermissions = @($ApplicationPermissions | Sort-Object -Property label)
delegatedPermissions = @($DelegatedPermissions | Sort-Object -Property label)
}
}

$Body = @{
'Permissions' = $Permissions
'LastUpdate' = $LastWrite
}
$Body = Get-CippSamPermissions
}
}

Expand Down
154 changes: 154 additions & 0 deletions Modules/CIPPCore/Public/GraphHelper/Get-CippSamPermissions.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
function Get-CippSamPermissions {
<#
.SYNOPSIS
This script retrieves the CIPP-SAM permissions.
.DESCRIPTION
The Get-CippSamManifest function is used to retrieve the CIPP-SAM permissions either from the manifest files or table.
.EXAMPLE
Get-CippSamManifest
Retrieves the CIPP SAM manifest located in the module root
.FUNCTIONALITY
Internal
#>
[CmdletBinding(DefaultParameterSetName = 'Default')]
Param(
[Parameter(ParameterSetName = 'ManifestOnly')]
[switch]$ManifestOnly,
[Parameter(ParameterSetName = 'Default')]
[switch]$SavedOnly,
[Parameter(ParameterSetName = 'Diff')]
[switch]$NoDiff
)

if (!$SavedOnly.IsPresent) {
$ModuleBase = Get-Module -Name CIPPCore | Select-Object -ExpandProperty ModuleBase
$SamManifest = Get-Item "$ModuleBase\Public\SAMManifest.json"
$AdditionalPermissions = Get-Item "$ModuleBase\Public\AdditionalPermissions.json"

$ServicePrincipals = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/servicePrincipals?$top=999&$select=appId,displayName,appRoles,publishedPermissionScopes' -tenantid $env:TenantID -NoAuthCheck $true
$SAMManifest = Get-Content -Path $SamManifest.FullName | ConvertFrom-Json
$AdditionalPermissions = Get-Content -Path $AdditionalPermissions.FullName | ConvertFrom-Json

$RequiredResources = $SamManifest.requiredResourceAccess

$AppIds = ($RequiredResources.resourceAppId + $AdditionalPermissions.resourceAppId) | Sort-Object -Unique

$Permissions = @{}
foreach ($AppId in $AppIds) {
$ServicePrincipal = $ServicePrincipals | Where-Object -Property appId -EQ $AppId
$AppPermissions = [System.Collections.Generic.List[object]]@()
$ManifestPermissions = ($RequiredResources | Where-Object -Property resourceAppId -EQ $AppId).resourceAccess
$UnpublishedPermissions = ($AdditionalPermissions | Where-Object -Property resourceAppId -EQ $AppId).resourceAccess

foreach ($Permission in $ManifestPermissions) {
$AppPermissions.Add($Permission)
}
if ($UnpublishedPermissions) {
foreach ($Permission in $UnpublishedPermissions) {
$AppPermissions.Add($Permission)
}
}

$ApplicationPermissions = [system.collections.generic.list[object]]@()
$DelegatedPermissions = [system.collections.generic.list[object]]@()
foreach ($Permission in $AppPermissions) {
if ($Permission.id -match '^[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}$') {
if ($Permission.type -eq 'Role') {
$PermissionName = ($ServicePrincipal.appRoles | Where-Object -Property id -EQ $Permission.id).value
} else {
$PermissionName = ($ServicePrincipal.publishedPermissionScopes | Where-Object -Property id -EQ $Permission.id).value
}
} else {
$PermissionName = $Permission.id
}

if ($Permission.type -eq 'Role') {
$ApplicationPermissions.Add([PSCustomObject]@{
id = $Permission.id
value = $PermissionName

})
} else {
$DelegatedPermissions.Add([PSCustomObject]@{
id = $Permission.id
value = $PermissionName
})
}
}

$ServicePrincipal = $ServicePrincipals | Where-Object -Property appId -EQ $AppId
$Permissions.$AppId = @{
applicationPermissions = @($ApplicationPermissions | Sort-Object -Property label)
delegatedPermissions = @($DelegatedPermissions | Sort-Object -Property label)
}
}
}
if ($ManifestOnly) {
return [PSCustomObject]@{
Permissions = $Permissions
Type = 'Manifest'
}
}

$Table = Get-CippTable -tablename 'AppPermissions'
$SavedPermissions = Get-CippAzDataTableEntity @Table -Filter "PartitionKey eq 'CIPP-SAM' and RowKey eq 'CIPP-SAM'"
if ($SavedPermissions.Permissions) {
$SavedPermissions.Permissions = $SavedPermissions.Permissions | ConvertFrom-Json
} else {
$SavedPermissions = @{
Permissions = [PSCustomObject]@{}
}
}

if ($SavedOnly.IsPresent) {
$SavedPermissions | Add-Member -MemberType NoteProperty -Name Type -Value 'Table'
return $SavedPermissions
}

if (!$NoDiff -and $SavedPermissions.Permissions) {
$DiffPermissions = @{}
foreach ($AppId in $AppIds) {
$ManifestSpPermissions = $Permissions.$AppId
$SavedSpPermission = $SavedPermissions.Permissions.$AppId
$MissingApp = [System.Collections.Generic.List[object]]::new()
$MissingDelegated = [System.Collections.Generic.List[object]]::new()
foreach ($Permission in $ManifestSpPermissions.applicationPermissions) {
if ($SavedSpPermission.applicationPermissions.id -notcontains $Permission.id) {
$MissingApp.Add($Permission)
}
}
foreach ($Permission in $ManifestSpPermissions.delegatedPermissions) {
if ($SavedSpPermission.delegatedPermissions.id -notcontains $Permission.id) {
$MissingDelegated.Add($Permission)
}
}
if ($MissingApp -or $MissingDelegated) {
$DiffPermissions.$AppId = @{
applicationPermissions = $MissingApp
delegatedPermissions = $MissingDelegated
}
}
}
}

$SamAppPermissions = @{}
if (($SavedPermissions.Permissions.PSObject.Properties.Name | Measure-Object).Count -gt 0) {
$SamAppPermissions.Permissions = $SavedPermissions.Permissions
$SamAppPermissions.Type = 'Table'
} else {
$SamAppPermissions.Permissions = $Permissions
$SamAppPermissions.Type = 'Manifest'
}

if (!$NoDiff.IsPresent) {
$SamAppPermissions.MissingPermissions = $DiffPermissions
}

$SamAppPermissions = $SamAppPermissions | ConvertTo-Json -Depth 10 -Compress | ConvertFrom-Json

return $SamAppPermissions
}

4 changes: 2 additions & 2 deletions Modules/CIPPCore/Public/SAMManifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@
{ "id": "1138cb37-bd11-4084-a2b7-9f71582aeddb", "type": "Role" },
{ "id": "78145de6-330d-4800-a6ce-494ff2d33d07", "type": "Role" },
{ "id": "9241abd9-d0e6-425a-bd4f-47ba86e767a4", "type": "Role" },
{ "id": "5b07b0dd-2377-4e44-a38d-703f09a0dc3c", "type": "Role" },
{ "id": "243333ab-4d21-40cb-a475-36241daa0842", "type": "Role" },
{ "id": "e330c4f0-4170-414e-a55a-2f022ec2b57b", "type": "Role" },
{ "id": "5ac13192-7ace-4fcf-b828-1a26f28068ee", "type": "Role" },
Expand Down Expand Up @@ -154,7 +153,8 @@
{ "id": "e0a7cdbb-08b0-4697-8264-0069786e9674", "type": "Scope" },
{ "id": "19da66cb-0fb0-4390-b071-ebc76a349482", "type": "Role" },
{ "id": "818c620a-27a9-40bd-a6a5-d96f7d610b4b", "type": "Scope" },
{ "id": "6931bccd-447a-43d1-b442-00a195474933", "type": "Role" }
{ "id": "6931bccd-447a-43d1-b442-00a195474933", "type": "Role" },
{ "id": "c5366453-9fb0-48a5-a156-24f0c49a4b84", "type": "Scope" }
]
},
{
Expand Down

0 comments on commit 940f334

Please sign in to comment.