Application Objects

An Application object represents an Azure AD App Registration.

It consists of elements such as the:

  • Supported account types (single or multi-tenant)
  • Redirect URIs
  • Token configuration
  • Resource permissions

These objects serve as the blueprint for the application they represent.

To use this object, a counterpart Service Principal is needed.

Service Principals

Service Principals enable authentication and authorisation

In Azure AD there are three Service Principal types:

  • Application
  • Managed; and
  • Legacy

For the purposes of this article we will focus just on the Application type.

Application

An Application Service Principal supports the instance of an Application object.

For multi-tenant apps, each tenant will create and maintain its own Application Service Principal which ties to the original Application object.

The principal facilitates configuration such as:

  • Sign-in availability
  • Assigned owners
  • Assigned users or groups
  • Appearance within MyApps
  • Conditional Access

It is not recommended to change redirect URI values on the service principal itself because these values can be overriden when a sync occurs (between it and the application object).

PowerShell Script

The following script gathers all application integrations in the current tenant. It presents their owning tenants, redirect URLs, inferred authentication scheme and whether app role assignment is required.

If this option is on, then users and other apps or services must first be assigned this application before being able to access it (Authentication).

If this option is off, then all users (including Guests of your tenant) will be able to Authenticate, and other apps and services will be able to obtain an access token to this service. It will be up to the Application’s configuration to deny access (Authorisation).

This snippet depends upon the Azure AD or AzureADPreview PowerShell modules.

Sample Output

Id                          : ...
Enabled                     : True
DisplayName                 : Chris' App
OwningTenant                : Chris' Tenant
InferredAuth                : OAuth
IsAppRoleAssignmentRequired : True
ReplyUrls                   : https://localhost:8080, ...
Additional                  :

Id                          : ...
Enabled                     : True
DisplayName                 : Azure Storage
OwningTenant                : Microsoft
InferredAuth                : OAuth
IsAppRoleAssignmentRequired : False
ReplyUrls                   : https://storage.azure.com
Additional                  :

Code

using namespace System.Collections.Generic
using namespace Microsoft.Open.AzureAD.Model
using namespace Microsoft.Open.Azure.AD.CommonLibrary

$ErrorActionPreference = 'stop'

try {
    Get-AzureADTenantDetail | Out-Null
}
catch [AadNeedAuthenticationException] {
    Connect-AzureAD
}

class AzureAppIntegration {
    [string]$Id
    [bool]$Enabled
    [String]$DisplayName
    [string]$OwningTenant
    [string]$InferredAuth
    [bool]$IsAppRoleAssignmentRequired
    [string]$ReplyUrls
    [string]$Additional
}

$tenantDisplayName = (Get-AzureADTenantDetail).DisplayName

$appRegistrations = Get-AzureADApplication -All $true
$servicePrincipals = Get-AzureADServicePrincipal -All $true

$appRegistrationsDict = [Dictionary[String, DirectoryObject]]::new()
$servicePrincipalsDict = [Dictionary[String, DirectoryObject]]::new()

$appRegistrations | ForEach-Object {
    $appRegistrationsDict.Add($_.AppId, $_)
}

$servicePrincipals | ForEach-Object {
    $servicePrincipalsDict.Add($_.AppId, $_)
}

$azureAppIntegrations = [Dictionary[String, AzureAppIntegration]]::new()

foreach ($key in $appRegistrationsDict.Keys) {
    $appRegistration = $appRegistrationsDict[$key]
    $azureAppIntegration = [AzureAppIntegration]::new()
    if ($null -eq $servicePrincipalsDict[$appRegistration.AppId]) {
        $azureAppIntegration.Additional = 'This App Registration is without a Service Principal. '
    }
    $azureAppIntegration.Id = $appRegistration.AppId
    $azureAppIntegration.DisplayName = $appRegistration.DisplayName
    $azureAppIntegration.ReplyUrls = ($appRegistration.ReplyUrls | Sort-Object) -join ', '
    $azureAppIntegration.OwningTenant = $tenantDisplayName
    $azureAppIntegrations.Add($appRegistration.AppId, $azureAppIntegration)
}

foreach ($key in $servicePrincipalsDict.Keys) {
    $servicePrincipal = $servicePrincipalsDict[$key]
    if ($servicePrincipal.ServicePrincipalType -eq 'Application') {
        $inferredAuth = 'OAuth'
        if ($servicePrincipal.Tags -contains 'WindowsAzureActiveDirectoryGalleryApplicationPrimaryV1' -or `
                $servicePrincipal.Tags -contains 'WindowsAzureActiveDirectoryCustomSingleSignOnApplication') {
            $inferredAuth = 'SAML'
        }
        if ($null -eq $azureAppIntegrations[$servicePrincipal.AppId]) {
            # This is an external App Integration
            $azureAppIntegration = [AzureAppIntegration]::new()
            $azureAppIntegration.Id = $servicePrincipal.AppId
            $azureAppIntegration.Enabled = $servicePrincipal.AccountEnabled
            $azureAppIntegration.DisplayName = $servicePrincipal.AppDisplayName
            $azureAppIntegration.ReplyUrls = ($servicePrincipal.ReplyUrls | Sort-Object) -join ', '
            $azureAppIntegration.InferredAuth = $inferredAuth
            $azureAppIntegration.IsAppRoleAssignmentRequired = $servicePrincipal.AppRoleAssignmentRequired
            # Note - This is not an exhaustive list of Microsoft tenants (from which their service principals may derive)
            if ($servicePrincipal.AppOwnerTenantId -eq 'f8cdef31-a31e-4b4a-93e4-5f571e91255a' -or `
                    $servicePrincipal.AppOwnerTenantId -eq '47df5bb7-e6bc-4256-afb0-dd8c8e3c1ce8' -or `
                    $servicePrincipal.AppOwnerTenantId -eq '72f988bf-86f1-41af-91ab-2d7cd011db47') {
                $azureAppIntegration.OwningTenant = 'Microsoft'
            }
            elseif ($servicePrincipal.AppOwnerTenantId -eq '9188040d-6c67-4c5b-b112-36a304b66dad') {
                $azureAppIntegration.OwningTenant = 'Microsoft Accounts'
            }
            else {
                $azureAppIntegration.OwningTenant = $servicePrincipal.AppOwnerTenantId 
            }
            $azureAppIntegrations.Add($servicePrincipal.AppId, $azureAppIntegration)
        }
        else {
            $azureAppIntegration = $azureAppIntegrations[$servicePrincipal.AppId]
            $azureAppIntegration.Enabled = $servicePrincipal.AccountEnabled
            $azureAppIntegration.InferredAuth = $inferredAuth
            $azureAppIntegration.IsAppRoleAssignmentRequired = $servicePrincipal.AppRoleAssignmentRequired   
        }    
    }
}

# $azureAppIntegrations['AppId']
$azureAppIntegrationsList = [List[AzureAppIntegration]]::new()
foreach ($key in $azureAppIntegrations.Keys) {
    $azureAppIntegration = $azureAppIntegrations[$key]
    $azureAppIntegrationsList.Add($azureAppIntegration)
}

# $azureAppIntegrationsList | fl
# $azureAppIntegrationsList | Export-Csv -NoTypeInformation -Path 'AzureAppIntegrations.csv'

Categories:

Updated: