Skip to content

Commit fd84794

Browse files
authored
Merge pull request #336 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents f732739 + 643dfcb commit fd84794

File tree

3 files changed

+204
-131
lines changed

3 files changed

+204
-131
lines changed
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
function Get-CippAllowedPermissions {
2+
<#
3+
.SYNOPSIS
4+
Retrieves the allowed permissions for the current user.
5+
6+
.DESCRIPTION
7+
This function retrieves the allowed permissions for the current user based on their role and the configured permissions in the CIPP system.
8+
For admin/superadmin users, permissions are computed from base role include/exclude rules.
9+
For editor/readonly users, permissions start from base role and are restricted by custom roles.
10+
11+
.PARAMETER UserRoles
12+
Array of user roles to compute permissions for.
13+
14+
.OUTPUTS
15+
Returns a list of allowed permissions for the current user.
16+
#>
17+
18+
[CmdletBinding()]
19+
param(
20+
[Parameter(Mandatory = $true)]
21+
[string[]]$UserRoles
22+
)
23+
24+
# Get all available permissions and base roles configuration
25+
26+
$CIPPCoreModuleRoot = Get-Module -Name CIPPCore | Select-Object -ExpandProperty ModuleBase
27+
$CIPPRoot = (Get-Item $CIPPCoreModuleRoot).Parent.Parent
28+
$Version = (Get-Content -Path $CIPPRoot\version_latest.txt).trim()
29+
$BaseRoles = Get-Content -Path $CIPPRoot\Config\cipp-roles.json | ConvertFrom-Json
30+
$DefaultRoles = @('superadmin', 'admin', 'editor', 'readonly', 'anonymous', 'authenticated')
31+
32+
$AllPermissionCacheTable = Get-CIPPTable -tablename 'cachehttppermissions'
33+
$AllPermissionsRow = Get-CIPPAzDataTableEntity @AllPermissionCacheTable -Filter "PartitionKey eq 'HttpFunctions' and RowKey eq 'HttpFunctions' and Version eq '$($Version)'"
34+
35+
if (-not $AllPermissionsRow) {
36+
$AllPermissions = Get-CIPPHttpFunctions -ByRole | Select-Object -ExpandProperty Permission
37+
$Entity = @{
38+
PartitionKey = 'HttpFunctions'
39+
RowKey = 'HttpFunctions'
40+
Version = [string]$Version
41+
Permissions = [string]($AllPermissions | ConvertTo-Json -Compress)
42+
}
43+
Add-CIPPAzDataTableEntity @AllPermissionCacheTable -Entity $Entity -Force
44+
} else {
45+
$AllPermissions = $AllPermissionsRow.Permissions | ConvertFrom-Json
46+
}
47+
48+
$AllowedPermissions = [System.Collections.Generic.List[string]]::new()
49+
50+
# Determine user's primary base role (highest priority first)
51+
$BaseRole = $null
52+
$PrimaryRole = $null
53+
54+
if ($UserRoles -contains 'superadmin') {
55+
$PrimaryRole = 'superadmin'
56+
} elseif ($UserRoles -contains 'admin') {
57+
$PrimaryRole = 'admin'
58+
} elseif ($UserRoles -contains 'editor') {
59+
$PrimaryRole = 'editor'
60+
} elseif ($UserRoles -contains 'readonly') {
61+
$PrimaryRole = 'readonly'
62+
}
63+
64+
if ($PrimaryRole) {
65+
$BaseRole = $BaseRoles.PSObject.Properties | Where-Object { $_.Name -eq $PrimaryRole } | Select-Object -First 1
66+
}
67+
68+
# Get custom roles (non-default roles)
69+
$CustomRoles = $UserRoles | Where-Object { $DefaultRoles -notcontains $_ }
70+
71+
# For admin and superadmin: Compute permissions from base role include/exclude rules
72+
if ($PrimaryRole -in @('admin', 'superadmin')) {
73+
Write-Information "Computing permissions for $PrimaryRole using base role rules"
74+
75+
if ($BaseRole) {
76+
# Start with all permissions and apply include/exclude rules
77+
$BasePermissions = [System.Collections.Generic.List[string]]::new()
78+
79+
# Apply include rules
80+
foreach ($Include in $BaseRole.Value.include) {
81+
$MatchingPermissions = $AllPermissions | Where-Object { $_ -like $Include }
82+
foreach ($Permission in $MatchingPermissions) {
83+
if ($BasePermissions -notcontains $Permission) {
84+
$BasePermissions.Add($Permission)
85+
}
86+
}
87+
}
88+
89+
# Apply exclude rules
90+
foreach ($Exclude in $BaseRole.Value.exclude) {
91+
$ExcludedPermissions = $BasePermissions | Where-Object { $_ -like $Exclude }
92+
foreach ($Permission in $ExcludedPermissions) {
93+
$BasePermissions.Remove($Permission) | Out-Null
94+
}
95+
}
96+
97+
foreach ($Permission in $BasePermissions) {
98+
$AllowedPermissions.Add($Permission)
99+
}
100+
}
101+
}
102+
# For editor and readonly: Start with base role permissions and restrict with custom roles
103+
elseif ($PrimaryRole -in @('editor', 'readonly')) {
104+
Write-Information "Computing permissions for $PrimaryRole with custom role restrictions"
105+
106+
if ($BaseRole) {
107+
# Get base role permissions first
108+
$BasePermissions = [System.Collections.Generic.List[string]]::new()
109+
110+
# Apply include rules from base role
111+
foreach ($Include in $BaseRole.Value.include) {
112+
$MatchingPermissions = $AllPermissions | Where-Object { $_ -like $Include }
113+
foreach ($Permission in $MatchingPermissions) {
114+
if ($BasePermissions -notcontains $Permission) {
115+
$BasePermissions.Add($Permission)
116+
}
117+
}
118+
}
119+
120+
# Apply exclude rules from base role
121+
foreach ($Exclude in $BaseRole.Value.exclude) {
122+
$ExcludedPermissions = $BasePermissions | Where-Object { $_ -like $Exclude }
123+
foreach ($Permission in $ExcludedPermissions) {
124+
$BasePermissions.Remove($Permission) | Out-Null
125+
}
126+
}
127+
128+
# If custom roles exist, intersect with custom role permissions (restriction)
129+
if ($CustomRoles.Count -gt 0) {
130+
$CustomRolePermissions = [System.Collections.Generic.List[string]]::new()
131+
132+
foreach ($CustomRole in $CustomRoles) {
133+
try {
134+
$RolePermissions = Get-CIPPRolePermissions -RoleName $CustomRole
135+
foreach ($Permission in $RolePermissions.Permissions) {
136+
if ($null -ne $Permission -and $Permission -is [string] -and $CustomRolePermissions -notcontains $Permission) {
137+
$CustomRolePermissions.Add($Permission)
138+
}
139+
}
140+
} catch {
141+
Write-Warning "Failed to get permissions for custom role '$CustomRole': $($_.Exception.Message)"
142+
}
143+
}
144+
145+
# Restrict base permissions to only those allowed by custom roles
146+
$RestrictedPermissions = $BasePermissions | Where-Object { $CustomRolePermissions -contains $_ }
147+
foreach ($Permission in $RestrictedPermissions) {
148+
if ($null -ne $Permission -and $Permission -is [string]) {
149+
$AllowedPermissions.Add($Permission)
150+
}
151+
}
152+
} else {
153+
# No custom roles, use base role permissions
154+
foreach ($Permission in $BasePermissions) {
155+
if ($null -ne $Permission -and $Permission -is [string]) {
156+
$AllowedPermissions.Add($Permission)
157+
}
158+
}
159+
}
160+
}
161+
}
162+
# Handle users with only custom roles (no base role)
163+
elseif ($CustomRoles.Count -gt 0) {
164+
Write-Information 'Computing permissions for custom roles only'
165+
166+
foreach ($CustomRole in $CustomRoles) {
167+
try {
168+
$RolePermissions = Get-CIPPRolePermissions -RoleName $CustomRole
169+
foreach ($Permission in $RolePermissions.Permissions) {
170+
if ($null -ne $Permission -and $Permission -is [string] -and $AllowedPermissions -notcontains $Permission) {
171+
$AllowedPermissions.Add($Permission)
172+
}
173+
}
174+
} catch {
175+
Write-Warning "Failed to get permissions for custom role '$CustomRole': $($_.Exception.Message)"
176+
}
177+
}
178+
}
179+
180+
# Return sorted unique permissions
181+
return ($AllowedPermissions | Sort-Object -Unique)
182+
}

Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,6 @@ function Test-CIPPAccess {
1515
# Check help for role
1616
$APIRole = $Help.Role
1717

18-
if ($APIRole -eq 'Public') {
19-
return $true
20-
}
21-
22-
# Get default roles from config
23-
$CIPPCoreModuleRoot = Get-Module -Name CIPPCore | Select-Object -ExpandProperty ModuleBase
24-
$CIPPRoot = (Get-Item $CIPPCoreModuleRoot).Parent.Parent
25-
$BaseRoles = Get-Content -Path $CIPPRoot\Config\cipp-roles.json | ConvertFrom-Json
26-
27-
if ($APIRole -eq 'Public') {
28-
return $true
29-
}
30-
3118
# Get default roles from config
3219
$CIPPCoreModuleRoot = Get-Module -Name CIPPCore | Select-Object -ExpandProperty ModuleBase
3320
$CIPPRoot = (Get-Item $CIPPCoreModuleRoot).Parent.Parent
@@ -38,11 +25,6 @@ function Test-CIPPAccess {
3825
return $true
3926
}
4027

41-
# Get default roles from config
42-
$CIPPCoreModuleRoot = Get-Module -Name CIPPCore | Select-Object -ExpandProperty ModuleBase
43-
$CIPPRoot = (Get-Item $CIPPCoreModuleRoot).Parent.Parent
44-
$BaseRoles = Get-Content -Path $CIPPRoot\Config\cipp-roles.json | ConvertFrom-Json
45-
4628
if ($Request.Headers.'x-ms-client-principal-idp' -eq 'aad' -and $Request.Headers.'x-ms-client-principal-name' -match '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$') {
4729
$Type = 'APIClient'
4830
# Direct API Access
@@ -91,6 +73,22 @@ function Test-CIPPAccess {
9173
$CustomRoles = @('cipp-api')
9274
Write-Information "API Access: AppId=$($Request.Headers.'x-ms-client-principal-name'), IP=$IPAddress"
9375
}
76+
if ($Request.Params.CIPPEndpoint -eq 'me') {
77+
$Permissions = Get-CippAllowedPermissions -UserRoles $CustomRoles
78+
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
79+
StatusCode = [HttpStatusCode]::OK
80+
Body = (
81+
@{
82+
'clientPrincipal' = @{
83+
appId = $Request.Headers.'x-ms-client-principal-name'
84+
appRole = $CustomRoles
85+
}
86+
'permissions' = $Permissions
87+
} | ConvertTo-Json -Depth 5)
88+
})
89+
return
90+
}
91+
9492
} else {
9593
$Type = 'User'
9694
$User = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Request.Headers.'x-ms-client-principal')) | ConvertFrom-Json
@@ -103,9 +101,14 @@ function Test-CIPPAccess {
103101
#Write-Information ($User | ConvertTo-Json -Depth 5)
104102
# Return user permissions
105103
if ($Request.Params.CIPPEndpoint -eq 'me') {
104+
$Permissions = Get-CippAllowedPermissions -UserRoles $User.userRoles
106105
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
107106
StatusCode = [HttpStatusCode]::OK
108-
Body = (@{ 'clientPrincipal' = $User } | ConvertTo-Json -Depth 5)
107+
Body = (
108+
@{
109+
'clientPrincipal' = $User
110+
'permissions' = $Permissions
111+
} | ConvertTo-Json -Depth 5)
109112
})
110113
return
111114
}

Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecGraphRequest.ps1

Lines changed: 0 additions & 112 deletions
This file was deleted.

0 commit comments

Comments
 (0)