let SensitiveMsGraphPermissions = externaldata(EAMTierLevelName: string, Category: string, AppRoleDisplayName: string)["https://raw.githubusercontent.com/Cloud-Architekt/AzurePrivilegedIAM/main/Classification/Classification_AppRoles.json"] with(format='multijson'); let SignInsWithDelegatedScope = union SigninLogs, AADNonInteractiveUserSignInLogs | where ResourceDisplayName == "Microsoft Graph" // Enrichment of CAE, OAuthScope and Token Binding | extend AuthenticationMethod = tostring(parse_json(AuthenticationDetails)[0].authenticationMethod) | extend AuthenticationDetail = tostring(parse_json(AuthenticationDetails)[0].authenticationStepResultDetail) | extend AuthProcessDetails = replace_string(AuthenticationProcessingDetails, " " , "") | extend AuthProcessDetails = replace_string(AuthProcessDetails, "\r\n" , "") | parse AuthProcessDetails with * "IsClientCapable\",\"value\":\"" IsClientCapable "\"" * | parse AuthProcessDetails with * "IsCAEToken\",\"value\":\"" IsCaeToken "\"" * | parse AuthProcessDetails with * "OauthScopeInfo\",\"value\":\"" OauthScopeInfo "\"}" * | extend OAuthDelegatedScope = replace_string(OauthScopeInfo, '\\', '') | extend TokenProtectionStatus = iff(isempty( TokenProtectionStatusDetails_dynamic ), todynamic(TokenProtectionStatusDetails_string), TokenProtectionStatusDetails_dynamic) | extend SignInSessionStatus = tostring(TokenProtectionStatus.signInSessionStatus) // Enrichment for AuthMethod and DeviceDetails | extend AuthenticationMethod = tostring(parse_json(AuthenticationDetails)[0].authenticationMethod) | extend AuthenticationDetail = tostring(parse_json(AuthenticationDetails)[0].authenticationStepResultDetail) | extend DeviceDetail = iff(isempty( DeviceDetail_dynamic ), todynamic(DeviceDetail_string), DeviceDetail_dynamic) | extend DeviceName = tostring(toupper(DeviceDetail.displayName)) | extend DeviceOS = tostring(parse_json(DeviceDetail).operatingSystem) | extend DeviceTrust = tostring(parse_json(DeviceDetail).trustType) | extend DeviceCompliance = tostring(parse_json(DeviceDetail).isCompliant) | project TimeGenerated = CreatedDateTime, CorrelationId, UserPrincipalName, RiskLevelDuringSignIn, RiskState, AppDisplayName, ResourceDisplayName, tostring(OAuthDelegatedScope), AuthenticationMethod, AuthenticationDetail, DeviceName, DeviceOS, DeviceTrust, DeviceCompliance, IncomingTokenType, IsCaeToken, SignInSessionStatus; SignInsWithDelegatedScope | mv-expand parse_json(OAuthDelegatedScope) | extend AppRoleDisplayName = tostring(OAuthDelegatedScope) | join kind=leftouter( SensitiveMsGraphPermissions | project AppRolePermissionTierLevel = tostring(EAMTierLevelName), tostring(Category), tostring(AppRoleDisplayName) ) on AppRoleDisplayName | where isnotempty(AppRoleDisplayName) | extend AppRolePermissionTierLevel = iff(isnotempty(AppRolePermissionTierLevel), AppRolePermissionTierLevel, "Unclassified") | sort by TimeGenerated | extend AppRolePermissionDetails = bag_pack_columns(AppRoleDisplayName, AppRolePermissionTierLevel) // Optional: Filter sign-ins with delegated permissions on Control Plane //| where AppRolePermissionTierLevel == "ControlPlane" | summarize AppRolePermissions = make_set(AppRolePermissionDetails), AppRolePermissionTierLevels = array_sort_asc(make_set(AppRolePermissionTierLevel)) by TimeGenerated, CorrelationId, UserPrincipalName, RiskLevelDuringSignIn, RiskState, AppDisplayName, ResourceDisplayName, AuthenticationMethod, AuthenticationDetail, DeviceName, DeviceOS, DeviceTrust, DeviceCompliance, IncomingTokenType, IsCaeToken, SignInSessionStatus