Skip to content

Commit 3f22668

Browse files
authored
Merge pull request #992 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents f47875e + 77073ba commit 3f22668

3 files changed

Lines changed: 35 additions & 4 deletions

File tree

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,19 @@ function Test-CIPPAccess {
136136
$swUserBranch = [System.Diagnostics.Stopwatch]::StartNew()
137137
$User = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Request.Headers.'x-ms-client-principal')) | ConvertFrom-Json
138138

139+
if ($User.claims -and [string]::IsNullOrWhiteSpace($User.userDetails)) {
140+
$Claims = @($User.claims)
141+
$Upn = ($Claims | Where-Object { $_.typ -in @('preferred_username', 'upn', 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn', 'email', 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress') } | Select-Object -First 1).val
142+
if ([string]::IsNullOrWhiteSpace($Upn)) { $Upn = $Request.Headers.'x-ms-client-principal-name' }
143+
$Oid = ($Claims | Where-Object { $_.typ -in @('http://schemas.microsoft.com/identity/claims/objectidentifier', 'oid') } | Select-Object -First 1).val
144+
$User = [pscustomobject]@{
145+
identityProvider = 'aad'
146+
userId = $Oid
147+
userDetails = $Upn
148+
userRoles = @('authenticated', 'anonymous')
149+
}
150+
}
151+
139152
# Check for roles granted via group membership
140153
if (($User.userRoles | Measure-Object).Count -eq 2 -and $User.userRoles -contains 'authenticated' -and $User.userRoles -contains 'anonymous') {
141154
$swResolveUserRoles = [System.Diagnostics.Stopwatch]::StartNew()
@@ -145,6 +158,9 @@ function Test-CIPPAccess {
145158
}
146159

147160
$swIPCheck = [System.Diagnostics.Stopwatch]::StartNew()
161+
if (-not $User.userRoles) {
162+
throw 'Access denied: unable to resolve roles for the authenticated principal.'
163+
}
148164
$AllowedIPRanges = Get-CIPPRoleIPRanges -Roles $User.userRoles
149165

150166
if ($AllowedIPRanges -notcontains 'Any') {

Modules/CIPPCore/Public/Entrypoints/HTTP Functions/New-CippCoreRequest.ps1

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,24 @@ function New-CippCoreRequest {
4343
$FunctionName = 'Invoke-{0}' -f $Request.Params.CIPPEndpoint
4444
Write-Information "API Endpoint: $($Request.Params.CIPPEndpoint) | Frontend Version: $($Request.Headers.'X-CIPP-Version' ?? 'Not specified')"
4545

46+
# For now, while we're in read-only we force the role of the MCP API cred.
47+
# When we remove the feature flag, in NG, we move this to use the users role/ident.
48+
if ($Request.Params.CIPPEndpoint -eq 'ExecMcp' -and
49+
$Request.Headers.'x-ms-client-principal' -and
50+
$Request.Headers.'x-ms-client-principal-name' -notmatch '^[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}$') {
51+
try {
52+
$McpPrincipal = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Request.Headers.'x-ms-client-principal')) | ConvertFrom-Json
53+
$McpAppId = ($McpPrincipal.claims | Where-Object { $_.typ -in @('azp', 'appid') } | Select-Object -First 1).val
54+
if ($McpAppId -and (Get-CippApiClient -AppId $McpAppId)) {
55+
$Request.Headers | Add-Member -NotePropertyName 'x-ms-client-principal-name' -NotePropertyValue $McpAppId -Force
56+
$Request.Headers | Add-Member -NotePropertyName 'x-ms-client-principal-idp' -NotePropertyValue 'aad' -Force
57+
Write-Information "MCP request mapped to API client $McpAppId (running at the app's CIPP role)"
58+
}
59+
} catch {
60+
Write-Information "MCP principal app resolution failed: $($_.Exception.Message)"
61+
}
62+
}
63+
4664
# Check if endpoint is disabled via feature flags
4765
$FeatureFlags = Get-CIPPFeatureFlag
4866
$DisabledEndpoint = $FeatureFlags | Where-Object {

Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/MCP/Invoke-ExecMcp.ps1

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,9 @@ function Invoke-ExecMcp {
2727
})
2828
}
2929

30-
# Per-client gate: the global 'MCPServer' feature flag lets this endpoint run at all (enforced
31-
# upstream in New-CippCoreRequest); this narrows access to API clients explicitly flagged
32-
# 'MCP Access Allowed'. A non-API-client caller, an unknown client, or one without the flag is denied.
3330
$CallerAppId = $Request.Headers.'x-ms-client-principal-name'
3431
$IsApiClient = $Request.Headers.'x-ms-client-principal-idp' -eq 'aad' -and $CallerAppId -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}$'
35-
$McpAllowed = if ($IsApiClient) { [bool](Get-CippApiClient -AppId $CallerAppId).MCPAllowed } else { $false }
32+
$McpAllowed = if ($IsApiClient) { [bool](Get-CippApiClient -AppId $CallerAppId).MCPAllowed } else { $true }
3633
if (-not $McpAllowed) {
3734
return ([HttpResponseContext]@{
3835
StatusCode = [HttpStatusCode]::Forbidden

0 commit comments

Comments
 (0)